|
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);
}
|
|
|
|
|
|