/********************************* circles.c ************************/ #include #include "sdi.h" #include #include "sdi_color.h" /* * Copyright 1987 by Mark Weiser. * Permission to reproduce and use in any manner whatsoever on Suns is granted * so long as this copyright and other identifying marks of authorship * in the code and the game remain intact and visible. Use of this code * in other products is reserved to me--I'm working on Mac and IBM versions. */ /* * Here be everything associated with drawing circles, especially * all the different kinds of blasts (which are done by clipping * different pixrects to different shapes of circles.) All the * blast pixrects are precomputed for every size to save time during * game display updating. */ static short default_laser_blast[] = { #include "laser.h" }; mpr_static(laser_blast_pr, 64, 64, 1, default_laser_blast); static short default_laser_kill[] = { #include "laserkill.h" }; mpr_static(laser_kill_pr, 64, 64, 1, default_laser_kill); static short default_city_blast[] = { #include "mushroom.h" }; mpr_static(city_blast_pr, 64, 64, 1, default_city_blast); static short default_missile_kill[] = { #include "missilekill.h" }; mpr_static(missile_kill_pr, 64, 64, 1, default_missile_kill); static short default_rocks[] = { #include "rocks.h" }; mpr_static(rocks_pr, 64, 64, 1, default_rocks); Xv_Window circles[MAX_NUM_CIRCLES], m_circles[MAX_NUM_CIRCLES], blast_circles[MAX_NUM_CIRCLES]; Xv_Window m_limited_circles[MAX_NUM_CIRCLES], blast_limited_circles[MAX_NUM_CIRCLES]; Xv_Window rock_limited_circles[MAX_NUM_CIRCLES], m_rock_limited_circles[MAX_NUM_CIRCLES]; Xv_Window make_circle_internal(); static struct { int x, y; } center = { 0, 0 }; static struct fill_line { int left; int right; int y; } scan_lines[MAX_LINES], *free_line; static void circle_fill_pair(), circle_fill(); #define LIMIT(n) (((n) < 0) ? 0 : (((n) >= MAX_LINES) ? MAX_LINES-1 : (n))) init_circles() { int i, size = 2*CIRCLE_SIZE_INC; int limited_size = (MAX_NUM_CIRCLES-4)*CIRCLE_SIZE_INC + size; int rock_limited_size = 2*CIRCLE_SIZE_INC + size; for (i=0; i < MAX_NUM_CIRCLES; i++) { if (size > MAX_CIRCLE) size = MAX_CIRCLE; circles[i] = make_circle(size, GREY); blast_circles[i] = make_circle(size, BLACK); blast_limited_circles[i] = make_circle(size > limited_size ? limited_size : size, BLACK); rock_limited_circles[i] = make_circle(size > rock_limited_size ? rock_limited_size : size, GREY); m_circles[i] = make_circle(size, BACKGROUND); m_limited_circles[i] = make_circle(size > limited_size ? limited_size : size, BACKGROUND); m_rock_limited_circles[i] = make_circle(size > rock_limited_size ? rock_limited_size : size, BACKGROUND); size += CIRCLE_SIZE_INC; } lasercircles = init_circ(3, circles, m_circles); laserkillcircles = init_circ(3, circles, m_circles); bigblastcircles = init_circ(MAX_NUM_CIRCLES, blast_circles, m_circles); littleblastcircles = init_circ(MAX_NUM_CIRCLES-2, blast_limited_circles, m_limited_circles); blastkillcircles = init_circ(MAX_NUM_CIRCLES-3, blast_circles, m_circles); citykillcircles = init_circ(MAX_NUM_CIRCLES, circles, m_circles); littlerockcircles = init_circ(4, rock_limited_circles, m_rock_limited_circles); bigrockcircles = init_circ(7, rock_limited_circles, m_rock_limited_circles); change_circ(lasercircles, &laser_blast_pr, LASERBLAST_COLOR); change_circ(laserkillcircles, &laser_kill_pr, LASERKILL_COLOR); change_circ(citykillcircles, &city_blast_pr, CITYKILL_COLOR); change_circ(blastkillcircles, &missile_kill_pr, BLASTKILL_COLOR); change_circ(littlerockcircles, &rocks_pr, LITTLEROCK_COLOR); change_circ(bigrockcircles, &rocks_pr, BIGROCK_COLOR); } /* * Create a new circ structure, and initialize it to contain the pixrect * list 'c'. */ struct circ * init_circ(n, c, m) Xv_Window *c, *m; { struct circ *r; r = (struct circ *)calloc(sizeof(struct circ), 1); r->masks = m; r->circles = c; r->num_circles = n; return r; } /* * Routine to replace a list of pixrects in a circ structure with a new * list. The new list is constructed by 'and'ing parameter p with * circles of the diameter contained in the old list. This is the * basic routine used to construct all the different kinds of blasts. * * Calling change_circ several times on the same circ structure * will waste memory because the calloc from previous calls is * never freed, nor are the pixrects. It is not much memory, however. */ change_circ(c, p, color) struct circ *c; struct pixrect *p; { int i; Xv_Window *newcircles; int size, psize; newcircles = (Xv_Window *)calloc(sizeof(Xv_Window),c->num_circles); psize = p->pr_size.x; for (i = 0; i < c->num_circles; i++) { size = xv_get(c->masks[i], XV_HEIGHT); /* assume height=width */ newcircles[i] = (Xv_Window)xv_create(XV_NULL, SERVER_IMAGE, XV_HEIGHT, size, XV_WIDTH, size, SERVER_IMAGE_DEPTH, SDI_COLOR_DEPTH, NULL); if (use_color) xv_set(newcircles[i], SERVER_IMAGE_COLORMAP, sdi_colormap_name, NULL); xv_rop(newcircles[i], 0, 0, size, size, PIX_SRC | PIX_COLOR(color), p, psize/2 - size/2, psize/2 - size/2); } c->circles = newcircles; } Xv_Window make_circle(diameter, color) int diameter, color; { Xv_Window pr = (Xv_Window)xv_create(XV_NULL, SERVER_IMAGE, XV_HEIGHT, diameter, XV_WIDTH, diameter, SERVER_IMAGE_DEPTH, SDI_COLOR_DEPTH, 0); if (use_color) xv_set(pr, SERVER_IMAGE_COLORMAP, sdi_colormap_name, NULL); return make_circle_internal(pr, diameter, color); } /* * Build a circle of the specified diameter, and return it in * a window of just the right size to hold it. */ Xv_Window make_circle_internal(pr, diameter, color) Xv_Window pr; int diameter, color; { xv_rop(pr, 0, 0, diameter, diameter, use_color ? (PIX_SRC | PIX_COLOR(BACKGROUND)) : PIX_CLR, 0, 0, 0); center.x = diameter/2; center.y = diameter/2; free_line = scan_lines; circle_accept(pr, LIMIT((diameter/2)-2), color); return pr; } /* * The routines below borrow ideas from the Sun Bresenham * circle code in iconedit. */ /* * Draw a circle inside pr, with length as given here, and with center as * set in global variable 'center'. */ circle_accept(pr, length, color) struct pixrect *pr; { int d, x, y; x = 0; y = length; d = 3 - 2*y; while ( x < y ) { circle_fill_pair(x, y); if (d < 0) d += 4*x + 6; else { d += 4*(x-y) +10; y -= 1; } x++; } if (x == y) { circle_fill_pair(x, y); } circle_fill(pr, color); } static void circle_fill_pair( x, y) register int x, y; { register struct fill_line *line_ptr = free_line; free_line += 4; line_ptr->left = LIMIT(center.x - x); line_ptr->right = LIMIT(center.x + x); line_ptr->y = LIMIT(center.y - y); ++line_ptr; line_ptr->left = LIMIT(center.x - y); line_ptr->right = LIMIT(center.x + y); line_ptr->y = LIMIT(center.y - x); ++line_ptr; line_ptr->left = LIMIT(center.x - y); line_ptr->right = LIMIT(center.x + y); line_ptr->y = LIMIT(center.y + x); ++line_ptr; line_ptr->left = LIMIT(center.x - x); line_ptr->right = LIMIT(center.x + x); line_ptr->y = LIMIT(center.y + y); } static int compare_lines(l1, l2) register struct fill_line *l1, *l2; { if (l1->y < l2->y) return -1; else if (l1->y > l2->y) return 1; else if (l1->left < l2->left || l1->right > l2->right) return -1; else if (l1->left > l2->left || l1->right < l2->right) return 1; else return 0; } static void circle_fill(pr, color) struct pixrect *pr; { register struct fill_line *line_ptr = scan_lines; register int len, y = -1; qsort(scan_lines, free_line - scan_lines, sizeof(struct fill_line), compare_lines); while (line_ptr < free_line) { register int x0; if (line_ptr->y != y) { x0 = line_ptr->left; y = line_ptr->y; len = line_ptr->right - x0 + 1; pr_vector(pr, x0, y, x0+len, y, PIX_SRC, color); } line_ptr++; } }