|
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 Payments Humor Music |
Heathkit H-100 DeSmet C function to flood fill paint an enclosed graphic areaThis is a DeSmet C graphics function for the Heathkit H-100 computer, to paint (flood fill) an enclosed graphic area, stopping when it reaches the specified border color(s) or the edge of the screen. Since the H-100 only has 8 colors, the function supports "dithering", using more than one paint color. Placing pure color pixels close to each other in varying proportions can simulate finer shades of coloration that aren't otherwise possible. For example, color 1 is blue and color 2 is red. Dithering with "12" produces purple. Dithering with "112" produces a bluer shade of purple, while "122" would be more toward red. The function can dither using a regular pattern (tiling) or it can randomly choose which of the colors to use for each pixel. It uses my pset function, and it is put to use in my H-100 graphics editor program. |
/* ===========================================================*/
/* 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 3, with ABSOLUTELY NO WARRANTY. */
/* Initially published by http://25yearsofprogramming.com. */
#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);
}
|
|
|
|
|
Copyright ©2011 Steven Whitney. Last modified Tue 05/24/2011 12:26:50 -0700. |
||