00001
00002
00003
00004
00005
00006
00007 #include "common.h"
00008 #include "hash.h"
00009 #include "memgfx.h"
00010 #include "gfxPoly.h"
00011 #include "colHash.h"
00012 #include "psGfx.h"
00013 #include "pscmGfx.h"
00014 #include "gemfont.h"
00015 #include "vGfx.h"
00016 #include "vGfxPrivate.h"
00017
00018 static char const rcsid[] = "$Id: pscmGfx.c,v 1.20 2007/04/15 00:43:41 galt Exp $";
00019
00020
00021 static struct pscmGfx *boxPscm;
00022
00023
00024
00025
00026 void pscmSetHint(struct pscmGfx *pscm, char *hint, char *value)
00027
00028 {
00029 if (!value) return;
00030 if (sameString(value,""))
00031 {
00032 hashRemove(pscm->hints, hint);
00033 }
00034 struct hashEl *el = hashLookup(pscm->hints, hint);
00035 if (el)
00036 {
00037 freeMem(el->val);
00038 el->val = cloneString(value);
00039 }
00040 else
00041 {
00042 hashAdd(pscm->hints, hint, cloneString(value));
00043 }
00044 }
00045
00046 char *pscmGetHint(struct pscmGfx *pscm, char *hint)
00047
00048 {
00049 return hashOptionalVal(pscm->hints, hint, "");
00050 }
00051 void pscmSetClip(struct pscmGfx *pscm, int x, int y, int width, int height)
00052
00053 {
00054 double x2 = x + width;
00055 double y2 = y + height;
00056 pscm->clipMinX = x;
00057 pscm->clipMinY = y;
00058 pscm->clipMaxX = x2;
00059 pscm->clipMaxY = y2;
00060
00061 x2 -= 1;
00062 y2 -= 1;
00063 double x1 = x;
00064 double y1 = y;
00065
00066 x1 -= 0.5;
00067 y1 -= 0.5;
00068 x2 += 0.5;
00069 y2 += 0.5;
00070 psClipRect(pscm->ps, x1, y1, x2-x1, y2-y1);
00071 }
00072
00073 void pscmUnclip(struct pscmGfx *pscm)
00074
00075 {
00076 psClipRect(pscm->ps, 0, 0, pscm->ps->userWidth, pscm->ps->userHeight);
00077 }
00078
00079 static Color pscmClosestColor(struct pscmGfx *pscm,
00080 unsigned char r, unsigned char g, unsigned char b)
00081
00082 {
00083 struct rgbColor *c = pscm->colorMap;
00084 int closestDist = 0x7fffffff;
00085 int closestIx = -1;
00086 int dist, dif;
00087 int i;
00088
00089 for (i=0; i<pscm->colorsUsed; ++i)
00090 {
00091 dif = c->r - r;
00092 dist = dif*dif;
00093 dif = c->g - g;
00094 dist += dif*dif;
00095 dif = c->b - b;
00096 dist += dif*dif;
00097 if (dist < closestDist)
00098 {
00099 closestDist = dist;
00100 closestIx = i;
00101 }
00102 ++c;
00103 }
00104 return closestIx;
00105 }
00106
00107 static Color pscmAddColor(struct pscmGfx *pscm,
00108 unsigned char r, unsigned char g, unsigned char b)
00109
00110 {
00111 int colIx = pscm->colorsUsed;
00112 struct rgbColor *c = pscm->colorMap + pscm->colorsUsed;
00113 c->r = r;
00114 c->g = g;
00115 c->b = b;
00116 pscm->colorsUsed += 1;
00117 colHashAdd(pscm->colorHash, r, g, b, colIx);;
00118 return (Color)colIx;
00119 }
00120
00121 int pscmFindColorIx(struct pscmGfx *pscm, int r, int g, int b)
00122
00123
00124
00125 {
00126 struct colHashEl *che;
00127 if (r>255||g>255||b>255)
00128 errAbort("RGB values out of range (0-255). r:%d g:%d b:%d", r, g, b);
00129 if ((che = colHashLookup(pscm->colorHash, r, g, b)) != NULL)
00130 return che->ix;
00131 if (pscm->colorsUsed < 256)
00132 return pscmAddColor(pscm, r, g, b);
00133 return pscmClosestColor(pscm, r, g, b);
00134 }
00135
00136
00137 struct rgbColor pscmColorIxToRgb(struct pscmGfx *pscm, int colorIx)
00138
00139 {
00140 return pscm->colorMap[colorIx];
00141 }
00142
00143 static void pscmSetDefaultColorMap(struct pscmGfx *pscm)
00144
00145 {
00146
00147 int i;
00148 for (i=0; i<ArraySize(mgFixedColors); ++i)
00149 {
00150 struct rgbColor *c = &mgFixedColors[i];
00151 pscmFindColorIx(pscm, c->r, c->g, c->b);
00152 }
00153 }
00154
00155 struct pscmGfx *pscmOpen(int width, int height, char *file)
00156
00157 {
00158 struct pscmGfx *pscm;
00159
00160 AllocVar(pscm);
00161 pscm->ps = psOpen(file, width, height, 72.0 * 7.5, 0, 0);
00162 psTranslate(pscm->ps,0.5,0.5);
00163 pscm->colorHash = colHashNew();
00164 pscmSetDefaultColorMap(pscm);
00165 pscm->clipMinX = pscm->clipMinY = 0;
00166 pscm->clipMaxX = width;
00167 pscm->clipMaxY = height;
00168 pscm->hints = hashNew(6);
00169 return pscm;
00170 }
00171
00172 void pscmClose(struct pscmGfx **pPscm)
00173
00174 {
00175 struct pscmGfx *pscm = *pPscm;
00176 if (pscm != NULL)
00177 {
00178 psClose(&pscm->ps);
00179 colHashFree(&pscm->colorHash);
00180 freez(pPscm);
00181 }
00182 }
00183
00184 void pscmSetColor(struct pscmGfx *pscm, int colorIx)
00185
00186 {
00187 struct rgbColor *col = pscm->colorMap + colorIx;
00188 if (colorIx != pscm->curColor)
00189 {
00190 psSetColor(pscm->ps, col->r, col->g, col->b);
00191 pscm->curColor = colorIx;
00192 }
00193 }
00194
00195 void pscmBoxToPs(struct pscmGfx *pscm, int x, int y,
00196 int width, int height)
00197
00198 {
00199
00200
00201 double x2 = x + width;
00202 double y2 = y + height;
00203
00204 if (x < pscm->clipMinX) x = pscm->clipMinX;
00205 if (y < pscm->clipMinY) y = pscm->clipMinY;
00206 if (x2 > pscm->clipMaxX) x2 = pscm->clipMaxX;
00207 if (y2 > pscm->clipMaxY) y2 = pscm->clipMaxY;
00208
00209
00210 x2 -= 1;
00211 y2 -= 1;
00212 double x1 = x;
00213 double y1 = y;
00214
00215 x1 -= 0.5;
00216 y1 -= 0.5;
00217 x2 += 0.5;
00218 y2 += 0.5;
00219 psDrawBox(pscm->ps, x1, y1, x2-x1, y2-y1);
00220 }
00221
00222 void pscmBox(struct pscmGfx *pscm, int x, int y,
00223 int width, int height, int color)
00224
00225 {
00226
00227
00228
00229
00230
00231 static int lx, ly, lw, lh, lc=-1;
00232 if (x != lx || y != ly || width != lw || height != lh || color != lc ||
00233 pscm != boxPscm)
00234 {
00235 pscmSetColor(pscm, color);
00236 pscmBoxToPs(pscm, x, y, width, height);
00237 lx = x;
00238 ly = y;
00239 lw = width;
00240 lh = height;
00241 lc = color;
00242 boxPscm = pscm;
00243 }
00244 }
00245
00246 void pscmDot(struct pscmGfx *pscm, int x, int y, int color)
00247
00248 {
00249 pscmSetColor(pscm, color);
00250 psDrawBox(pscm->ps, x, y, 1, 1);
00251 }
00252
00253 void pscmLine(struct pscmGfx *pscm,
00254 int x1, int y1, int x2, int y2, int color)
00255
00256 {
00257 pscmSetColor(pscm, color);
00258 if ((x1==x2) || (y1 == y2))
00259 {
00260
00261 psDrawBox(pscm->ps, x1-0.5, y1-0.5, x2-x1+1, y2-y1+1);
00262 }
00263 else
00264 {
00265 psDrawLine(pscm->ps, x1, y1, x2, y2);
00266 }
00267 boxPscm = NULL;
00268 }
00269
00270 static void pscmVerticalSmear(struct pscmGfx *pscm,
00271 int xOff, int yOff, int width, int height,
00272 unsigned char *dots, boolean zeroClear)
00273
00274 {
00275 int x, i;
00276 struct psGfx *ps = pscm->ps;
00277 Color c;
00278 for (i=0; i<width; ++i)
00279 {
00280 x = xOff + i;
00281 c = dots[i];
00282 if (c != 0 || !zeroClear)
00283 {
00284 pscmSetColor(pscm, c);
00285 psDrawBox(ps, x, yOff, 1, height);
00286 }
00287 }
00288 }
00289
00290 static void pscmSetFont(struct pscmGfx *pscm, MgFont *font)
00291
00292 {
00293
00294
00295
00296
00297 void *v = font;
00298 if (v != pscm->curFont)
00299 {
00300 psTimesFont(pscm->ps, font->frm_hgt);
00301 pscm->curFont = v;
00302 }
00303 }
00304
00305 void pscmText(struct pscmGfx *pscm, int x, int y, int color,
00306 MgFont *font, char *text)
00307
00308 {
00309 pscmSetColor(pscm, color);
00310 pscmSetFont(pscm, font);
00311 psTextAt(pscm->ps, x, y, text);
00312 boxPscm = NULL;
00313 }
00314
00315 void pscmTextRight(struct pscmGfx *pscm, int x, int y, int width, int height,
00316 int color, MgFont *font, char *text)
00317
00318 {
00319 pscmSetColor(pscm, color);
00320 pscmSetFont(pscm, font);
00321 psTextRight(pscm->ps, x, y, width, height, text);
00322 boxPscm = NULL;
00323 }
00324
00325 void pscmTextCentered(struct pscmGfx *pscm, int x, int y,
00326 int width, int height, int color, MgFont *font, char *text)
00327
00328 {
00329 pscmSetColor(pscm, color);
00330 pscmSetFont(pscm, font);
00331 psTextCentered(pscm->ps, x, y, width, height, text);
00332 boxPscm = NULL;
00333 }
00334
00335 void pscmFillUnder(struct pscmGfx *pscm, int x1, int y1, int x2, int y2,
00336 int bottom, Color color)
00337
00338
00339
00340
00341 {
00342 pscmSetColor(pscm, color);
00343 psFillUnder(pscm->ps, x1, y1, x2, y2, bottom);
00344 boxPscm = NULL;
00345 }
00346
00347 void pscmDrawPoly(struct pscmGfx *pscm, struct gfxPoly *poly, Color color,
00348 boolean filled)
00349
00350 {
00351 struct gfxPoint *p = poly->ptList;
00352 struct psPoly *psPoly = psPolyNew();
00353 if (poly->ptCount < 1)
00354 {
00355 return;
00356 }
00357 if (poly->ptCount == 1)
00358 {
00359 struct gfxPoint *p = poly->ptList;
00360 pscmBox(pscm, p->x, p->y, 1, 1, color);
00361 return;
00362 }
00363 if (poly->ptCount == 2)
00364 {
00365 struct gfxPoint *p1 = poly->ptList;
00366 struct gfxPoint *p2 = p1->next;
00367 pscmLine(pscm, p1->x, p1->y, p2->x, p2->y, color);
00368 }
00369 pscmSetColor(pscm, color);
00370
00371 for (;;)
00372 {
00373 psPolyAddPoint(psPoly,p->x, p->y);
00374 p = p->next;
00375 if (p == poly->ptList)
00376 break;
00377 }
00378 psDrawPoly(pscm->ps, psPoly, filled);
00379
00380 psPolyFree(&psPoly);
00381 }
00382
00383
00384 struct vGfx *vgOpenPostScript(int width, int height, char *fileName)
00385
00386 {
00387 struct vGfx *vg = vgHalfInit(width, height);
00388 vg->data = pscmOpen(width, height, fileName);
00389 vg->close = (vg_close)pscmClose;
00390 vg->dot = (vg_dot)pscmDot;
00391 vg->box = (vg_box)pscmBox;
00392 vg->line = (vg_line)pscmLine;
00393 vg->text = (vg_text)pscmText;
00394 vg->textRight = (vg_textRight)pscmTextRight;
00395 vg->textCentered = (vg_textCentered)pscmTextCentered;
00396 vg->findColorIx = (vg_findColorIx)pscmFindColorIx;
00397 vg->colorIxToRgb = (vg_colorIxToRgb)pscmColorIxToRgb;
00398 vg->setClip = (vg_setClip)pscmSetClip;
00399 vg->unclip = (vg_unclip)pscmUnclip;
00400 vg->verticalSmear = (vg_verticalSmear)pscmVerticalSmear;
00401 vg->fillUnder = (vg_fillUnder)pscmFillUnder;
00402 vg->drawPoly = (vg_drawPoly)pscmDrawPoly;
00403 vg->setHint = (vg_setHint)pscmSetHint;
00404 vg->getHint = (vg_getHint)pscmGetHint;
00405 return vg;
00406 }
00407