25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more...
Home   Projects   Up   Sitemap   Search   Blog   Forum+Chat   About Us   Privacy   Terms of Use   Feedback   FAQ   Images   Services   Ads   Donate   Humor

Heathkit H-100 DeSmet C function to flood fill paint an enclosed graphic area

/* ===========================================================*/
/* H100 ROUTINE FOR FLOOD FILL PAINTING AN ENCLOSED GRAPHIC AREA */
/* ===========================================================*/
/* PAINT.C MODULE */
/* Copyright (C)1993 Steven Whitney. Published under the */
/* GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY. */

#define TRUE	(1)
#define FALSE	(0)
#define ERR		(-1)
/* -------------------------------------------------------------- */
/*	ENLARGE()	5-1-94 USED BY PAINT TO RESIZE THE POINTS ARRAYS */
/*	RETURNS TRUE IF SUCCEEDED OR FALSE IF FAILED */
/* -------------------------------------------------------------- */
int enlarge(up,down,temp,maxcount)
char **up, **down, **temp;				/* ACTUALLY STRUCT CELL POINTERS */
int *maxcount;
{
char *realloc();
void free();
struct cell
{
	int x;
	int y;
	int active;
};

*maxcount += 640;
if((!(*up = realloc(*up,*maxcount * sizeof(struct cell)))) ||
	(!(*down = realloc(*down,*maxcount * sizeof(struct cell)))) ||
	(!(*temp = realloc(*temp,*maxcount * sizeof(struct cell)))))
		{
			puts("\nMemory allocation error in paint().\n");
			if(*up) free(*up);
			if(*down) free(*down);
			if(*temp) free(*temp);
			return(FALSE);
		}
return(TRUE);
}

/* -------------------------------------------------------------- */
/*	PAINT()		5-12-93  */
/*	PAINTS AN AREA WITH SPECIFIED COLOR, UP TO A SPECIFIED */
/*	BORDER COLOR OR TO EDGE OF SCREEN */
/*	(IF IT RUNS OUT OF MEMORY, WILL NEED A ROUTINE TO PACK THE ARRAY) */
/*	RETURNS TRUE IF SUCCEEDED, FALSE IF AN ERROR OCCURRED */
/*	5-29-93 */
/*	6-2-93	DYNAMICALLY EXPANDABLE ARRAYS */
/* 	11-24-93 MULTIPLE BORDER COLORS ALLOWED, WILL STOP ON ANY ONE OF THEM */
/*	12-7-93 USE ONLY 'P' PSET MODE.  */
/*			OTHERS CAUSE CONSTANTLY CHANGING BORDERS & MEM.ALLOC. ERRORS */
/*	5-2-94	ARRAY RESIZING MOVED TO ENLARGE() */
/*			ACCEPTS LIST OF PAINT COLORS TO CHOOSE FROM. E.G. IF LIST IS */
/*			"01", PAINTED AREA WILL BE 50% BLACK, 50% BLUE, OR DARK BLUE. */
/*			CAN USE REGULAR TILING OR RANDOM */
/* -------------------------------------------------------------- */
int paint(x0,y0,colors,border,tile)
int x0, y0;
char *colors;		/* TEXT STRING OF PAINT COLORS, E.G. "1124" */
char *border;		/* ASCII STRING OF BORDER COLORS, E.G. "123" */
					/* CAN'T BE CONVERTED TO NUMERIC BECAUSE COLOR OF 0 */
					/* WOULD TERMINATE THE STRING INDEX() SEARCHES */
