#ifndef UNSUPPORTED REGISTERS(3) static void tracecolor(int xstart, int ystart, int xend, int yend, register int x, register int y) { int dir = RIGHT, fill = 0; register unsigned char *calc; int peri = 0; cpixeldata_t c = (cpixeldata_t) calculatepixel(x, y, 0); cpixeldata_t w = (cpixeldata_t) 0; cpixeldata_t inset = (cpixeldata_t) cpalette.pixels[0]; putpixel(x, y, c); calc = calculated + x + y * CALCWIDTH; *calc = (unsigned char) 1; while (x > xstart && getpixel(x - 1, y) == c) x--, calc--; *calc = (unsigned char) 2; if (c == inset) peri = 1; do { if (!fill && !*calc) { *calc = (unsigned char) 1; putpixel(x, y, c); } switch (dir) { case RIGHT: if (y > ystart) { if (!*(calc - CALCWIDTH)) { w = (cpixeldata_t) calculatepixel(x, y - 1, peri); putpixel(x, y - 1, w); *(calc - CALCWIDTH) = (unsigned char) 1; } else w = getpixel(x, y - 1); if (w == c) { dir = UP; calc -= CALCWIDTH; y--; break; } } if (x < xend) { if (!*(calc + 1)) { w = (cpixeldata_t) calculatepixel(x + 1, y, peri); putpixel(x + 1, y, w); *(calc + 1) = (unsigned char) 1; } else w = getpixel(x + 1, y); if (w == c) { calc++; x++; break; } } if (y < yend) { if (!*(calc + CALCWIDTH)) { w = (cpixeldata_t) calculatepixel(x, y + 1, peri); putpixel(x, y + 1, w); *(calc + CALCWIDTH) = (unsigned char) 1; } else w = getpixel(x, y + 1); if (w == c) { dir = DOWN; calc += CALCWIDTH; y++; break; } } if (*calc == (unsigned char) 2) { *calc = (unsigned char) 1; return; } dir = LEFT; x--; calc--; break; case LEFT: if (y < yend) { if (!*(calc + CALCWIDTH)) { w = (cpixeldata_t) calculatepixel(x, y + 1, peri); putpixel(x, y + 1, w); *(calc + CALCWIDTH) = (unsigned char) 1; } else w = getpixel(x, y + 1); if (w == c) { dir = DOWN; calc += CALCWIDTH; y++; break; } } if (x > xstart) { if (!*(calc - 1)) { w = (cpixeldata_t) calculatepixel(x - 1, y, peri); putpixel(x - 1, y, w); *(calc - 1) = (unsigned char) 1; } else w = getpixel(x - 1, y); if (w == c) { calc--; x--; break; } } if (y > ystart) { if (!*(calc - CALCWIDTH)) { w = (cpixeldata_t) calculatepixel(x, y - 1, peri); putpixel(x, y - 1, w); *(calc - CALCWIDTH) = (unsigned char) 1; } else w = getpixel(x, y - 1); if (w == c) { dir = UP; calc -= CALCWIDTH; y--; break; } } dir = RIGHT; x++; calc++; break; case UP: if (fill) { unsigned char *calc1; cpixel_t *pixel1; calc1 = calc + 1; pixel1 = p_add((cpixel_t *) cimage.currlines[y], x + 1); while (pixel1 <= p_add((cpixel_t *) cimage.currlines[y], xend)) { if (!*calc1) *calc1 = (unsigned char) 1, p_set(pixel1, c); else if (p_get(pixel1) != c) break; p_inc(pixel1, 1); calc1++; } } if (x > xstart) { if (!*(calc - 1)) { w = (cpixeldata_t) calculatepixel(x - 1, y, peri); putpixel(x - 1, y, w); *(calc - 1) = (unsigned char) 1; } w = getpixel(x - 1, y); if (w == c) { dir = LEFT; calc--; x--; break; } } if (y > ystart) { if (!*(calc - CALCWIDTH)) { w = (cpixeldata_t) calculatepixel(x, y - 1, peri); putpixel(x, y - 1, w); *(calc - CALCWIDTH) = (unsigned char) 1; } w = getpixel(x, y - 1); if (w == c) { calc -= CALCWIDTH; y--; break; } } if (x < xend) { if (!*(calc + 1)) { w = (cpixeldata_t) calculatepixel(x + 1, y, peri); putpixel(x + 1, y, w); *(calc + 1) = (unsigned char) 1; } else w = getpixel(x + 1, y); if (w == c) { dir = RIGHT; calc++; x++; break; } } dir = DOWN; y++; calc += CALCWIDTH; break; case DOWN: if (x < xend) { if (!*(calc + 1)) { w = (cpixeldata_t) calculatepixel(x + 1, y, peri); putpixel(x + 1, y, w); *(calc + 1) = (unsigned char) 1; } else w = getpixel(x + 1, y); if (w == c) { dir = RIGHT; calc++; x++; break; } } if (y < yend) { if (!*(calc + CALCWIDTH)) { w = (cpixeldata_t) calculatepixel(x, y + 1, peri); putpixel(x, y + 1, w); *(calc + CALCWIDTH) = (unsigned char) 1; } else w = getpixel(x, y + 1); if (w == c) { dir = DOWN; calc += CALCWIDTH; y++; break; } } if (x > xstart) { if (!*(calc - 1)) { w = (cpixeldata_t) calculatepixel(x - 1, y, peri); putpixel(x - 1, y, w); *(calc - 1) = (unsigned char) 1; } else w = getpixel(x - 1, y); if (w == c) { dir = LEFT; calc--; x--; break; } } dir = UP; calc -= CALCWIDTH; y--; break; } if (*calc == (unsigned char) 2) { if (fill) { *calc = (unsigned char) 1; return; } fill = 1; dir = RIGHT; } } while (1); } #ifndef SLOWCACHESYNC #ifndef nthreads #define ethreads 1 REGISTERS(3) static INLINE void tracepoint(int xp, int yp, int dir, unsigned int color, int xstart, int xend, int ystart, int yend) { unsigned char *calc; cpixeldata_t mycolor; int i, lookdir; unsigned int c; int x, y; int periodicity = (dir & 8) != 0; dir &= ~8; calc = calculated + xp + yp * CALCWIDTH; if (!(*calc & (CALCULATED | CALCULATING))) { *calc |= CALCULATING; mycolor = (cpixeldata_t) calculatepixel(xp, yp, periodicity); putpixel(xp, yp, mycolor); *calc |= CALCULATED; *calc &= ~CALCULATING; } else { if (*calc & CALCULATING) { /*Bad luck..some other procesor is working with out pixel :) try *later.*/ addstack(xp, yp, dir, color, periodicity); return; } mycolor = getpixel(xp, yp); } while (1) { periodicity = (mycolor == inset || color == inset); lookdir = turnright(dir); for (i = 0; i < 3; i++) { x = xp + dirrections[lookdir][0]; y = yp + dirrections[lookdir][1]; if (x >= xstart && x <= xend && y >= ystart && y <= yend) { calc = calculated + x + y * CALCWIDTH; if (!(*calc & (CALCULATED | CALCULATING))) { *calc |= CALCULATING; c = calculatepixel(x, y, periodicity); putpixel(x, y, c); *calc |= CALCULATED; *calc &= ~CALCULATING; } else { if (*calc & CALCULATING) { /*Bad luck..some other procesor is working with out pixel :) try *later.*/ addstack(xp, yp, dir, color, periodicity); return; } c = getpixel(x, y); } if (c == mycolor) break; if (c != color) { int dir2 = turnright(lookdir); int mask = (1 << dir2) + (1 << turnright(dir2)); if (!(*calc & mask)) { addstack(x, y, dir2, mycolor, periodicity); } color = c; } } lookdir = turnleft(lookdir); } x = xp + dirrections[lookdir][0]; y = yp + dirrections[lookdir][1]; if (x >= xstart && x <= xend && y >= ystart && y <= yend) { calc = calculated + x + y * CALCWIDTH; if (!(*calc & (1 << lookdir))) { *calc |= (1 << lookdir); if (size < 10) { addstack(x, y, lookdir, color, periodicity); return; } else { xp = x; yp = y; dir = lookdir; calc = calculated + xp + yp * CALCWIDTH; } } else return; } else return; } } static void queue(void *data, struct taskinfo *task, int r1, int r2) { int x, y, d, c; int pos = 0; while (1) { int nstack; xth_lock(0); while (!size) { /*Well stack is empty. */ if (exitnow) { /*Possibly everything is done now.. */ xth_unlock(0); return; } if (nwaiting == nthreads - 1) { /*We are last working CPU */ exitnow = 1; /*So we should exit now */ xth_wakeup(0); /*Wake up all waiting tasks */ xth_unlock(0); return; /*and exit :) */ } nwaiting++; /*We are not latest task. */ xth_sleep(0, 0); /*Wait until other task will push some data */ nwaiting--; if (exitnow) { /*Evrything is done now? */ xth_unlock(0); return; } } nstack = xth_nthread(task); while (!sizes[nstack]) if (nstack != nthreads - 1) nstack++; else nstack = 0; sizes[nstack]--; size--; pos++; if (pos >= sizes[nstack]) pos = 0; x = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)].x; y = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)].y; d = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)]. direction; c = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)].color; /* Well stack currently is queue. Should have better results at * SMP, since has tendency trace all ways at time, so (I believe) * should avoid some cache conflict and situation where queue is * empty. At the other hand, makes queue bigger and needs following * copy: */ starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)] = starts[nstack][sizes[nstack] >> PAGESHIFT][sizes[nstack] & (PAGESIZE - 1)]; xth_unlock(0); tracepoint(x, y, d, c, xstart, xend, ystart, yend); } } static void bfill(void *dat, struct taskinfo *task, int r1, int r2) { int y; cpixel_t *pos, *end; unsigned char *data; r1 += ystart + 1; r2 += ystart + 1; for (y = r1; y < r2; y++) { pos = p_add((cpixel_t *) cimage.currlines[y], xstart + 1); end = p_add((cpixel_t *) cimage.currlines[y], xend); data = calculated + xstart + y * CALCWIDTH + 1; for (; pos < end; p_inc(pos, 1), data++) { if (!*data) p_copy(pos, 0, pos, -1); } } } #undef ethreads #endif #endif static void dosymetries(int x1, int x2, int y1, int y2, int xsym, int cx1, int cx2) { if (cx1 != x1) { register int y; register cpixel_t *xx1, *xx2; for (y = y1; y <= y2; y++) { xx1 = p_add((cpixel_t *) cimage.currlines[y], x1); xx2 = p_add((cpixel_t *) cimage.currlines[y], 2 * xsym - x1); while (xx1 < xx2) { p_copy(xx1, 0, xx2, 0); p_inc(xx1, 1); p_inc(xx2, -1); } } } if (cx2 != x2) { register int y; register cpixel_t *xx1, *xx2; for (y = y1; y <= y2; y++) { xx1 = p_add((cpixel_t *) cimage.currlines[y], x2); xx2 = p_add((cpixel_t *) cimage.currlines[y], 2 * xsym - x2); while (xx1 > xx2) { p_copy(xx1, 0, xx2, 0); p_inc(xx1, -1); p_inc(xx2, 1); } } } } #endif #undef dosymetries #undef tracepoint #undef tracecolor #undef queue #undef bfill