Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/engine/btraced.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/btraced.c')
-rw-r--r--src/engine/btraced.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/src/engine/btraced.c b/src/engine/btraced.c
new file mode 100644
index 0000000..e0073c0
--- /dev/null
+++ b/src/engine/btraced.c
@@ -0,0 +1,466 @@
+#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