int tile;			/* FLAG WHETHER TO USE REGULAR TILING */
					/* IF FALSE, RANDOM PAINTING WILL BE USED */
{
int a, b, i, j, k;						
char ch;							/* TRAP FOR ^C */
int oob;							/* FLAG FOR OUT-OF-BOUNDS */
int upcount, downcount, tempcount;	/* # OF ACTIVE ELEMENTS IN ARRAYS */
int maxcount;						/* MAXIMUM LENGTH OF THE ARRAYS */
double colorcount;					/* NUMBER OF PAINT COLORS BEING USED */
int color;							/* ACTUAL COLOR SENT TO PSET() */
int colindex;						/* INDEX INTO COLORS[] */
char compound;						/* FLAG WHETHER PAINT COLOR IS SINGLE OR COMPOUND */
char *calloc(), csts();
void free();
double posrnd();

struct cell
{
	int x;
	int y;
	int active;
} *up, *down, *temp, *dummy;

/* -------------------------------------------------------------- */
/*	FIRST, DO INITIAL CHECKS FOR A QUICK EXIT */
/* -------------------------------------------------------------- */
oob = pset(x0,y0,'s',0);
if(oob == ERR) return(TRUE);				/* LANDED OUT OF BOUNDS */
if(index(border,(char)(oob + 0x30)))		/* LANDED ON A BORDER COLOR */
	return(TRUE);

/* -------------------------------------------------------------- */
/*	ALLOCATE SPACE FOR ARRAYS */
/* -------------------------------------------------------------- */
maxcount = 640;
up = down = temp = dummy = 0;
if((!(up = (struct cell *)calloc(maxcount,sizeof(struct cell)))) ||
	(!(down = (struct cell *)calloc(maxcount,sizeof(struct cell)))) ||
	(!(temp = (struct cell *)calloc(maxcount,sizeof(struct cell)))))
	{
		puts("\nMemory allocation error in paint().\n");
		if(up) free(up);
		if(down) free(down);
		if(temp) free(temp);
		return(FALSE);
	}

/* -------------------------------------------------------------- */
/*	SET UP COLOR-HANDLING VARIABLES */
/* -------------------------------------------------------------- */
if((colorcount = (double)strlen(colors)) > 1.)
{
	compound = TRUE;
	colindex = 0;
}
else
{
	compound = FALSE;
	color = (int)(colors[0]) - 0x30;
}
					

/* -------------------------------------------------------------- */
/*	DRAW THE LONGEST HORIZONTAL LINE POSSIBLE THROUGH THE ORIGIN */
/* -------------------------------------------------------------- */
upcount = downcount = 0;		/*	EXTEND TO LEFT FROM ORIGIN */
i = 0;
while(1)								/* DO FOREVER, EXIT IS IN LOOP */
{
	oob = pset(x0 - i,y0,'s',0);		/* GET COLOR OR OUT-OF-BOUNDS */
	if(oob == ERR) break;				/* IF OFF SCREEN, QUIT */
	oob += 0x30;						/* NOW OK TO MAP UP TO ASCII */
	if(index(border,(char)oob))			/* IF IT HITS BORDER, QUIT */
		break;
	if(!index(colors,(char)oob))		/* IF COLOR, DON'T ADD TO ARRAYS, */
	{									/* BUT DO CONTINUE WHILE LOOP */
		if(compound)
		{
			if(tile)
			{
				color = (int)(colors[colindex]) - 0x30;
				if(!(colors[++colindex]))				/* IF USED LAST COLOR, */
					colindex = 0;						/* RESET TO START */
			}
			else
				color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30;	
		}
		pset(x0 - i,y0,'p',color);			/* SET THE POINT */

		up[upcount].x = x0 - i;			/* ADD IT TO THE UP ARRAY */
		up[upcount].y = y0;
		up[upcount].active = TRUE;
		upcount++;

		down[downcount].x = x0 - i;		/* ALSO ADD IT TO THE DOWN ARRAY */
		down[downcount].y = y0;
		down[downcount].active = TRUE;
		downcount++;
	}
	if((upcount == maxcount) || (downcount == maxcount))
		if(!enlarge(&up,&down,&temp,&maxcount))
			return(FALSE);
	i++;
}
									/* EXTEND TO RIGHT FROM ORIGIN */
i = 1;
while(1)
{
	oob = pset(x0 + i,y0,'s',0);
	if(oob == ERR) break;
	oob += 0x30;
	if(index(border,(char)oob))
		break;
	if(!index(colors,(char)oob))
	{
		if(compound)
		{
			if(tile)
			{
				color = (int)(colors[colindex]) - 0x30;
				if(!(colors[++colindex]))			
					colindex = 0;					
			}
			else
				color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30;
		}
		pset(x0 + i,y0,'p',color);	

		up[upcount].x = x0 + i;	
		up[upcount].y = y0;
		up[upcount].active = TRUE;
		upcount++;

		down[downcount].x = x0 + i;
		down[downcount].y = y0;
		down[downcount].active = TRUE;
		downcount++;
	}
	if((upcount == maxcount) || (downcount == maxcount))
		if(!enlarge(&up,&down,&temp,&maxcount))
			return(FALSE);
	i++;
}

/* -------------------------------------------------------------- */
/*	LOOP ENTRY POINT */
/*	DO THE WHOLE MESS AS LONG AS THERE ARE ANY POINTS IN EITHER */
/*	UP ARRAY OR DOWN ARRAY */
/* -------------------------------------------------------------- */

while(upcount || downcount)
{
if((ch = csts()) == 3) break;		/* USER CAN ABORT WITH CONTROL-C */
/* -------------------------------------------------------------- */
/*	SEE IF POINTS DIRECTLY ABOVE & BELOW SHOULD BE SET */
/*	IF SO, SET THEM, AND ADD THEM TO THE 'MARCHING' ARRAYS */
/* -------------------------------------------------------------- */
for(i = 0 ; i < upcount ; i++)
{
	/* IF BORDER COLOR, OUT OF BOUNDS, OR ALREADY COLOR TURN CELL OFF */

	up[i].active = FALSE;	/* FOR LATER PACKING, SET TO FALSE NOW, */
							/* IF TESTS FALL THROUGH, IT'S TURNED BACK ON */
	oob = pset(up[i].x,up[i].y - 1,'s',0);	
	if(oob == ERR) continue;
	oob += 0x30;
	if(index(colors,(char)oob)) continue;
	if(index(border,(char)oob)) continue;

	if(compound)
	{
		if(tile)
		{
			color = (int)(colors[colindex]) - 0x30;
			if(!(colors[++colindex]))			
				colindex = 0;					
		}
		else
			color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30; 
	}
	pset(up[i].x,up[i].y - 1,'p',color);	/* SET THE POINT */
/*	UP[I].X = UP[I].X;	*/ 					/* LEFT IN FOR CLARITY, BUT DON'T DO IT */
	up[i].y = up[i].y - 1;					/* GIVE IT THE SPOT */
	up[i].active = TRUE;					/* VACATED BY THE POINT */
}											/* BELOW IT */

for(i = 0 ; i < downcount ; i++)
{
	down[i].active = FALSE;				

	oob = pset(down[i].x,down[i].y + 1,'s',0);
	if(oob == ERR) continue;
	oob += 0x30;
	if(index(colors,(char)oob)) continue;
	if(index(border,(char)oob)) continue;
	if(compound)
	{
		if(tile)
		{
			color = (int)(colors[colindex]) - 0x30;
			if(!(colors[++colindex]))			
				colindex = 0;					
		}
		else
			color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30; 
	}
	pset(down[i].x,down[i].y + 1,'p',color);	/* SET THE POINT */
/*	DOWN[I].X = DOWN[I].X;	*/			/* IN FOR CLARITY, BUT DON'T DO IT */			
	down[i].y = down[i].y + 1;				/* GIVE IT THE SPOT */
	down[i].active = TRUE;					/* VACATED BY THE POINT */
}											/* ABOVE IT */

/* -------------------------------------------------------------- */
/*	PACK THE ARRAYS TO REMOVE POINTS THAT HAVE HIT DEAD ENDS */
/*	THIS IS THE FIRST STEP IN MOVING THE NEXT SCAN LINE'S POINTS */
/*	INTO IT. */
/* -------------------------------------------------------------- */
tempcount = 0;
for(i = 0 ; i < upcount ; i++)
	if(up[i].active == TRUE)				/* TRANSFER ONLY ACTIVE */
	{										/* RECORDS TO TEMP */
		temp[tempcount].x = up[i].x;
		temp[tempcount].y = up[i].y;
		temp[tempcount].active = TRUE;
		tempcount++;
	}
dummy = up;								/* TRANSFER BACK TO UP, BUT */
up = temp;								/* SWAP ARRAYS BY JUST */		
temp = dummy;							/* TRADING POINTERS AROUND! */
upcount = tempcount;					/* RESET RECORD COUNT */

tempcount = 0;
for(i = 0 ; i < downcount ; i++)
	if(down[i].active == TRUE)				/* TRANSFER ONLY ACTIVE */
	{										/* RECORDS TO TEMP */
		temp[tempcount].x = down[i].x;
		temp[tempcount].y = down[i].y;
		temp[tempcount].active = TRUE;
		tempcount++;
	}
dummy = down;
down = temp;
temp = dummy;
downcount = tempcount;						/* RESET RECORD COUNT */

/* -------------------------------------------------------------- */
/*	TRY TO MOVE (AND SET) LEFT FROM *EACH* POINT IN UP ARRAY */
/*	NEW POINTS FOUND MUST BE ADDED TO BOTH ARRAYS BECAUSE, SINCE THEY */
/*	DIDN'T "GROW" FROM THE POINTS ABOVE/BELOW THEM, THEY COULD */
/*	"EXPAND" IN EITHER DIRECTION */
/* -------------------------------------------------------------- */
a = upcount;					/* # OF POINTS IN STARTING ARRAY */
for(j = 0 ; j < a ; j++)		/* PROCESS ALL POINTS IN STARTING ARRAY */
{								/* (ARRAY WILL LENGTHEN DURING LOOP) */
	i = 1;						/* OFFSET FROM POINT WE'RE LOOKING AT */
	while(1)
	{
		oob = pset(up[j].x - i,up[j].y,'s',0);
		if(oob == ERR) break;					/* OFF SCREEN? */
		oob += 0x30;
		if(index(colors,(char)oob)) break;
		if(index(border,(char)oob)) break;			/* BORDER? */
		if(compound)
		{
			if(tile)
			{
				color = (int)(colors[colindex]) - 0x30;
				if(!(colors[++colindex]))			
					colindex = 0;					
			}
			else
				color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30; 
		}
		pset(up[j].x - i,up[j].y,'p',color);		/* SET THE POINT */
		

		up[upcount].x = up[j].x - i;			/* ADD IT TO THE UP ARRAY */
		up[upcount].y = up[j].y;
		up[upcount].active = TRUE;
		upcount++;
	

		down[downcount].x = up[j].x - i;		/* ALSO ADD IT TO THE DOWN ARRAY */
		down[downcount].y = up[j].y;
		down[downcount].active = TRUE;
		downcount++;

		if((upcount == maxcount) || (downcount == maxcount))
			if(!enlarge(&up,&down,&temp,&maxcount))
				return(FALSE);
		i++;
	}				/* END WHILE */
}

/* -------------------------------------------------------------- */
/*	TRY TO MOVE (AND SET) LEFT FROM *EACH* POINT IN DOWN ARRAY */
/* -------------------------------------------------------------- */
a = downcount;				
for(j = 0 ; j < a ; j++)	
{							
	i = 1;		
	while(1)
	{
		oob = pset(down[j].x - i,down[j].y,'s',0);
		if(oob == ERR) break;
		oob += 0x30;
		if(index(colors,(char)oob)) break;
		if(index(border,(char)oob)) break;

		if(compound)
		{
			if(tile)
			{
				color = (int)(colors[colindex]) - 0x30;
				if(!(colors[++colindex]))			
					colindex = 0;					
			}
			else
				color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30; 
		}
		pset(down[j].x - i,down[j].y,'p',color);	
	

		up[upcount].x = down[j].x - i;
		up[upcount].y = down[j].y;
		up[upcount].active = TRUE;
		upcount++;
	

		down[downcount].x = down[j].x - i;	
		down[downcount].y = down[j].y;
		down[downcount].active = TRUE;
		downcount++;

		if((upcount == maxcount) || (downcount == maxcount))
			if(!enlarge(&up,&down,&temp,&maxcount))
				return(FALSE);
		i++;
	}			/* END WHILE */
}

/* -------------------------------------------------------------- */
/*	TRY TO MOVE (AND SET) RIGHT FROM *EACH* POINT IN UP ARRAY */
/* -------------------------------------------------------------- */
a = upcount;				
for(j = 0 ; j < a ; j++)	
{							
	i = 1;				
	while(1)
	{
		oob = pset(up[j].x + i,up[j].y,'s',0);
		if(oob == ERR) break;
		oob += 0x30;
		if(index(colors,(char)oob)) break;
		if(index(border,(char)oob)) break;
		if(compound)
		{
			if(tile)
			{
				color = (int)(colors[colindex]) - 0x30;
				if(!(colors[++colindex]))			
					colindex = 0;
			}
			else
				color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30; 
		}
		pset(up[j].x + i,up[j].y,'p',color);	
	

		up[upcount].x = up[j].x + i;		
		up[upcount].y = up[j].y;
		up[upcount].active = TRUE;
		upcount++;
	

		down[downcount].x = up[j].x + i;	
		down[downcount].y = up[j].y;
		down[downcount].active = TRUE;
		downcount++;
	

		if((upcount == maxcount) || (downcount == maxcount))
			if(!enlarge(&up,&down,&temp,&maxcount))
				return(FALSE);
		i++;
	}				/* END WHILE */
}

/* -------------------------------------------------------------- */
/*	TRY TO MOVE (AND SET) RIGHT FROM *EACH* POINT IN DOWN ARRAY */
/* -------------------------------------------------------------- */
a = downcount;				
for(j = 0 ; j < a ; j++)
{							
	i = 1;		
	while(1)
	{
		oob = pset(down[j].x + i,down[j].y,'s',0);
		if(oob == ERR) break;
		oob += 0x30;
		if(index(colors,(char)oob)) break;
		if(index(border,(char)oob)) break;
		if(compound)
		{
			if(tile)
			{
				color = (int)(colors[colindex]) - 0x30;
				if(!(colors[++colindex]))			
					colindex = 0;					
			}
			else
				color = (int)(colors[(int)(posrnd() * colorcount)]) - 0x30;
		}
		pset(down[j].x + i,down[j].y,'p',color);	
	

		up[upcount].x = down[j].x + i;		
		up[upcount].y = down[j].y;
		up[upcount].active = TRUE;
		upcount++;
	

		down[downcount].x = down[j].x + i;
		down[downcount].y = down[j].y;
		down[downcount].active = TRUE;
		downcount++;

		if((upcount == maxcount) || (downcount == maxcount))
			if(!enlarge(&up,&down,&temp,&maxcount))
				return(FALSE);
		i++;					/* INCREMENT OFFSET */
	}			/* END WHILE */
}				/* END FOR */
}				/* END WHILE (UPCOUNT || DOWNCOUNT) */
if(up) free(up);
if(down) free(down);
if(temp) free(temp);
if(dummy) free(dummy);
return(TRUE);
}

 

 

Valid HTML 4.01 Transitional Valid CSS
View content labeling at ICRA.
Copyright ©2007 Steven Whitney. Last modified 09/25/2007.