00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "common.h"
00011 #include "bits.h"
00012 #include "memgfx.h"
00013 #include "gfxPoly.h"
00014
00015 void mgDrawPolyOutline(struct memGfx *mg, struct gfxPoly *poly, Color color)
00016
00017 {
00018 struct gfxPoint *a, *b, *end;
00019
00020 a = end = poly->ptList;
00021 b = a->next;
00022 for (;;)
00023 {
00024 mgDrawLine(mg, a->x, a->y, b->x, b->y, color);
00025 a = b;
00026 b = b->next;
00027 if (a == end)
00028 break;
00029 }
00030 }
00031
00032
00033
00034
00035
00036
00037 #define UPDIR 1
00038 #define DOWNDIR 0
00039
00040 static UBYTE *on_off_buf;
00041
00042 static int pxmin, pxmax, pymin, pymax;
00043
00044 static void find_pminmax(struct gfxPoly *poly)
00045 {
00046 struct gfxPoint *pointpt;
00047 int i;
00048
00049 pointpt = poly->ptList;
00050 pxmin = pxmax = pointpt->x;
00051 pymin = pymax = pointpt->y;
00052 pointpt = pointpt->next;
00053
00054 i = poly->ptCount;
00055 while (--i > 0)
00056 {
00057 if (pxmin > pointpt->x) pxmin = pointpt->x;
00058 if (pxmax < pointpt->x) pxmax = pointpt->x;
00059 if (pymin > pointpt->y) pymin = pointpt->y;
00060 if (pymax < pointpt->y) pymax = pointpt->y;
00061 pointpt = pointpt->next;
00062 }
00063 }
00064
00065 static void xor_pt(int bpr, int x, int y)
00066
00067 {
00068 UBYTE rot;
00069
00070 rot = ((unsigned)0x80) >> (x&7);
00071 on_off_buf[ bpr*y + (x>>3) ] ^= rot;
00072 }
00073
00074
00075 static void y_xor_line(int bpr, int x1, int y1, int x2, int y2)
00076
00077 {
00078 UBYTE *imagept = on_off_buf;
00079 UBYTE rot;
00080 int duty_cycle;
00081 int delta_x, delta_y;
00082 int dots;
00083 int swap;
00084
00085 if (x1 > x2)
00086 {
00087 swap = x1;
00088 x1 = x2;
00089 x2 = swap;
00090 swap = y1;
00091 y1 = y2;
00092 y2 = swap;
00093 }
00094 delta_y = y2-y1;
00095 delta_x = x2-x1;
00096 rot = ((unsigned)0x80) >> (x1&7);
00097 imagept += bpr*y1 + (x1>>3);
00098
00099
00100 if (delta_y < 0)
00101 {
00102 delta_y = -delta_y;
00103 bpr = -bpr;
00104 }
00105 duty_cycle = (delta_x - delta_y)/2;
00106 *(imagept) ^= rot;
00107 if (delta_x < delta_y)
00108 {
00109 dots = delta_y;
00110 while (--dots >= 0)
00111 {
00112 *(imagept) ^= rot;
00113 duty_cycle += delta_x;
00114 imagept += bpr;
00115 if (duty_cycle > 0)
00116 {
00117 duty_cycle -= delta_y;
00118 rot >>= 1;
00119 if (rot == 0)
00120 {
00121 imagept++;
00122 rot = 0x80;
00123 }
00124 }
00125 }
00126 }
00127 else
00128 {
00129 dots = delta_x;
00130 while (--dots >= 0)
00131 {
00132 duty_cycle -= delta_y;
00133 if (duty_cycle < 0)
00134 {
00135 *(imagept) ^= rot;
00136 duty_cycle += delta_x;
00137 imagept += bpr;
00138 }
00139 rot >>= 1;
00140 if (rot == 0)
00141 {
00142 imagept++;
00143 rot = 0x80;
00144 }
00145 }
00146 }
00147 }
00148
00149
00150 static void drawAfterOnOff(struct memGfx *mg, Color color, int bpr, int width,
00151 int height)
00152
00153 {
00154 UBYTE *linept = on_off_buf;
00155 int y;
00156
00157 for (y=0; y<height; ++y)
00158 {
00159 int start = 0;
00160 int end;
00161 for (;;)
00162 {
00163 start = bitFindSet(linept, start, width);
00164 if (start >= width)
00165 break;
00166 end = bitFindSet(linept, start+1, width);
00167 mgLineH(mg, y+pymin, start+pxmin, end+pxmin, color);
00168 start = end+1;
00169 }
00170 linept += bpr;
00171 }
00172 }
00173
00174 static void fillConcave(struct memGfx *mg, struct gfxPoly *poly, Color color)
00175
00176 {
00177 struct gfxPoint *pointpt;
00178 int x,y;
00179 int ox,oy;
00180 int lastdir;
00181 int i;
00182 int bpr;
00183 int width, height;
00184 long size;
00185
00186 find_pminmax(poly);
00187 if (pymin==pymax)
00188 {
00189 mgLineH(mg, pymin, pxmin, pxmax,color);
00190 return;
00191 }
00192 width = pxmax - pxmin + 1;
00193 height = pymax - pymin + 1;
00194 bpr = ((width+7)>>3);
00195 size = (long)bpr*height;
00196 if ((on_off_buf = needMem(size)) == NULL)
00197 return;
00198 pointpt = poly->ptList;
00199 x = pointpt->x;
00200 y = pointpt->y;
00201
00202 do
00203 {
00204 pointpt = pointpt->next;
00205 ox = pointpt->x;
00206 oy = pointpt->y;
00207 }
00208 while (oy == y);
00209
00210 if (oy>y)
00211 lastdir = UPDIR;
00212 else
00213 lastdir = DOWNDIR;
00214
00215 i = poly->ptCount;
00216 while (--i >= 0)
00217 {
00218 pointpt = pointpt->next;
00219 x = pointpt->x;
00220 y = pointpt->y;
00221 if (y!=oy)
00222 {
00223 y_xor_line(bpr,ox-pxmin,oy-pymin,x-pxmin,y-pymin);
00224 if (y>oy)
00225 if (lastdir == UPDIR)
00226 xor_pt(bpr,ox-pxmin,oy-pymin);
00227 else
00228 lastdir = UPDIR;
00229 else
00230 if (lastdir == DOWNDIR)
00231 xor_pt(bpr,ox-pxmin,oy-pymin);
00232 else
00233 lastdir = DOWNDIR;
00234 }
00235 ox = x;
00236 oy = y;
00237 }
00238
00239 drawAfterOnOff(mg, color, bpr, width, height);
00240 freez(&on_off_buf);
00241 return;
00242 }
00243
00244
00245
00246 #ifdef SOME_OFF_BY_ONE_PROBLEMS
00247 static int *xdda_ebuf(int *ebuf, int x1, int y1, int x2, int y2)
00248
00249 {
00250 int incx, incy;
00251 int x;
00252 int duty_cycle;
00253 int delta_x, delta_y;
00254 int dots;
00255
00256 delta_y = y2-y1;
00257 delta_x = x2-x1;
00258 incx = incy = 1;
00259 x = x1;
00260 if (delta_y < 0)
00261 {
00262 delta_y = -delta_y;
00263 incy = -1;
00264 }
00265
00266 if (delta_x < 0)
00267 {
00268 delta_x = -delta_x;
00269 incx = -1;
00270 }
00271
00272 duty_cycle = (delta_x - delta_y)/2;
00273 if (delta_x >= delta_y)
00274 {
00275 int lasty = y1-1;
00276 dots = delta_x+1;
00277 while (--dots >= 0)
00278 {
00279 if (lasty != y1)
00280 {
00281 *ebuf++ = x1;
00282 lasty = y1;
00283 }
00284 duty_cycle -= delta_y;
00285 x1 += incx;
00286 if (duty_cycle < 0)
00287 {
00288 duty_cycle += delta_x;
00289 y1+=incy;
00290 }
00291 }
00292 }
00293 else
00294 {
00295 dots = delta_y+1;
00296 while (--dots >= 0)
00297 {
00298 *ebuf++ = x1;
00299 duty_cycle += delta_x;
00300 y1+=incy;
00301 if (duty_cycle > 0)
00302 {
00303 duty_cycle -= delta_y;
00304 x1 += incx;
00305 }
00306 }
00307 }
00308 return(ebuf);
00309 }
00310 #endif
00311
00312
00313 #ifdef CONVEX_OPTIMIZATION
00314 int *fill_ebuf(struct gfxPoint *thread, int count, int *ebuf)
00315
00316
00317
00318 {
00319 int x, y, ox, oy;
00320 int i;
00321
00322 ox = thread->x;
00323 oy = thread->y;
00324
00325 for (i=0; i<count; ++i)
00326 {
00327 thread = thread->next;
00328 x = thread->x;
00329 y = thread->y;
00330 if (y!=oy)
00331 ebuf = xdda_ebuf(ebuf,ox,oy,x,y) - 1;
00332 ox = x;
00333 oy = y;
00334 }
00335 return(ebuf+1);
00336 }
00337
00338 static void blast_hlines(struct memGfx *mg,
00339 int *thread1,
00340 int *thread2,
00341 int y,
00342 int count,
00343 Color color)
00344
00345 {
00346 int x1, x2;
00347 thread2 += count;
00348 while (--count >= 0)
00349 {
00350 x1 = *thread1++;
00351 x2 = *(--thread2);
00352 if (x1 > x2)
00353 mgLineH(mg, y, x2, x1, color);
00354 else
00355 mgLineH(mg, y, x1, x2, color);
00356 y += 1;
00357 }
00358 }
00359
00360 void mgDrawPolyFilled(struct memGfx *mg, struct gfxPoly *poly, Color color)
00361
00362 {
00363 struct gfxPoint *p;
00364 struct gfxPoint *np;
00365 struct gfxPoint *peak;
00366 struct gfxPoint *valley;
00367 int highy;
00368 int i;
00369 int pcount;
00370 int lasty;
00371
00372 peak = p = poly->ptList;
00373 i = poly->ptCount;
00374 highy = p->y;
00375 pcount = 0;
00376 while (--i > 0)
00377 {
00378 p = p->next;
00379 if (p->y <= highy)
00380 {
00381 peak = p;
00382 highy = p->y;
00383 }
00384 }
00385 p = peak;
00386 np = p->next;
00387 i = poly->ptCount;
00388 while (--i >= 0)
00389 {
00390 if (np->y < p->y)
00391 {
00392 int totalHeight;
00393 int *thread1, *thread2;
00394 valley = p;
00395 p = np;
00396 np = np->next;
00397 while (--i >= 0)
00398 {
00399 if (np->y > p->y)
00400 {
00401 fillConcave(mg, poly, color);
00402 return;
00403 }
00404 p = np;
00405 np = np->next;
00406 }
00407 totalHeight = valley->y - highy + 1;
00408 AllocArray(thread1, totalHeight);
00409 AllocArray(thread2, totalHeight);
00410 fill_ebuf(peak, pcount, thread1);
00411 pcount = fill_ebuf(valley, poly->ptCount - pcount, thread2)
00412 - thread2;
00413 blast_hlines(mg, thread1, thread2, highy, pcount, color);
00414 freeMem(thread1);
00415 freeMem(thread2);
00416 return;
00417 }
00418 pcount++;
00419 p = np;
00420 np = np->next;
00421 }
00422 return;
00423 }
00424 #endif
00425
00426 void mgDrawPoly(struct memGfx *mg, struct gfxPoly *poly, Color color,
00427 boolean filled)
00428
00429 {
00430 if (filled)
00431 fillConcave(mg, poly, color);
00432
00433 mgDrawPolyOutline(mg, poly, color);
00434 }
00435