/********************************* circles.c ************************/ #include <pixrect/pixrect_hs.h> #include <stdio.h> #include "sdi.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); struct pixrect *circles[MAX_NUM_CIRCLES]; struct pixrect *limited_circles[MAX_NUM_CIRCLES]; struct pixrect *rock_limited_circles[MAX_NUM_CIRCLES]; 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); limited_circles[i] = make_circle(size > limited_size ? limited_size : size); rock_limited_circles[i] = make_circle(size > rock_limited_size ? rock_limited_size : size); size += CIRCLE_SIZE_INC; } blankcircles = circles; lasercircles = init_circ(3, circles); laserkillcircles = init_circ(3, circles); bigblastcircles = init_circ(MAX_NUM_CIRCLES, circles); littleblastcircles = init_circ(MAX_NUM_CIRCLES-2, limited_circles); blastkillcircles = init_circ(MAX_NUM_CIRCLES-3, circles); citykillcircles = init_circ(MAX_NUM_CIRCLES, circles); littlerockcircles = init_circ(4, rock_limited_circles); bigrockcircles = init_circ(7, rock_limited_circles); change_circ(lasercircles, &laser_blast_pr); change_circ(laserkillcircles, &laser_kill_pr); change_circ(citykillcircles, &city_blast_pr); change_circ(blastkillcircles, &missile_kill_pr); change_circ(littlerockcircles, &rocks_pr); change_circ(bigrockcircles, &rocks_pr); } /* * Create a new circ structure, and initialize it to contain the pixrect * list 'c'. */ struct circ * init_circ(n, c) struct pixrect **c; { struct circ *r; r = (struct circ *)calloc(sizeof(struct circ), 1); r->masks = 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, and nothing will die from it. */ change_circ(c, p) struct circ *c; struct pixrect *p; { int i; struct pixrect **newcircles; int size, psize; newcircles = (struct pixrect **)calloc(sizeof(struct pixrect *),c->num_circles); psize = p->pr_size.x; for (i = 0; i < c->num_circles; i++) { size = c->masks[i]->pr_size.x; newcircles[i] = mem_create(size, size, 1); pr_rop(newcircles[i], 0, 0, size, size, PIX_SRC, c->masks[i], 0, 0); pr_rop(newcircles[i], 0, 0, size, size, PIX_SRC & PIX_DST, p, psize/2 - size/2, psize/2 - size/2); } c->circles = newcircles; } /* * Build a black circle of the specified diameter, and return it in * a pixrect of just the right size to hold it. */ struct pixrect * make_circle(diameter) int diameter; { struct pixrect *pr = mem_create(diameter, diameter, 1); center.x = diameter/2; center.y = diameter/2; free_line = scan_lines; circle_accept(pr, LIMIT((diameter/2)-2)); 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) struct pixrect *pr; { int d, x, y; x = 0; y = length; d = 3 - 2*y; while ( x < y ) { circle_fill_pair(pr, x, y); if (d < 0) d += 4*x + 6; else { d += 4*(x-y) +10; y -= 1; } x++; } if (x == y) { circle_fill_pair(pr, x, y); } circle_fill(pr); } static void circle_fill_pair(pr, x, y) struct pixrect *pr; 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) 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_SET, 1); } line_ptr++; } }