00001
00002
00003
00004
00005
00006
00007 #include "common.h"
00008 #include "memgfx.h"
00009 #include "gemfont.h"
00010 #include "localmem.h"
00011 #include "vGfx.h"
00012 #include "vGfxPrivate.h"
00013 #include "colHash.h"
00014
00015 static char const rcsid[] = "$Id: memgfx.c,v 1.47 2007/04/15 00:33:35 galt Exp $";
00016
00017 static void mgSetDefaultColorMap(struct memGfx *mg)
00018
00019 {
00020
00021 int i;
00022 for (i=0; i<ArraySize(mgFixedColors); ++i)
00023 {
00024 struct rgbColor *c = &mgFixedColors[i];
00025 mgAddColor(mg, c->r, c->g, c->b);
00026 }
00027 }
00028
00029
00030 void mgSetClip(struct memGfx *mg, int x, int y, int width, int height)
00031
00032 {
00033 int x2, y2;
00034 if (x < 0)
00035 x = 0;
00036 if (y < 0)
00037 y = 0;
00038 x2 = x + width;
00039 if (x2 > mg->width)
00040 x2 = mg->width;
00041 y2 = y + height;
00042 if (y2 > mg->height)
00043 y2 = mg->height;
00044 mg->clipMinX = x;
00045 mg->clipMaxX = x2;
00046 mg->clipMinY = y;
00047 mg->clipMaxY = y2;
00048 }
00049
00050 void mgUnclip(struct memGfx *mg)
00051
00052 {
00053 mgSetClip(mg, 0,0,mg->width, mg->height);
00054 }
00055
00056 struct memGfx *mgNew(int width, int height)
00057
00058 {
00059 struct memGfx *mg;
00060
00061 mg = needMem(sizeof(*mg));
00062 mg->pixels = needLargeMem(width*height);
00063 mg->width = width;
00064 mg->height = height;
00065 mg->colorHash = colHashNew();
00066 mgSetDefaultColorMap(mg);
00067 mgUnclip(mg);
00068 return mg;
00069 }
00070
00071 void mgClearPixels(struct memGfx *mg)
00072
00073 {
00074 zeroBytes(mg->pixels, mg->width*mg->height);
00075 }
00076
00077 Color mgFindColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
00078
00079
00080
00081 {
00082 struct colHashEl *che;
00083 if ((che = colHashLookup(mg->colorHash, r, g, b)) != NULL)
00084 return che->ix;
00085 if (mgColorsFree(mg))
00086 return mgAddColor(mg, r, g, b);
00087 return mgClosestColor(mg, r, g, b);
00088 }
00089
00090
00091 struct rgbColor mgColorIxToRgb(struct memGfx *mg, int colorIx)
00092
00093 {
00094 return mg->colorMap[colorIx];
00095 }
00096
00097 Color mgClosestColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
00098
00099 {
00100 struct rgbColor *c = mg->colorMap;
00101 int closestDist = 0x7fffffff;
00102 int closestIx = -1;
00103 int dist, dif;
00104 int i;
00105 for (i=0; i<mg->colorsUsed; ++i)
00106 {
00107 dif = c->r - r;
00108 dist = dif*dif;
00109 dif = c->g - g;
00110 dist += dif*dif;
00111 dif = c->b - b;
00112 dist += dif*dif;
00113 if (dist < closestDist)
00114 {
00115 closestDist = dist;
00116 closestIx = i;
00117 }
00118 ++c;
00119 }
00120 return closestIx;
00121 }
00122
00123
00124 Color mgAddColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
00125
00126 {
00127 int colIx = mg->colorsUsed;
00128 if (colIx < 256)
00129 {
00130 struct rgbColor *c = mg->colorMap + mg->colorsUsed;
00131 c->r = r;
00132 c->g = g;
00133 c->b = b;
00134 mg->colorsUsed += 1;
00135 colHashAdd(mg->colorHash, r, g, b, colIx);
00136 }
00137 return (Color)colIx;
00138 }
00139
00140 int mgColorsFree(struct memGfx *mg)
00141
00142 {
00143 return 256-mg->colorsUsed;
00144 }
00145
00146 void mgFree(struct memGfx **pmg)
00147 {
00148 struct memGfx *mg = *pmg;
00149 if (mg != NULL)
00150 {
00151 if (mg->pixels != NULL)
00152 freeMem(mg->pixels);
00153 colHashFree(&mg->colorHash);
00154 zeroBytes(mg, sizeof(*mg));
00155 freeMem(mg);
00156 }
00157 *pmg = NULL;
00158 }
00159
00160 static void nonZeroCopy(Color *d, Color *s, int width)
00161
00162 {
00163 Color c;
00164 int i;
00165 for (i=0; i<width; ++i)
00166 {
00167 if ((c = s[i]) != 0)
00168 d[i] = c;
00169 }
00170 }
00171
00172 static void mgPutSegMaybeZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots, boolean zeroClear)
00173
00174
00175 {
00176 int x2;
00177 Color *pt;
00178 if (y < mg->clipMinY || y > mg->clipMaxY)
00179 return;
00180 x2 = x + width;
00181 if (x2 > mg->clipMaxX)
00182 x2 = mg->clipMaxX;
00183 if (x < mg->clipMinX)
00184 {
00185 dots += mg->clipMinX - x;
00186 x = mg->clipMinX;
00187 }
00188 width = x2 - x;
00189 if (width > 0)
00190 {
00191 pt = _mgPixAdr(mg, x, y);
00192 if (zeroClear)
00193 nonZeroCopy(pt, dots, width);
00194 else
00195 memcpy(pt, dots, width);
00196 }
00197 }
00198
00199 void mgVerticalSmear(struct memGfx *mg,
00200 int xOff, int yOff, int width, int height,
00201 unsigned char *dots, boolean zeroClear)
00202
00203 {
00204 while (--height >= 0)
00205 {
00206 mgPutSegMaybeZeroClear(mg, xOff, yOff, width, dots, zeroClear);
00207 ++yOff;
00208 }
00209 }
00210
00211 void mgDrawBox(struct memGfx *mg, int x, int y, int width, int height, Color color)
00212 {
00213 int i;
00214 Color *pt;
00215 int x2 = x + width;
00216 int y2 = y + height;
00217 int wrapCount;
00218
00219 if (x < mg->clipMinX)
00220 x = mg->clipMinX;
00221 if (y < mg->clipMinY)
00222 y = mg->clipMinY;
00223 if (x2 > mg->clipMaxX)
00224 x2 = mg->clipMaxX;
00225 if (y2 > mg->clipMaxY)
00226 y2 = mg->clipMaxY;
00227 width = x2-x;
00228 height = y2-y;
00229 if (width > 0 && height > 0)
00230 {
00231 pt = _mgPixAdr(mg,x,y);
00232
00233 wrapCount = _mgBpr(mg) - width;
00234 while (--height >= 0)
00235 {
00236 i = width;
00237 while (--i >= 0)
00238 *pt++ = color;
00239 pt += wrapCount;
00240 }
00241 }
00242 }
00243
00244 void mgBrezy(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color,
00245 int yBase, boolean fillFromBase)
00246
00247 {
00248 if (x1 == x2)
00249 {
00250 int y,height;
00251 if (y1 > y2)
00252 {
00253 y = y2;
00254 height = y1-y2+1;
00255 }
00256 else
00257 {
00258 y = y1;
00259 height = y2-y1+1;
00260 }
00261 if (fillFromBase)
00262 {
00263 if (y < yBase)
00264 mgDrawBox(mg, x1, y, 1, yBase-y, color);
00265 }
00266 else
00267 mgDrawBox(mg, x1, y, 1, height, color);
00268 }
00269 else if (y1 == y2)
00270 {
00271 int x,width;
00272 if (x1 > x2)
00273 {
00274 x = x2;
00275 width = x1-x2+1;
00276 }
00277 else
00278 {
00279 x = x1;
00280 width = x2-x1+1;
00281 }
00282 if (fillFromBase)
00283 {
00284 if (y1 < yBase)
00285 mgDrawBox(mg, x, y1, width, yBase - y1, color);
00286 }
00287 else
00288 {
00289 mgDrawBox(mg, x, y1, width, 1, color);
00290 }
00291 }
00292 else
00293 {
00294 int duty_cycle;
00295 int incy;
00296 int delta_x, delta_y;
00297 int dots;
00298 delta_y = y2-y1;
00299 delta_x = x2-x1;
00300 if (delta_y < 0)
00301 {
00302 delta_y = -delta_y;
00303 incy = -1;
00304 }
00305 else
00306 {
00307 incy = 1;
00308 }
00309 if (delta_x < 0)
00310 {
00311 delta_x = -delta_x;
00312 incy = -incy;
00313 x1 = x2;
00314 y1 = y2;
00315 }
00316 duty_cycle = (delta_x - delta_y)/2;
00317 if (delta_x >= delta_y)
00318 {
00319 dots = delta_x+1;
00320 while (--dots >= 0)
00321 {
00322 if (fillFromBase)
00323 {
00324 if (y1 < yBase)
00325 mgDrawBox(mg,x1,y1,1,yBase-y1,color);
00326 }
00327 else
00328 mgPutDot(mg,x1,y1,color);
00329 duty_cycle -= delta_y;
00330 x1 += 1;
00331 if (duty_cycle < 0)
00332 {
00333 duty_cycle += delta_x;
00334 y1+=incy;
00335 }
00336 }
00337 }
00338 else
00339 {
00340 dots = delta_y+1;
00341 while (--dots >= 0)
00342 {
00343 if (fillFromBase)
00344 {
00345 if (y1 < yBase)
00346 mgDrawBox(mg,x1,y1,1,yBase-y1,color);
00347 }
00348 else
00349 mgPutDot(mg,x1,y1,color);
00350 duty_cycle += delta_x;
00351 y1+=incy;
00352 if (duty_cycle > 0)
00353 {
00354 duty_cycle -= delta_y;
00355 x1 += 1;
00356 }
00357 }
00358 }
00359 }
00360 }
00361
00362 void mgDrawLine(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color)
00363
00364 {
00365 mgBrezy(mg, x1, y1, x2, y2, color, 0, FALSE);
00366 }
00367
00368 void mgFillUnder(struct memGfx *mg, int x1, int y1, int x2, int y2,
00369 int bottom, Color color)
00370
00371
00372
00373
00374 {
00375 mgBrezy(mg, x1, y1, x2, y2, color, bottom, TRUE);
00376 }
00377
00378 void mgPutSeg(struct memGfx *mg, int x, int y, int width, Color *dots)
00379
00380 {
00381 mgPutSegMaybeZeroClear(mg, x, y, width, dots, FALSE);
00382 }
00383
00384 void mgPutSegZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots)
00385
00386
00387 {
00388 mgPutSegMaybeZeroClear(mg, x, y, width, dots, TRUE);
00389 }
00390
00391
00392 void mgDrawHorizontalLine(struct memGfx *mg, int y1, Color color)
00393
00394
00395 {
00396 mgDrawLine( mg, mg->clipMinX, y1, mg->clipMaxX, y1, color);
00397 }
00398
00399 void mgLineH(struct memGfx *mg, int y, int x1, int x2, Color color)
00400
00401 {
00402 if (y >= mg->clipMinY && y < mg->clipMaxY)
00403 {
00404 int w;
00405 if (x1 < mg->clipMinX)
00406 x1 = mg->clipMinX;
00407 if (x2 > mg->clipMaxX)
00408 x2 = mg->clipMaxX;
00409 w = x2 - x1;
00410 if (w > 0)
00411 {
00412 Color *pt = _mgPixAdr(mg,x1,y);
00413 while (--w >= 0)
00414 *pt++ = color;
00415 }
00416 }
00417 }
00418
00419
00420 boolean mgClipForBlit(int *w, int *h, int *sx, int *sy,
00421 struct memGfx *dest, int *dx, int *dy)
00422 {
00423
00424 int over;
00425
00426 if ((over = dest->clipMinX - *dx) > 0)
00427 {
00428 *w -= over;
00429 *sx += over;
00430 *dx = dest->clipMinX;
00431 }
00432 if ((over = dest->clipMinY - *dy) > 0)
00433 {
00434 *h -= over;
00435 *sy += over;
00436 *dy = dest->clipMinY;
00437 }
00438 if ((over = *w + *dx - dest->clipMaxX) > 0)
00439 *w -= over;
00440 if ((over = *h + *dy - dest->clipMaxY) > 0)
00441 *h -= over;
00442 return (*h > 0 && *w > 0);
00443 }
00444
00445 void mgTextBlit(int width, int height, int bitX, int bitY,
00446 unsigned char *bitData, int bitDataRowBytes,
00447 struct memGfx *dest, int destX, int destY,
00448 Color color, Color backgroundColor)
00449 {
00450 UBYTE *inLine;
00451 UBYTE *outLine;
00452 UBYTE inLineBit;
00453
00454 if (!mgClipForBlit(&width, &height, &bitX, &bitY, dest, &destX, &destY))
00455 return;
00456
00457 inLine = bitData + (bitX>>3) + bitY * bitDataRowBytes;
00458 inLineBit = (0x80 >> (bitX&7));
00459 outLine = _mgPixAdr(dest,destX,destY);
00460 while (--height >= 0)
00461 {
00462 UBYTE *in = inLine;
00463 UBYTE *out = outLine;
00464 UBYTE inBit = inLineBit;
00465 UBYTE inByte = *in++;
00466 int i = width;
00467 while (--i >= 0)
00468 {
00469 if (inBit & inByte)
00470 *out = color;
00471 ++out;
00472 if ((inBit >>= 1) == 0)
00473 {
00474 inByte = *in++;
00475 inBit = 0x80;
00476 }
00477 }
00478 inLine += bitDataRowBytes;
00479 outLine += _mgBpr(dest);
00480 }
00481 }
00482
00483 void mgTextBlitSolid(int width, int height, int bitX, int bitY,
00484 unsigned char *bitData, int bitDataRowBytes,
00485 struct memGfx *dest, int destX, int destY,
00486 Color color, Color backgroundColor)
00487 {
00488 UBYTE *inLine;
00489 UBYTE *outLine;
00490 UBYTE inLineBit;
00491
00492 if (!mgClipForBlit(&width, &height, &bitX, &bitY, dest, &destX, &destY))
00493 return;
00494 inLine = bitData + (bitX>>3) + bitY * bitDataRowBytes;
00495 inLineBit = (0x80 >> (bitX&7));
00496 outLine = _mgPixAdr(dest,destX,destY);
00497 while (--height >= 0)
00498 {
00499 UBYTE *in = inLine;
00500 UBYTE *out = outLine;
00501 UBYTE inBit = inLineBit;
00502 UBYTE inByte = *in++;
00503 int i = width;
00504 while (--i >= 0)
00505 {
00506 *out++ = ((inBit & inByte) ? color : backgroundColor);
00507 if ((inBit >>= 1) == 0)
00508 {
00509 inByte = *in++;
00510 inBit = 0x80;
00511 }
00512 }
00513 inLine += bitDataRowBytes;
00514 outLine += _mgBpr(dest);
00515 }
00516 }
00517
00518
00519 void mgText(struct memGfx *mg, int x, int y, Color color,
00520 MgFont *font, char *text)
00521
00522 {
00523 gfText(mg, font, text, x, y, color, mgTextBlit, MG_WHITE);
00524 }
00525
00526 void mgTextCentered(struct memGfx *mg, int x, int y, int width, int height,
00527 Color color, MgFont *font, char *text)
00528
00529 {
00530 int fWidth, fHeight;
00531 int xoff, yoff;
00532 fWidth = mgFontStringWidth(font, text);
00533 fHeight = mgFontPixelHeight(font);
00534 xoff = x + (width - fWidth)/2;
00535 yoff = y + (height - fHeight)/2;
00536 if (font == mgSmallFont())
00537 {
00538 xoff += 1;
00539 yoff += 1;
00540 }
00541 mgText(mg, xoff, yoff, color, font, text);
00542 }
00543
00544 void mgTextRight(struct memGfx *mg, int x, int y, int width, int height,
00545 Color color, MgFont *font, char *text)
00546
00547 {
00548 int fWidth, fHeight;
00549 int xoff, yoff;
00550 fWidth = mgFontStringWidth(font, text);
00551 fHeight = mgFontPixelHeight(font);
00552 xoff = x + width - fWidth - 1;
00553 yoff = y + (height - fHeight)/2;
00554 if (font == mgSmallFont())
00555 {
00556 xoff += 1;
00557 yoff += 1;
00558 }
00559 mgText(mg, xoff, yoff, color, font, text);
00560 }
00561
00562 int mgFontPixelHeight(MgFont *font)
00563
00564 {
00565 return font_cel_height(font);
00566 }
00567
00568 int mgFontLineHeight(MgFont *font)
00569
00570 {
00571 int celHeight = font_cel_height(font);
00572 return celHeight + 1 + (celHeight/5);
00573 }
00574
00575 int mgFontWidth(MgFont *font, char *chars, int charCount)
00576
00577 {
00578 return fnstring_width(font, (unsigned char *)chars, charCount);
00579 }
00580
00581 int mgFontStringWidth(MgFont *font, char *string)
00582
00583 {
00584 return mgFontWidth(font, string, strlen(string));
00585 }
00586
00587 int mgFontCharWidth(MgFont *font, char c)
00588
00589 {
00590 return mgFontWidth(font, &c, 1);
00591 }
00592
00593 void mgSlowDot(struct memGfx *mg, int x, int y, int colorIx)
00594
00595 {
00596 mgPutDot(mg, x, y, colorIx);
00597 }
00598
00599 int mgSlowGetDot(struct memGfx *mg, int x, int y)
00600
00601 {
00602 return mgGetDot(mg, x, y);
00603 }
00604
00605 struct memGfx *mgRotate90(struct memGfx *in)
00606
00607 {
00608 int iWidth = in->width, iHeight = in->height;
00609 struct memGfx *out = mgNew(iHeight, iWidth);
00610 Color *inCol, *outRow, *outRowStart;
00611 int i,j;
00612
00613 memcpy(out->colorMap, in->colorMap, sizeof(out->colorMap));
00614 outRowStart = out->pixels;
00615 for (i=0; i<iWidth; ++i)
00616 {
00617 inCol = in->pixels + i;
00618 outRow = outRowStart;
00619 outRowStart += _mgBpr(out);
00620 j = iHeight;
00621 while (--j >= 0)
00622 {
00623 outRow[j] = *inCol;
00624 inCol += _mgBpr(in);
00625 }
00626 }
00627 return out;
00628 }
00629
00630 void mgSetHint(char *hint)
00631
00632 {
00633 return;
00634 }
00635
00636 char *mgGetHint(char *hint)
00637
00638 {
00639 return "";
00640 }
00641
00642 void vgMgMethods(struct vGfx *vg)
00643
00644 {
00645 vg->pixelBased = TRUE;
00646 vg->close = (vg_close)mgFree;
00647 vg->dot = (vg_dot)mgSlowDot;
00648 vg->getDot = (vg_getDot)mgSlowGetDot;
00649 vg->box = (vg_box)mgDrawBox;
00650 vg->line = (vg_line)mgDrawLine;
00651 vg->text = (vg_text)mgText;
00652 vg->textRight = (vg_textRight)mgTextRight;
00653 vg->textCentered = (vg_textCentered)mgTextCentered;
00654 vg->findColorIx = (vg_findColorIx)mgFindColor;
00655 vg->colorIxToRgb = (vg_colorIxToRgb)mgColorIxToRgb;
00656 vg->setClip = (vg_setClip)mgSetClip;
00657 vg->unclip = (vg_unclip)mgUnclip;
00658 vg->verticalSmear = (vg_verticalSmear)mgVerticalSmear;
00659 vg->fillUnder = (vg_fillUnder)mgFillUnder;
00660 vg->drawPoly = (vg_drawPoly)mgDrawPoly;
00661 vg->setHint = (vg_setHint)mgSetHint;
00662 vg->getHint = (vg_getHint)mgGetHint;
00663 }
00664