Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / graphics / flood.c
blob20e67fdb9071611244192bcc070744a2e4e86559
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
8 #include <aros/debug.h>
10 #include <proto/graphics.h>
11 #include <string.h>
12 #include "graphics_intern.h"
14 #define USE_WRITEPIXEL
16 struct fillinfo
18 ULONG fillpen;
19 BOOL (*isfillable)();
20 struct RastPort *rp;
21 UBYTE *rasptr;
22 ULONG bpr;
23 ULONG orig_apen;
24 ULONG orig_bpen;
25 ULONG rp_width;
26 ULONG rp_height;
28 struct GfxBase *gfxbase;
31 static VOID settmpraspixel(BYTE *rasptr, LONG x, LONG y, ULONG bpr, UBYTE state);
32 static BOOL gettmpraspixel(BYTE *rasptr, LONG x, LONG y, ULONG bpr );
34 static BOOL filline(struct fillinfo *fi, LONG start_x, LONG start_y);
35 static BOOL outline_isfillable(struct fillinfo *fi, LONG x, LONG y);
36 static BOOL color_isfillable(struct fillinfo *fi, LONG x, LONG y);
38 #if DEBUG_FLOOD
39 static int fail_count;
40 static int pix_written;
41 #endif
43 /*****************************************************************************
45 NAME */
46 #include <clib/graphics_protos.h>
48 AROS_LH4(BOOL, Flood,
50 /* SYNOPSIS */
51 AROS_LHA(struct RastPort *, rp, A1),
52 AROS_LHA(ULONG , mode, D2),
53 AROS_LHA(LONG , x, D0),
54 AROS_LHA(LONG , y, D1),
56 /* LOCATION */
57 struct GfxBase *, GfxBase, 55, Graphics)
59 /* FUNCTION
60 Flood fill a RastPort.
62 INPUTS
63 rp - destination RastPort
64 mode - 0: fill adjacent pixels which don't have color of OPen.
65 1: fill adjacent pixels which have the same pen as of coordinate x,y.
66 x,y - coordinate to start filling.
68 RESULT
70 NOTES
71 The RastPort must have a TmpRas raster whose size is as large as of
72 that of the RastPort.
74 EXAMPLE
76 BUGS
78 SEE ALSO
80 INTERNALS
82 HISTORY
83 27-11-96 digulla automatically created from
84 graphics_lib.fd and clib/graphics_protos.h
86 *****************************************************************************/
88 AROS_LIBFUNC_INIT
90 struct TmpRas *tmpras = rp->TmpRas;
91 ULONG bpr, needed_size;
93 struct fillinfo fi;
95 BOOL success;
97 EnterFunc(bug("Flood(rp=%p, mode=%d, x=%d, y=%d)\n"
98 , rp, mode, x, y));
100 #if DEBUG_FLOOD
101 fail_count = 0;
102 pix_written = 0;
103 #endif
105 /* Check for tmpras */
106 if (NULL == tmpras)
107 ReturnBool("Flood (No tmpras)", FALSE);
109 if (NULL != rp->Layer)
111 fi.rp_width = rp->Layer->Width;
112 fi.rp_height = rp->Layer->Height;
114 else
116 fi.rp_width = GetBitMapAttr(rp->BitMap, BMA_WIDTH);
117 fi.rp_height = GetBitMapAttr(rp->BitMap, BMA_HEIGHT);
121 bpr = WIDTH_TO_BYTES( fi.rp_width );
122 needed_size = bpr * fi.rp_height;
124 if (tmpras->Size < needed_size)
125 ReturnBool("Flood (To small tmpras)", FALSE);
128 /* Clear the needed part of tmpras */
132 !!! Maybe we should use BltClear() here, since
133 !!! tmpras allways reside in CHIP RAM
136 D(bug("Clearing tmpras\n"));
137 memset(tmpras->RasPtr, 0, needed_size);
139 if (mode == 0)
141 /* Outline mode */
142 D(bug("Getting outline pen\n"));
143 fi.fillpen = GetOutlinePen(rp);
144 D(bug("Got pen\n"));
146 fi.isfillable = outline_isfillable;
148 else
150 /* Color mode */
151 D(bug("Reading pixel\n"));
152 fi.fillpen = ReadPixel(rp, x, y);
153 D(bug("pixel read: %d\n", fi.fillpen));
154 fi.isfillable = color_isfillable;
157 fi.rasptr = tmpras->RasPtr;
158 fi.rp = rp;
159 fi.bpr = bpr;
161 fi.orig_apen = GetAPen(rp);
162 fi.orig_bpen = GetBPen(rp);
164 fi.gfxbase = GfxBase;
166 D(bug("Calling filline\n"));
167 success = filline(&fi, x, y);
169 #if DEBUG_FLOOD
170 D(bug("fails: %d, pix written: %d\n", fail_count, pix_written));
171 #endif
173 SetAPen(rp, fi.orig_apen);
175 ReturnBool("Flood", success);
177 AROS_LIBFUNC_EXIT
178 } /* Flood */
183 static VOID settmpraspixel(BYTE *rasptr, LONG x, LONG y, ULONG bpr, UBYTE state)
185 ULONG idx = COORD_TO_BYTEIDX(x, y, bpr);
186 UBYTE mask = XCOORD_TO_MASK( x );
188 if (state)
189 rasptr[idx] |= mask;
190 else
191 rasptr[idx] &= ~mask;
193 return;
196 static BOOL gettmpraspixel(BYTE *rasptr, LONG x, LONG y, ULONG bpr )
198 ULONG idx = COORD_TO_BYTEIDX(x, y, bpr);
199 UBYTE mask = XCOORD_TO_MASK( x );
200 BOOL state;
202 /* D(bug("gettmpraspixel (%d, %d, %d): idx=%d, mask=%d, rasptr[idx]=%d, state=%d\n"
203 ,x, y, bpr, idx, mask, rasptr[idx], rasptr[idx] & mask));
205 state = ((rasptr[idx] & mask) != 0);
207 /* D(bug("Returning %d\n", state));
209 return state;
213 #undef GfxBase
214 #define GfxBase (fi->gfxbase)
216 static BOOL color_isfillable(struct fillinfo *fi, LONG x, LONG y)
218 BOOL fill;
220 if (x < 0 || y < 0 || x >= fi->rp_width || y >= fi->rp_height)
221 return FALSE;
223 if (gettmpraspixel(fi->rasptr, x, y, fi->bpr))
225 /* D(bug("Pixel checked twice at (%d, %d)\n", x, y)); */
226 fill = FALSE;
227 #if DEBUG_FLOOD
228 fail_count ++;
229 #endif
231 else
233 fill = (fi->fillpen == ReadPixel(fi->rp, x, y));
236 return fill;
239 static BOOL outline_isfillable(struct fillinfo *fi, LONG x, LONG y)
241 BOOL fill;
242 /* EnterFunc(bug("outline_isfillable(fi=%p, x=%d, y=%d)\n",
243 fi, x, y));
245 if (x < 0 || y < 0 || x >= fi->rp_width || y >= fi->rp_height)
246 return FALSE;
248 if (gettmpraspixel(fi->rasptr, x, y, fi->bpr))
250 /* D(bug("Pixel checked twice at (%d, %d)\n", x, y)); */
251 fill = FALSE;
252 #if DEBUG_FLOOD
253 fail_count ++;
254 #endif
256 else
258 fill = (fi->fillpen != ReadPixel(fi->rp, x, y));
261 /* D(bug("fillpen: %d, pen: %d\n", fi->fillpen, ReadPixel(fi->rp, x, y)));
264 /* ReturnBool("outline_isfillable", fill);
266 return fill;
271 static VOID putfillpixel(struct fillinfo *fi, LONG x, LONG y)
274 /* TODO: Implement use of patterns */
276 #ifdef USE_WRITEPIXEL
277 ULONG pixval, set_pixel = 0UL;
279 if (fi->rp->AreaPtrn)
281 set_pixel = pattern_pen(fi->rp
282 , x, y
283 , fi->orig_apen
284 , fi->orig_bpen
285 , &pixval
286 , GfxBase);
288 else
290 pixval = GetAPen(fi->rp);
291 set_pixel = TRUE;
294 if (set_pixel)
296 SetAPen(fi->rp, pixval);
297 WritePixel(fi->rp, x, y);
300 #endif
302 settmpraspixel(fi->rasptr, x, y, fi->bpr, 1);
304 #if DEBUG_FLOOD
305 pix_written ++;
306 #endif
307 return;
310 #define STACKSIZE 100
312 struct stack
314 ULONG current;
315 struct scanline
317 LONG x, y;
318 } items [STACKSIZE];
321 static VOID init_stack(struct stack *s)
323 s->current = 0;
326 static BOOL push(struct stack *s, LONG x, LONG y)
328 if (s->current == STACKSIZE)
329 return FALSE;
331 s->items[s->current].x = x;
332 s->items[s->current].y = y;
335 s->current ++;
337 return TRUE;
340 static BOOL pop(struct stack *s, LONG *xptr, LONG *yptr)
342 if (s->current == 0)
343 return FALSE;
345 s->current --;
348 *xptr = s->items[s->current].x;
349 *yptr = s->items[s->current].y;
352 return TRUE;
355 static BOOL filline(struct fillinfo *fi, LONG start_x, LONG start_y)
357 LONG x;
359 LONG rightmost_above, rightmost_below;
360 LONG leftmost_above, leftmost_below;
361 struct stack stack;
363 EnterFunc(bug("filline(fi=%p, start_x=%d, start_y=%d)\n"
364 ,fi, start_x, start_y));
366 init_stack(&stack);
368 for (;;) {
369 /* Scan right */
371 rightmost_above = start_x;
372 rightmost_below = start_x;
374 for (x = start_x + 1; ; x ++)
377 if (fi->isfillable(fi, x, start_y))
379 putfillpixel(fi, x, start_y);
381 /* Check above */
382 if (x > rightmost_above)
384 if (fi->isfillable(fi, x, start_y - 1))
386 /* Find rightmost pixel */
388 for (rightmost_above = x; ; rightmost_above ++)
390 if (!fi->isfillable(fi, rightmost_above + 1, start_y - 1))
391 break;
394 /* Fill that line */
395 if (!push(&stack, rightmost_above, start_y - 1))
396 ReturnBool("filline (stack full)", FALSE);
397 /* filline(fi, rightmost_above, start_y - 1);
398 */ }
402 /* Check below */
404 if (x > rightmost_below)
406 if (fi->isfillable(fi, x, start_y + 1))
408 /* Find rightmost pixel */
410 for (rightmost_below = x; ; rightmost_below ++)
412 if (!fi->isfillable(fi, rightmost_below + 1, start_y + 1))
413 break;
416 /* Fill that line */
417 if (!push(&stack, rightmost_below, start_y + 1))
418 ReturnBool("filline (stack full)", FALSE);
420 /* filline(fi, rightmost_below, start_y + 1);
421 */ }
426 else
427 break;
429 } /* for (scan right) */
432 /* scan left */
435 leftmost_above = start_x + 1;
436 leftmost_below = start_x + 1;
438 for (x = start_x; ; x -- )
442 if (fi->isfillable(fi, x, start_y))
444 putfillpixel(fi, x, start_y);
446 /* Check above */
447 if (x <= leftmost_above)
449 if (fi->isfillable(fi, x, start_y - 1))
451 /* Find rightmost pixel */
453 for (leftmost_above = x; ; leftmost_above --)
455 if (!fi->isfillable(fi, leftmost_above - 1, start_y - 1))
456 break;
459 /* Fill that line */
460 if (!push(&stack, leftmost_above, start_y - 1))
461 ReturnBool("filline (stack full)", FALSE);
462 /* filline(fi, leftmost_above, start_y - 1);
463 */ }
467 /* Check below */
469 if (x < leftmost_below)
471 if (fi->isfillable(fi, x, start_y + 1))
473 /* Find rightmost pixel */
475 for (leftmost_below = x; ; leftmost_below --)
477 if (!fi->isfillable(fi, leftmost_below - 1, start_y + 1))
478 break;
481 /* Fill that line */
482 if (!push(&stack, leftmost_below, start_y + 1))
483 ReturnBool("filline (stack full)", FALSE);
485 /* filline(fi, leftmost_below, start_y + 1);
486 */ }
491 else
492 break;
494 } /* for (scan left) */
497 if (!pop(&stack, &start_x, &start_y))
498 break;
499 D(bug("\t\t\tpop(%d, %d)\n", start_x, start_y));
501 } /* forever */
503 ReturnBool("filline", TRUE);
508 #undef GfxBase