[net.graphics] Area Flooder

perry (04/14/83)

There  has been a lot of requests on net.micro for a filling algorithm which
would handle arbitrary polygons.  A while back I needed a  quick  and  dirty
black  and  white  flooder  so  I  reached  for  my  nearest set of Siggraph
Proceedings and Notes (I thought everybody had a ``nearest set  of  Siggraph
Proceedings...),  turned  to  any  one  of several articles by A.  R.  Smith
(formerly of NYIT now at that great graphics lab on Tatooine) and  perverted
what  lay  therein.  So, with the caveat that this code was not intended for
any other eyes other than those residing on the first board on the  left  in
the cpu bucket, here's der code.

----------------------------------------------------------------------------
Meant to run with an off bus frame buffer - most of the code is there to
cache scan lines (to reduce i/o overhead). Also, there is some code left
in here from some other diddling I was doing at about the same time  (so
lint might find some unused routines).
----------------------------------------------------------------------------
#include <stdio.h>
/*
	permission is hereby granted to copy this code where ever you like
	just  as long as you bow down and utter thanks in the direction of
	Lucasfilm.  In  most  parts  of  the  country that will cause your
	posterior to face Stony Brook, but thats ok with me.

				perry s. kivolowitz
				allegra!sbcs!perry
				perry@suny-sbcs
*/

#define	LEFT	0
#define	RIGHT	511
#define	TOP	511
#define	BOTTOM	0
#define STACK_LIMIT	100

#define STACKNOTEMPTY	(sp > stack)

struct frame {
	int x;
	int y;
};

struct frame stack[STACK_LIMIT] , *sp;

int x , y , lx , rx , yref , lxref , rxref;
int new , old;

push()
{
	if (sp - stack >= STACK_LIMIT) {
		printf("Ooops! Stack Overflow\n");
		exit();
	}
	sp->x = x;
	sp->y = y;
	sp++;
}

pop()
{
	if (--sp < stack) {
		printf("Ooops! Stack Underflow\n");
		exit();
	}
	x = sp->x;
	y = sp->y;
}

init_stack()
{
	sp = stack;
}

dump_stack()
{
	struct frame *tsp;

	tsp = stack;
	printf("Stack Dump:\n");
	while (tsp != sp) {
		printf("x:   %3d    y:   %3d\n" , tsp->x , tsp->y);
		tsp++;
	}
}

static last_y = -1;
static last_left = 0; last_right = 511;
static dirty_line = 0;
static short int scan_line[512];

get()
{
	register int i;

	if (last_y != y) {
		last_left = last_left < 0 ? 0 : last_left;
		last_left = last_left > 511 ? 511 : last_left;
		last_right = last_right < 0 ? 0 : last_right;
		last_right = last_right > 511 ? 511 : last_right;
		if (dirty_line)
		   gcwlw(scan_line + last_left ,
			 last_left ,
			 last_y ,
			 last_right - last_left + 1 ,
			 0 , 0 , 13 , 0
		   );
		dirty_line = 0;
		if (last_y != -1) {
			last_left = lx;
			last_right = rx;
		}
		gcrlw(last_left ,
		      y ,
		      last_right - last_left + 1 ,
		      1 , scan_line+last_left
		);
	}
	if (x < last_left) {
		i = last_left / 2; /* shift right by 2 to the 0 bits */
		i = x < i ? x : i;
		gcrlw(i , y , last_left - i , 1 , scan_line + i);
		last_left = i;
	}
	if (x > last_right) {
		i = last_right + (511 - last_right) / 2;
		i = x > i ? x : i;
		gcrlw(last_right + 1 , y , i - last_right , 1 ,
		      scan_line + last_right + 1
		);
		last_right = i;
	}
	last_y = y;
	return((int) scan_line[x]);
}

set()
{
	scan_line[x] = new;
	dirty_line = 1;
}

basic_fill(seed_x , seed_y , new_pv)
int seed_x , seed_y , new_pv;
{
	x = seed_x;
	y = seed_y;
	new = new_pv;
	old = get();
	if (old == new) return;
	yref = y;
	push();
	while (STACKNOTEMPTY) {
		pop();
		if (get() == new) continue;
		fill_line();
		if (hi_neighbor()) {
/*			printf("Hi_Neighbor True\n"); */
			scan_hi();
		}
		else if (lo_neighbor()) {
/*			printf("Hi_Neighbor False\n");
			printf("Lo_Neighbor True\n"); */
			scan_low();
		     }
		     else {
/*				printf("Both Hi and Lo are False\n"); */
				scan_hi();
				scan_low();
		}
		yref = y;
		lxref = lx;
		rxref = rx;
	}
}

hi_neighbor()
{
	if ((y == yref + 1) &&
	    (lx >= lxref - 1) &&
	    (rx <= rxref +1))
	    return(1);
	else
	    return(0);
}

lo_neighbor()
{
	if ((y == yref - 1) &&
	    (lx >= lxref - 1) &&
	    (rx <= rxref +1))
	    return(1);
	else
	    return(0);
}

fill_line()
{
	fill_right();
	fill_left();
}

fill_right()
{
	auto int tx = x;

	while ((get() == old) && (x <= RIGHT)) {
		set();
		x++;
	}
	rx = x - 1;
	x = tx;
}

fill_left()
{
	auto int tx = x;

	x--;
	while ((get() == old) && (x >= LEFT)) {
		set();
		x--;
	}
	lx = x + 1;
	x = tx;
}

scan_hi()
{
	auto int tx = x , ty = y;

/*	printf("Greetings from sunny scan_hi!\n"); */
	if ((y + 1) > TOP) {
/*		printf("scan_hi taking y+1 > top return\n"); */
		return;
	}
	x = lx;
	y++;
	while (x <= rx) {
		while ((get() != old) && (x <= rx)) x++;
		if (x > rx) {
/*			printf("scan_hi taking x > rx break\n"); */
			break;
		}
		push();
		while ((get() == old) && (x <= rx)) x++;
	}
/*	printf("scan_hi leaving via bottom of me\n"); */
	x = tx;
	y = ty;
}

scan_low()
{
	auto int tx = x , ty = y;

	if ((y - 1) < BOTTOM) return;
	x = lx;
	y--;
	while (x <= rx) {
		while ((get() != old) && (x <= rx)) x++;
		if (x > rx) break;
		push();
		while ((get() == old) && (x <= rx)) x++;
	}
	x = tx;
	y = ty;
}

gcwlw(data,x,y,l,dw,dh,cm,zc)
short data[],x,y,l,dw,dh,cm,zc;
{
	grwlw_(data,&x , &y , &l , &dw , &dh , &cm , &zc);
}

snap_stack()
{
	printf("X: %3d   Y: %3d  SP: %3d\n" , x , y , sp - stack);
}