1476 lines
36 KiB
C
1476 lines
36 KiB
C
/*
|
||
* plotPNM.c --
|
||
*
|
||
* This file contains procedures that generate PNM format files
|
||
* to describe a section of layout.
|
||
*
|
||
* *********************************************************************
|
||
* * Copyright (C) 2000 Cornell University *
|
||
* * Permission to use, copy, modify, and distribute this *
|
||
* * software and its documentation for any purpose and without *
|
||
* * fee is hereby granted, provided that the above copyright *
|
||
* * notice appear in all copies. Cornell University *
|
||
* * makes no representations about the suitability of this *
|
||
* * software for any purpose. It is provided "as is" without *
|
||
* * express or implied warranty. Export of this software outside *
|
||
* * of the United States of America may require an export license. *
|
||
* *********************************************************************
|
||
*
|
||
* R. Timothy Edwards
|
||
* Copyright (C) 2004
|
||
* MultiGiG, Inc.
|
||
* Scotts Valley, CA
|
||
*
|
||
* Cleaned up the code, including optimization for speed
|
||
* Added: Non-Manhattan geometry handling, 24-bit color,
|
||
* plot styles automatically generated from display styles,
|
||
* downsampling for large plots, extended syntax for the
|
||
* technology file description.
|
||
*/
|
||
|
||
#ifndef lint
|
||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plot/plotPNM.c,v 1.3 2010/06/24 12:37:25 tim Exp $";
|
||
#endif /* not lint */
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <math.h>
|
||
|
||
#include "utils/magic.h"
|
||
#include "utils/geometry.h"
|
||
#include "utils/geofast.h"
|
||
#include "tiles/tile.h"
|
||
#include "utils/hash.h"
|
||
#include "database/database.h"
|
||
#include "utils/tech.h"
|
||
#include "utils/malloc.h"
|
||
#include "utils/utils.h"
|
||
#include "utils/styles.h"
|
||
#include "windows/windows.h"
|
||
#include "graphics/graphics.h"
|
||
#include "dbwind/dbwtech.h"
|
||
#include "dbwind/dbwind.h"
|
||
#include "utils/main.h"
|
||
#include "commands/commands.h"
|
||
#include "textio/textio.h"
|
||
#include "utils/signals.h"
|
||
#include "plot/plotInt.h"
|
||
|
||
#define LANCZOS_KERNEL_SIZE 1024
|
||
#define PI 3.14159265
|
||
|
||
/* Structure for saving R, G, B components of colors */
|
||
/* from a non-default colormap. */
|
||
|
||
typedef struct _pnmcolor {
|
||
unsigned char r, g, b;
|
||
} pnmcolor;
|
||
|
||
pnmcolor *PNMcolors = NULL;
|
||
static int ncolors = 0;
|
||
|
||
#define PIXELSZ sizeof(pnmcolor)
|
||
|
||
int PlotPNMmaxmem = 64 * 1024; /* 64MB */
|
||
int PlotPNMdownsample = 0; /* No downsampling by default */
|
||
unsigned char PlotPNMBG = 0xff; /* White background by default */
|
||
|
||
#ifdef VERSATEC
|
||
bool PlotPNMRTL = FALSE; /* If true, filter output through HP driver */
|
||
#endif
|
||
|
||
/*
|
||
* Local variables, modified/shared by callbacks.
|
||
*/
|
||
|
||
int Init_Error;
|
||
float lk[2 * LANCZOS_KERNEL_SIZE + 1];
|
||
int *lkstep; /* lanczos kernel steps */
|
||
pnmcolor *rtile;
|
||
int tile_xsize, tile_ysize;
|
||
int ds_xsize, ds_ysize;
|
||
Rect bb;
|
||
unsigned long BBinit;
|
||
int tile_yshift, tile_xshift;
|
||
int im_x, im_y;
|
||
int im_yoffset;
|
||
int y_pixels;
|
||
|
||
/* Structure for saving styles that are different from */
|
||
/* the styles loaded for this technology. */
|
||
|
||
typedef struct _dstyle {
|
||
char *name;
|
||
int init;
|
||
unsigned int wmask;
|
||
pnmcolor color;
|
||
} dstyle;
|
||
|
||
dstyle *Dstyles = NULL;
|
||
static int ndstyles = 0;
|
||
|
||
/* Structure which records how to paint a tile type. */
|
||
|
||
typedef struct _pstyle {
|
||
unsigned int wmask;
|
||
pnmcolor color;
|
||
} pstyle;
|
||
|
||
pstyle *PaintStyles = NULL;
|
||
|
||
/* Forward declarations */
|
||
|
||
extern void PlotLoadStyles();
|
||
extern void PlotLoadColormap();
|
||
extern pnmcolor PNMColorBlend();
|
||
extern pnmcolor PNMColorIndexAndBlend();
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* Function for output of PNM line data to HPRTL format
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
#ifdef VERSATEC
|
||
|
||
struct plotRTLdata {
|
||
FILE *outfile;
|
||
unsigned char *outbytes;
|
||
};
|
||
|
||
int
|
||
pnmRTLLineFunc(linebuffer, arg)
|
||
unsigned char *linebuffer;
|
||
struct plotRTLdata *arg;
|
||
{
|
||
int size;
|
||
|
||
size = PlotRTLCompress(linebuffer, arg->outbytes, im_x * 3);
|
||
fprintf(arg->outfile, "\033*b%dW", size);
|
||
fwrite(arg->outbytes, size, 1, arg->outfile);
|
||
return 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* Function for output of PNM line data to file fp
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
pnmLineFunc(linebuffer, fp)
|
||
unsigned char *linebuffer;
|
||
FILE *fp;
|
||
{
|
||
fwrite(linebuffer, im_x * 3, 1, fp);
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* pnmRenderRegion --
|
||
*
|
||
* Antialiased rendering.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Writes output to file.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
pnmRenderRegion(scale, scale_over_2, normal, temp, func, arg)
|
||
float scale;
|
||
int scale_over_2;
|
||
float normal; /* normalizing factor */
|
||
float *temp; /* passed so we don't have to allocate it
|
||
* on every call.
|
||
*/
|
||
int (*func)(); /* Function to call per line of output */
|
||
ClientData arg; /* Arguments to function */
|
||
{
|
||
int i, j;
|
||
int jmax;
|
||
int x, y;
|
||
int dx, dy;
|
||
int ds_over_2;
|
||
pnmcolor *color;
|
||
float r, g, b;
|
||
unsigned char *linebuffer, *lineptr;
|
||
|
||
jmax = MIN(y_pixels, im_yoffset + 1);
|
||
ds_over_2 = scale_over_2 >> PlotPNMdownsample;
|
||
|
||
linebuffer = mallocMagic(im_x * 3);
|
||
|
||
/* x, y : pixel coords */
|
||
|
||
if (ds_over_2 == 0)
|
||
{
|
||
for (j = 0; j < jmax; j++)
|
||
{
|
||
lineptr = linebuffer;
|
||
y = scale * (y_pixels - 1 - j);
|
||
y >>= PlotPNMdownsample;
|
||
for (i = 0; i < im_x; i++)
|
||
{
|
||
x = scale * i;
|
||
x >>= PlotPNMdownsample;
|
||
color = rtile + x + y * ds_xsize;
|
||
*lineptr++ = color->r;
|
||
*lineptr++ = color->g;
|
||
*lineptr++ = color->b;
|
||
}
|
||
(*func)(linebuffer, arg);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* When the scale is small enough, we have to resort to antialiasing */
|
||
|
||
float lkval;
|
||
int tidx;
|
||
|
||
for (j = 0; j < jmax; j++) {
|
||
y = scale_over_2 + scale * (y_pixels - 1 - j);
|
||
y >>= PlotPNMdownsample;
|
||
lineptr = linebuffer;
|
||
for (i = 0; i < im_x; i++) {
|
||
x = scale_over_2 + scale * i;
|
||
x >>= PlotPNMdownsample;
|
||
for (dx = -ds_over_2; dx < ds_over_2; dx++)
|
||
{
|
||
r = 0.0; g = 0.0; b = 0.0;
|
||
for (dy = -ds_over_2; dy < ds_over_2; dy++)
|
||
{
|
||
if (dy + y >= ds_ysize) continue;
|
||
/* grab rgb for (x + dx, y + dy) */
|
||
color = rtile + (x + dx) + (y + dy) * ds_xsize;
|
||
|
||
lkval = lk[lkstep[dy + ds_over_2]];
|
||
r += (float)color->r * lkval;
|
||
g += (float)color->g * lkval;
|
||
b += (float)color->b * lkval;
|
||
}
|
||
tidx = 3 * (dx + ds_over_2);
|
||
temp[tidx++] = r;
|
||
temp[tidx++] = g;
|
||
temp[tidx] = b;
|
||
}
|
||
r = 0.0; g = 0.0; b = 0.0;
|
||
for (dx = 0; dx < 2 * ds_over_2; dx++)
|
||
{
|
||
tidx = 3 * dx;
|
||
lkval = lk[lkstep[dx]];
|
||
r += temp[tidx++] * lkval;
|
||
g += temp[tidx++] * lkval;
|
||
b += temp[tidx] * lkval;
|
||
}
|
||
r /= normal;
|
||
g /= normal;
|
||
b /= normal;
|
||
*lineptr++ = (unsigned char)r;
|
||
*lineptr++ = (unsigned char)g;
|
||
*lineptr++ = (unsigned char)b;
|
||
}
|
||
(*func)(linebuffer, arg);
|
||
}
|
||
}
|
||
freeMagic(linebuffer);
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* pnmBBOX --
|
||
*
|
||
* Callback for DBTreeSrTiles; compute bounding box of plot
|
||
*
|
||
* Results:
|
||
* Always return 0 to keep search going.
|
||
*
|
||
* Side effects:
|
||
* Modifies BBinit, updates bounding box "bb"
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
pnmBBOX (tile,cxp)
|
||
Tile *tile;
|
||
TreeContext *cxp;
|
||
{
|
||
Rect targetRect, sourceRect;
|
||
SearchContext *scx = cxp->tc_scx;
|
||
Rect *arg;
|
||
TileType type;
|
||
|
||
if (!IsSplit(tile))
|
||
if ((type = TiGetType(tile)) == TT_SPACE)
|
||
return 0;
|
||
|
||
/* grab rectangle from tile */
|
||
TITORECT(tile, &targetRect);
|
||
|
||
/* coordinate transform */
|
||
GEOTRANSRECT(&scx->scx_trans, &targetRect, &sourceRect);
|
||
|
||
/* Clip */
|
||
arg = (Rect *)cxp->tc_filter->tf_arg;
|
||
GEOCLIP(&sourceRect, arg);
|
||
|
||
/* compute bbox */
|
||
if (!BBinit)
|
||
bb = sourceRect;
|
||
else
|
||
{
|
||
bb.r_xbot = MIN(bb.r_xbot, sourceRect.r_xbot);
|
||
bb.r_ybot = MIN(bb.r_ybot, sourceRect.r_ybot);
|
||
bb.r_xtop = MAX(bb.r_xtop, sourceRect.r_xtop);
|
||
bb.r_ytop = MAX(bb.r_ytop, sourceRect.r_ytop);
|
||
}
|
||
|
||
BBinit = 1;
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* pnmTile --
|
||
*
|
||
* Callback for DBTreeSrTiles; paints tiles in the current rtile buffer.
|
||
*
|
||
* Results:
|
||
* Return 0 to keep search going unless an error condition was
|
||
* encountered.
|
||
*
|
||
* Side effects:
|
||
* Modifies rtile array.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
pnmTile (tile, cxp)
|
||
Tile *tile;
|
||
TreeContext *cxp;
|
||
{
|
||
SearchContext *scx = cxp->tc_scx;
|
||
Rect targetRect, sourceRect, *clipRect;
|
||
int type, j, x, y, dx, dy;
|
||
pnmcolor *t;
|
||
pnmcolor col;
|
||
|
||
if ((type = (int)TiGetTypeExact(tile)) == TT_SPACE)
|
||
return 0;
|
||
|
||
/* undefined type; paint nothing */
|
||
if (!IsSplit(tile))
|
||
if (PaintStyles[type].wmask == 0) return 0;
|
||
|
||
/* grab rectangle from tile */
|
||
TITORECT(tile, &targetRect);
|
||
|
||
/* coordinate transform */
|
||
GEOTRANSRECT(&scx->scx_trans, &targetRect, &sourceRect);
|
||
|
||
/* Clip */
|
||
clipRect = (Rect *)cxp->tc_filter->tf_arg;
|
||
|
||
/* Handle non-Manhattan geometry */
|
||
if (IsSplit(tile))
|
||
{
|
||
TileType dinfo;
|
||
int w, h, llx, lly, urx, ury;
|
||
Rect scaledClip;
|
||
|
||
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
|
||
if (type == TT_SPACE) return 0;
|
||
else if (PaintStyles[type].wmask == 0) return 0;
|
||
|
||
llx = sourceRect.r_xbot - tile_xshift;
|
||
lly = sourceRect.r_ybot - tile_yshift;
|
||
llx >>= PlotPNMdownsample;
|
||
lly >>= PlotPNMdownsample;
|
||
dx = sourceRect.r_xtop - sourceRect.r_xbot;
|
||
dy = sourceRect.r_ytop - sourceRect.r_ybot;
|
||
dx >>= PlotPNMdownsample;
|
||
dy >>= PlotPNMdownsample;
|
||
urx = llx + dx;
|
||
ury = lly + dy;
|
||
|
||
col = PaintStyles[type].color;
|
||
scaledClip = *clipRect;
|
||
scaledClip.r_xbot -= tile_xshift;
|
||
scaledClip.r_xtop -= tile_xshift;
|
||
scaledClip.r_ybot -= tile_yshift;
|
||
scaledClip.r_ytop -= tile_yshift;
|
||
scaledClip.r_xbot >>= PlotPNMdownsample;
|
||
scaledClip.r_xtop >>= PlotPNMdownsample;
|
||
scaledClip.r_ybot >>= PlotPNMdownsample;
|
||
scaledClip.r_ytop >>= PlotPNMdownsample;
|
||
|
||
/* The following structures could be much better */
|
||
/* written for considerable speedup. . . */
|
||
|
||
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &scx->scx_trans);
|
||
if (((dinfo & TT_SIDE) >> 1) != (dinfo & TT_DIRECTION))
|
||
{
|
||
/* work top to bottom */
|
||
for (y = ury - 1; y >= lly; y--)
|
||
{
|
||
if (y >= scaledClip.r_ytop) continue;
|
||
else if (y < scaledClip.r_ybot) break;
|
||
if (dinfo & TT_SIDE) /* work right to left */
|
||
{
|
||
for (x = urx - 1; x >= llx; x--)
|
||
{
|
||
if (x >= scaledClip.r_xtop) continue;
|
||
else if (x < scaledClip.r_xbot) break;
|
||
if (((urx - x) * dy) > ((ury - y) * dx)) break;
|
||
t = rtile + x + ds_xsize * y;
|
||
*t = PNMColorBlend(t, &col);
|
||
}
|
||
}
|
||
else /* work left to right */
|
||
{
|
||
for (x = llx; x < urx; x++)
|
||
{
|
||
if (x < scaledClip.r_xbot) continue;
|
||
else if (x >= scaledClip.r_xtop) break;
|
||
if (((x - llx) * dy) > ((ury - y) * dx)) break;
|
||
t = rtile + x + ds_xsize * y;
|
||
*t = PNMColorBlend(t, &col);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else /* work bottom to top */
|
||
{
|
||
for (y = lly; y < ury; y++)
|
||
{
|
||
if (y < scaledClip.r_ybot) continue;
|
||
else if (y >= scaledClip.r_ytop) break;
|
||
if (dinfo & TT_SIDE) /* work right to left */
|
||
{
|
||
for (x = urx; x >= llx; x--)
|
||
{
|
||
if (x >= scaledClip.r_xtop) continue;
|
||
else if (x < scaledClip.r_xbot) break;
|
||
if (((urx - x) * dy) > ((y - lly) * dx)) break;
|
||
t = rtile + x + ds_xsize * y;
|
||
*t = PNMColorBlend(t, &col);
|
||
}
|
||
}
|
||
else /* work left to right */
|
||
{
|
||
for (x = llx; x < urx; x++)
|
||
{
|
||
if (x < scaledClip.r_xbot) continue;
|
||
else if (x >= scaledClip.r_xtop) break;
|
||
if (((x - llx) * dy) > ((y - lly) * dx)) break;
|
||
t = rtile + x + ds_xsize * y;
|
||
*t = PNMColorBlend(t, &col);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
GEOCLIP(&sourceRect, clipRect);
|
||
|
||
/* paint rectangle */
|
||
|
||
x = sourceRect.r_xbot - tile_xshift;
|
||
y = sourceRect.r_ybot - tile_yshift;
|
||
|
||
/* stop the search on an error condition */
|
||
/* (this should not happen---is guaranteed by GEOCLIP */
|
||
if ((x < 0) || (y < 0) || (x >= tile_xsize) || (y >= tile_ysize))
|
||
return 1;
|
||
|
||
x >>= PlotPNMdownsample;
|
||
y >>= PlotPNMdownsample;
|
||
|
||
dx = sourceRect.r_xtop - sourceRect.r_xbot;
|
||
dy = sourceRect.r_ytop - sourceRect.r_ybot;
|
||
dx >>= PlotPNMdownsample;
|
||
dy >>= PlotPNMdownsample;
|
||
|
||
col = PaintStyles[type].color;
|
||
t = rtile + x + ds_xsize * y;
|
||
|
||
for (dy; dy > 0; dy--)
|
||
{
|
||
for (j = 0; j < dx; j++)
|
||
{
|
||
*t = PNMColorBlend(t, &col);
|
||
t++;
|
||
}
|
||
t = t - dx + ds_xsize;
|
||
}
|
||
|
||
/* Continue search function */
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotPNM --
|
||
*
|
||
* This procedure generates a PNM file to describe an area of
|
||
* a layout.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotPNM(fileName, scx, layers, xMask, width)
|
||
char *fileName; /* Name of PNM file to write. */
|
||
SearchContext *scx; /* The use and area and transformation
|
||
* in this describe what to plot.
|
||
*/
|
||
TileTypeBitMask *layers; /* Tells what layers to plot. Only
|
||
* paint layers in this mask, and also
|
||
* expanded according to xMask, are
|
||
* plotted. If L_LABELS is set, then
|
||
* labels on the layers are also
|
||
* plotted, if expanded according to
|
||
* xMask. If L_CELL is set, then
|
||
* subcells that are unexpanded
|
||
* according to xMask are plotted as
|
||
* bounding boxes.
|
||
*/
|
||
int xMask; /* An expansion mask, used to indicate
|
||
* the window whose expansion status
|
||
* will be used to determine
|
||
* visibility. Zero means treat
|
||
* everything as expanded.
|
||
*/
|
||
int width; /* Indicates the width of the
|
||
* plot, in pixels.
|
||
*/
|
||
{
|
||
FILE *fp;
|
||
Rect bbox;
|
||
int bb_ysize, bb_xsize;
|
||
int i, x, y, tile_ydelta;
|
||
int save_ds, iter;
|
||
int scale_over_2, ds_over_2;
|
||
float *strip;
|
||
float scale, invscale, scaledown, normal;
|
||
|
||
#ifdef VERSATEC
|
||
struct plotRTLdata rtl_args;
|
||
char command[200], tempFile[200];
|
||
#endif
|
||
|
||
// Sanity check on PaintStyles---may be NULL if plot section
|
||
// was missing from techfile. If so, run default init/final
|
||
// procedures, flag a warning, and continue.
|
||
|
||
if (PaintStyles == NULL)
|
||
{
|
||
TxError ("Warning: No plot section in techfile, using defaults.\n");
|
||
PlotPNMTechInit();
|
||
PlotPNMTechFinal();
|
||
}
|
||
|
||
if (width <= 0)
|
||
{
|
||
TxError ("PNM module given negative pixel width; cannot plot\n");
|
||
return;
|
||
}
|
||
|
||
if (Init_Error)
|
||
{
|
||
TxError ("PNM module initialization had failed; cannot plot\n");
|
||
return;
|
||
}
|
||
|
||
/* image:
|
||
* -----
|
||
* | xxx |
|
||
* | xxx |
|
||
* | xxx |
|
||
* -----
|
||
*
|
||
* Use -scale/2 to scale/2 magic coordinates for each output pixel.
|
||
*
|
||
*/
|
||
|
||
/* Rendering Tile:
|
||
*
|
||
* 0.. bbox size + 2 * scale_over_2.
|
||
*
|
||
* To sample, pixel (i,j) will be at:
|
||
* (scale_over_2 + scale*i, scale_over_2 + scale*j)
|
||
*
|
||
* Given an initial pixel position at (i,j), we sample from
|
||
* -scale_over_2 to scale_over_2
|
||
*/
|
||
|
||
/* Compute bounding box size in lambda */
|
||
BBinit = 0;
|
||
DBTreeSrTiles(scx, layers, xMask, pnmBBOX, (ClientData)&scx->scx_area);
|
||
|
||
/* Initial bounding box size */
|
||
bb_ysize = bb.r_ytop - bb.r_ybot;
|
||
bb_xsize = bb.r_xtop - bb.r_xbot;
|
||
|
||
/* Determine value of "scale" from the total pixel width. */
|
||
scale = (float)bb_xsize / (float)width;
|
||
invscale = 1.0 / scale;
|
||
|
||
scale = 1.0 / invscale;
|
||
if ((scale > 2) || (invscale != ceil(invscale)))
|
||
scale_over_2 = (int) ceil(scale / 2.0);
|
||
else
|
||
scale_over_2 = 0;
|
||
|
||
/* bump search context by scale_over_2 pixels on each side */
|
||
scx->scx_area.r_xbot = bb.r_xbot - scale_over_2;
|
||
scx->scx_area.r_ybot = bb.r_ybot - scale_over_2;
|
||
scx->scx_area.r_xtop = bb.r_xtop + scale_over_2;
|
||
scx->scx_area.r_ytop = bb.r_ytop + scale_over_2;
|
||
|
||
/* Recalculate bounding box with extended boundary */
|
||
bb_ysize = bb.r_ytop - bb.r_ybot;
|
||
bb_xsize = bb.r_xtop - bb.r_xbot;
|
||
|
||
tile_xsize = bb_xsize + 2 * scale_over_2;
|
||
|
||
/* check for empty region */
|
||
if (BBinit == 0 || tile_xsize <= 0 || bb_ysize <= 0)
|
||
{
|
||
TxPrintf ("Empty region, no plot\n");
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* Compute memory requirements; a single pixel line needs a tile
|
||
* that has size "xsize" by "scale." To keep inter-tile overlap low,
|
||
* we insist that a single tile must have at least 3*scale pixels in
|
||
* it.
|
||
*/
|
||
|
||
save_ds = PlotPNMdownsample;
|
||
while ((PlotPNMmaxmem * 1024) <
|
||
((3 * scale + 2 * scale_over_2) * PIXELSZ * tile_xsize)
|
||
/ (1 << (PlotPNMdownsample * 2)))
|
||
PlotPNMdownsample++;
|
||
|
||
if (PlotPNMdownsample != save_ds)
|
||
{
|
||
TxPrintf ("%dX downsampling forced by memory size requirements.\n",
|
||
PlotPNMdownsample);
|
||
TxPrintf ("Current: %d KB; Required for non-downsampled image: %d KB\n",
|
||
PlotPNMmaxmem, (int) (1023 + ((3 * scale + 2 * scale_over_2)
|
||
* PIXELSZ * tile_xsize) / 1024) / (1 << (save_ds * 2)));
|
||
TxPrintf ("Use \"plot parameter pnmmaxmem\" to increase allocation.\n");
|
||
}
|
||
|
||
/*
|
||
* Compute the maximum y size for a tile.
|
||
*/
|
||
|
||
tile_ysize = PlotPNMmaxmem * 1024 / (PIXELSZ * tile_xsize);
|
||
tile_ydelta = (tile_ysize - scale_over_2 * 2);
|
||
|
||
/* Determine the amount shifted in Y for each consecutively */
|
||
/* computed region. */
|
||
/* tile_ydelta is the amount of shift in magic units. */
|
||
/* y_pixels is the amount of shift in PNM pixels. */
|
||
/* tile_ydelta MUST EQUAL y_pixels * scale. If not, then */
|
||
/* we need to back-compute a better tile_ysize value. */
|
||
|
||
y_pixels = tile_ydelta / scale;
|
||
if (y_pixels == 0) y_pixels = 1;
|
||
if (y_pixels * scale != tile_ydelta)
|
||
{
|
||
tile_ydelta = scale * y_pixels;
|
||
tile_ysize = tile_ydelta + (scale_over_2 * 2);
|
||
}
|
||
|
||
/* If there's enough memory allocation, tile_ysize bounds the whole plot */
|
||
if (tile_ysize > (bb_ysize + 2 * scale_over_2))
|
||
{
|
||
tile_ysize = bb_ysize + 2 * scale_over_2;
|
||
tile_ydelta = bb_ysize;
|
||
y_pixels = tile_ydelta / scale;
|
||
}
|
||
|
||
ds_xsize = tile_xsize >> PlotPNMdownsample;
|
||
ds_ysize = tile_ysize >> PlotPNMdownsample;
|
||
ds_over_2 = scale_over_2 >> PlotPNMdownsample;
|
||
|
||
rtile = (pnmcolor *) mallocMagic((ds_xsize * ds_ysize) * PIXELSZ);
|
||
|
||
/* bump search context by scale_over_2 pixels on each side */
|
||
scx->scx_area.r_ybot = scx->scx_area.r_ytop - tile_ysize;
|
||
tile_yshift = scx->scx_area.r_ybot;
|
||
tile_xshift = scx->scx_area.r_xbot;
|
||
|
||
im_x = (int)(bb_xsize / scale);
|
||
im_y = (int)(bb_ysize / scale);
|
||
|
||
#ifdef VERSATEC
|
||
if (PlotPNMRTL)
|
||
{
|
||
if (fileName == NULL)
|
||
{
|
||
int result;
|
||
|
||
sprintf(tempFile, "%s/magicPlotXXXXXX", PlotTempDirectory);
|
||
result = mkstemp(tempFile);
|
||
if (result == -1)
|
||
{
|
||
TxError("Failed to create temporary filename for %s\n", tempFile);
|
||
return;
|
||
}
|
||
fileName = tempFile;
|
||
}
|
||
rtl_args.outfile = PaOpen(fileName, "w", (char *)NULL, ".",
|
||
(char *)NULL, (char **)NULL);
|
||
if (rtl_args.outfile == NULL)
|
||
{
|
||
TxError("Couldn't open file \"%s\" to write plot.\n", fileName);
|
||
return;
|
||
}
|
||
|
||
switch (PlotVersPlotType)
|
||
{
|
||
case HPGL2: /* Write HPGL2 header */
|
||
/* Universal Command Language. */
|
||
fprintf(rtl_args.outfile, "\033%%-12345X");
|
||
/* Reset printer; set HPGL2 mode. */
|
||
fprintf(rtl_args.outfile, "@PJL ENTER LANGUAGE=HPGL2\r\n");
|
||
fprintf(rtl_args.outfile, "\033E\033%%0B");
|
||
/* Declare name; disable auto-rotate */
|
||
fprintf(rtl_args.outfile, "BP1,\"MAGIC\",5,1;");
|
||
/* Enter RTL mode. */
|
||
fprintf(rtl_args.outfile, "\033%%0A");
|
||
/* Source mode opaque */
|
||
fprintf(rtl_args.outfile, "\033*v1N");
|
||
/* Drop through */
|
||
|
||
case HPRTL: /* Write HPRTL header */
|
||
/* Direct pixel mode, 8 bits/component */
|
||
fwrite("\033*v6W\000\003\010\010\010\010", 11, 1, rtl_args.outfile);
|
||
/* Image width in pixels. */
|
||
fprintf(rtl_args.outfile, "\033*r%dS", im_x);
|
||
/* Image height in pixels.*/
|
||
fprintf(rtl_args.outfile, "\033*r%dT", im_y);
|
||
/* No negative motion. */
|
||
fprintf(rtl_args.outfile, "\033&a1N");
|
||
/* Mode 2 row compression */
|
||
/* But, we REALLY ought to have delta row compression here. . . */
|
||
fprintf(rtl_args.outfile, "\033*b2M");
|
||
/* Printer resolution in DPI */
|
||
fprintf(rtl_args.outfile, "\033*t%dR", PlotVersDotsPerInch);
|
||
/* Start raster data */
|
||
fprintf(rtl_args.outfile, "\033*r%cA",
|
||
(PlotVersPlotType == HPGL2) ? '1' : '0');
|
||
break;
|
||
}
|
||
|
||
/* Reserve enough space for run-length encoding compression */
|
||
rtl_args.outbytes = mallocMagic((im_x * 3) + ((im_x * 3) / 127) + 1);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
/* open PNM file */
|
||
|
||
fp = PaOpen (fileName, "w", ".pnm", ".", NULL, NULL);
|
||
if (fp == NULL)
|
||
{
|
||
TxError ("Could not open file `%s' for writing\n", fileName);
|
||
goto done;
|
||
}
|
||
|
||
fprintf (fp, "P6\n");
|
||
fprintf (fp, "%d %d\n", im_x, im_y);
|
||
fprintf (fp, "255\n");
|
||
}
|
||
|
||
im_yoffset = im_y - 1;
|
||
|
||
TxPrintf ("PNM image dimensions: %d x %d\n", im_x, im_y);
|
||
#if 0
|
||
TxPrintf ("Region size: %d x %d\n", tile_xsize, tile_ysize);
|
||
TxPrintf ("Pixels per region: %d\n", y_pixels);
|
||
TxPrintf ("Scale: %g\n", scale);
|
||
TxPrintf ("Antialiasing overlap: %d\n", scale_over_2);
|
||
if (PlotPNMdownsample > 0)
|
||
{
|
||
TxPrintf ("Downsampling: %d\n", PlotPNMdownsample);
|
||
TxPrintf ("Downsampled region size: %d x %d\n", ds_xsize, ds_ysize);
|
||
}
|
||
#endif
|
||
|
||
strip = (float *) mallocMagic((unsigned) (ds_over_2 * 2 * 3 * sizeof(float)));
|
||
lkstep = (int *) mallocMagic((unsigned) (ds_over_2 * 2 * sizeof(int)));
|
||
|
||
scaledown = scale / (2 * (1 << PlotPNMdownsample));
|
||
for (x = -ds_over_2; x < ds_over_2; x++)
|
||
{
|
||
lkstep[ds_over_2 + x] = ((float)ABS(x)) / scaledown * LANCZOS_KERNEL_SIZE;
|
||
if (lkstep[ds_over_2 + x] >= LANCZOS_KERNEL_SIZE)
|
||
lkstep[ds_over_2 + x] = LANCZOS_KERNEL_SIZE - 1;
|
||
}
|
||
|
||
/* Compute the normalization factor (what to divide by after adding up the */
|
||
/* weighted values of all pixels in the kernel area). */
|
||
|
||
normal = 0.0;
|
||
for (x = 0; x < 2 * ds_over_2; x++)
|
||
for (y = 0; y < 2 * ds_over_2; y++)
|
||
normal += lk[lkstep[x]] * lk[lkstep[y]];
|
||
|
||
iter = 0;
|
||
while (im_yoffset >= 0)
|
||
{
|
||
/* If this is a slow rendering, then we'll announce */
|
||
/* the progress every 20 steps. */
|
||
|
||
if ((++iter) % 10 == 0)
|
||
{
|
||
TxPrintf("%g%% done\n",
|
||
100 * (float)(im_y - im_yoffset + 1) / (float)im_y);
|
||
TxFlushOut();
|
||
}
|
||
|
||
/* Clear tile memory with the background gray level */
|
||
|
||
memset((void *)rtile, PlotPNMBG,
|
||
(size_t)(ds_xsize * ds_ysize * PIXELSZ));
|
||
|
||
if (SigInterruptPending)
|
||
{
|
||
TxPrintf (" *** interrupted ***\n");
|
||
goto done;
|
||
}
|
||
/* Use the "UniqueTiles" function to avoid painting contacts twice */
|
||
DBTreeSrUniqueTiles(scx, layers, xMask, pnmTile, (ClientData)&scx->scx_area);
|
||
|
||
/* anti-aliased rendering */
|
||
|
||
#ifdef VERSATEC
|
||
if (PlotPNMRTL)
|
||
pnmRenderRegion(scale, scale_over_2, normal, strip, pnmRTLLineFunc,
|
||
(ClientData)(&rtl_args));
|
||
else
|
||
#endif
|
||
pnmRenderRegion(scale, scale_over_2, normal, strip, pnmLineFunc,
|
||
(ClientData)fp);
|
||
|
||
/* advance to the next strip */
|
||
im_yoffset -= y_pixels; /* in output coords */
|
||
tile_yshift -= tile_ydelta; /* in magic coords */
|
||
scx->scx_area.r_ybot -= tile_ydelta;
|
||
scx->scx_area.r_ytop -= tile_ydelta;
|
||
}
|
||
|
||
/* TxPrintf ("Save to file `%s', scale = %f\n", fileName, scale);*/
|
||
#ifdef VERSATEC
|
||
if (PlotPNMRTL)
|
||
{
|
||
switch (PlotVersPlotType)
|
||
{
|
||
case HPRTL:
|
||
PlotHPRTLTrailer(rtl_args.outfile);
|
||
break;
|
||
case HPGL2:
|
||
PlotHPGL2Trailer(rtl_args.outfile);
|
||
break;
|
||
}
|
||
fflush(rtl_args.outfile);
|
||
fclose(rtl_args.outfile);
|
||
freeMagic(rtl_args.outbytes);
|
||
|
||
/* Run spooler */
|
||
sprintf(command, PlotVersCommand, PlotVersPrinter, fileName);
|
||
if (system(command) != 0)
|
||
{
|
||
TxError("Couldn't execute spooler command to print \"%s\"\n",
|
||
fileName);
|
||
}
|
||
}
|
||
else
|
||
#endif
|
||
fclose (fp);
|
||
|
||
done:
|
||
PlotPNMdownsample = save_ds;
|
||
freeMagic(rtile);
|
||
freeMagic(strip);
|
||
freeMagic(lkstep);
|
||
return;
|
||
}
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* lanczos_kernel --
|
||
*
|
||
* Compute the value of the lanczos kernel at the given position.
|
||
*
|
||
*
|
||
* Results:
|
||
* Returns kernel value at arg x.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
float lanczos_kernel(i, n)
|
||
int i, n;
|
||
{
|
||
double x; /* position at which to evaluate the lanczos kernel */
|
||
|
||
if (i == 0)
|
||
return (float)1.0;
|
||
else
|
||
x = (double)i / (double)n;
|
||
|
||
return (float)(sin(PI * x) / (PI * x)) * (sin(PI * 0.5 * x) / (PI * 0.5 * x));
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
* Color blending functions.
|
||
*
|
||
* PNMColorBlend blends two colors denoted by R, G, B components (0-255).
|
||
* "c_have" is the color that is already present, and "c_put" is the
|
||
* color being overlaid.
|
||
*
|
||
* PNMColorIndexAndBlend blends an R, G, B component color with a color
|
||
* indexed into a colormap table.
|
||
*
|
||
* Both functions return an R, G, B component color.
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
pnmcolor
|
||
PNMColorBlend(c_have, c_put)
|
||
pnmcolor *c_have, *c_put;
|
||
{
|
||
pnmcolor loccolor;
|
||
short r, g, b;
|
||
|
||
/* "127" is half the background color (which should be derived) */
|
||
|
||
r = (short)c_put->r - 127 + (short)c_have->r / 2;
|
||
g = (short)c_put->g - 127 + (short)c_have->g / 2;
|
||
b = (short)c_put->b - 127 + (short)c_have->b / 2;
|
||
|
||
loccolor.r = (r < 0) ? 0 : (unsigned char)r;
|
||
loccolor.g = (g < 0) ? 0 : (unsigned char)g;
|
||
loccolor.b = (b < 0) ? 0 : (unsigned char)b;
|
||
|
||
return loccolor;
|
||
}
|
||
|
||
pnmcolor
|
||
PNMColorIndexAndBlend(c_have, cidx)
|
||
pnmcolor *c_have;
|
||
int cidx;
|
||
{
|
||
pnmcolor loccolor, *c_put;
|
||
int ir, ig, ib;
|
||
short r, g, b;
|
||
|
||
if ((ncolors > 0) && (cidx < ncolors))
|
||
{
|
||
c_put = &PNMcolors[cidx];
|
||
r = (short)c_put->r;
|
||
g = (short)c_put->g;
|
||
b = (short)c_put->b;
|
||
}
|
||
else
|
||
{
|
||
GrGetColor(cidx, &ir, &ig, &ib);
|
||
r = (short)ir;
|
||
g = (short)ig;
|
||
b = (short)ib;
|
||
}
|
||
|
||
/* "127" is half the background color (which should be derived) */
|
||
|
||
r += (short)c_have->r / 2 - 127;
|
||
g += (short)c_have->g / 2 - 127;
|
||
b += (short)c_have->b / 2 - 127;
|
||
|
||
loccolor.r = (r < 0) ? 0 : (unsigned char)r;
|
||
loccolor.g = (g < 0) ? 0 : (unsigned char)g;
|
||
loccolor.b = (b < 0) ? 0 : (unsigned char)b;
|
||
|
||
return loccolor;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotPNMTechInit --
|
||
*
|
||
* Called when magic starts up.
|
||
*
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Initializes lk[...] array with the lanczos kernel.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotPNMTechInit()
|
||
{
|
||
int i;
|
||
|
||
/* Clear out any old information */
|
||
|
||
if (PaintStyles != NULL)
|
||
freeMagic(PaintStyles);
|
||
|
||
PaintStyles = (pstyle *)mallocMagic(DBNumUserLayers * sizeof(pstyle));
|
||
for (i = 0; i < DBNumUserLayers; i++)
|
||
{
|
||
PaintStyles[i].wmask = 0;
|
||
PaintStyles[i].color.r = 0xff;
|
||
PaintStyles[i].color.g = 0xff;
|
||
PaintStyles[i].color.b = 0xff;
|
||
}
|
||
|
||
Init_Error = 0;
|
||
|
||
/* Initialize Lanczos kernel */
|
||
for (i = 0; i <= 2 * LANCZOS_KERNEL_SIZE; i++)
|
||
lk[i] = lanczos_kernel(i, LANCZOS_KERNEL_SIZE);
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotPNMTechLine --
|
||
*
|
||
* Parse a magic technology file line for the pnm plot style
|
||
*
|
||
* Results:
|
||
* Return TRUE always (no errors flagged).
|
||
*
|
||
* Side effects:
|
||
* Modifies paintstyles[] array.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
/* ARGSUSED */
|
||
bool
|
||
PlotPNMTechLine(sectionName, argc, argv)
|
||
char *sectionName; /* Name of this section (unused). */
|
||
int argc; /* Number of arguments on line. */
|
||
char *argv[]; /* Pointers to fields of line. */
|
||
{
|
||
int i, j, k, style;
|
||
void PlotPNMSetDefaults(); /* Forward declaration */
|
||
|
||
if (!strncmp(argv[0], "color", 5))
|
||
PlotLoadColormap((argc == 1) ? NULL : argv[1]);
|
||
else if (!strncmp(argv[0], "dstyle", 6))
|
||
PlotLoadStyles((argc == 1) ? NULL : argv[1]);
|
||
else if (!strncmp(argv[0], "default", 7))
|
||
PlotPNMSetDefaults();
|
||
else if (!strncmp(argv[0], "draw", 4))
|
||
{
|
||
if (argc == 2)
|
||
{
|
||
/* Use the default drawing style(s) for this type. */
|
||
|
||
i = (int)DBTechNameType(argv[1]);
|
||
if (i >= 0 && i < DBNumUserLayers)
|
||
{
|
||
for (j = 0; j < DBWNumStyles; j++)
|
||
{
|
||
style = j + TECHBEGINSTYLES;
|
||
if (TTMaskHasType(DBWStyleToTypes(j), i))
|
||
{
|
||
PaintStyles[i].wmask |= GrStyleTable[style].mask;
|
||
PaintStyles[i].color =
|
||
PNMColorIndexAndBlend(&PaintStyles[i].color,
|
||
GrStyleTable[style].color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (argc == 3)
|
||
{
|
||
pstyle savestyle;
|
||
bool newcolor = FALSE;
|
||
|
||
/* Use the specified drawing style(s) instead of the */
|
||
/* display drawing styles (used to override crosses */
|
||
/* on contacts and such). */
|
||
|
||
k = (int)DBTechNameType(argv[1]);
|
||
if (k >= 0 && k < DBNumUserLayers)
|
||
{
|
||
savestyle = PaintStyles[k];
|
||
PaintStyles[k].wmask = 0;
|
||
PaintStyles[k].color.r = 255;
|
||
PaintStyles[k].color.g = 255;
|
||
PaintStyles[k].color.b = 255;
|
||
|
||
for (j = 2; j < argc; j++)
|
||
{
|
||
/* Use the specified display style, or the internal one */
|
||
if (ndstyles > 0)
|
||
{
|
||
for (i = 0; i < ndstyles; i++)
|
||
{
|
||
if (!strcmp(Dstyles[i].name, argv[j]))
|
||
{
|
||
PaintStyles[k].wmask |= Dstyles[i].wmask;
|
||
PaintStyles[k].color =
|
||
PNMColorBlend(&PaintStyles[k].color,
|
||
&Dstyles[i].color);
|
||
newcolor = TRUE;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
i = (int)GrGetStyleFromName(argv[j]);
|
||
if (i >= 0)
|
||
{
|
||
PaintStyles[k].wmask |= GrStyleTable[i].mask;
|
||
PaintStyles[k].color =
|
||
PNMColorIndexAndBlend(&PaintStyles[k].color,
|
||
GrStyleTable[i].color);
|
||
newcolor = TRUE;
|
||
}
|
||
else
|
||
TxError("Unknown drawing style \"%s\" for PNM plot.\n",
|
||
argv[j]);
|
||
}
|
||
|
||
/* In case of error, revert to the default style */
|
||
|
||
if (newcolor == FALSE)
|
||
PaintStyles[k] = savestyle;
|
||
}
|
||
}
|
||
else
|
||
TxError("Unknown magic layer \"%s\" for PNM plot.\n", argv[1]);
|
||
}
|
||
}
|
||
else if (!strncmp(argv[0], "map", 3))
|
||
{
|
||
k = (int)DBTechNameType(argv[1]);
|
||
if (k >= 0 && k < DBNumUserLayers)
|
||
{
|
||
for (j = 2; j < argc; j++)
|
||
{
|
||
i = (int)DBTechNameType(argv[j]);
|
||
if (i >= 0)
|
||
{
|
||
PaintStyles[k].wmask |= PaintStyles[i].wmask;
|
||
PaintStyles[k].color = PNMColorBlend(&PaintStyles[k].color,
|
||
&PaintStyles[i].color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotPNMSetDefaults --
|
||
*
|
||
* Generate default colors for the PNM plot style from existing
|
||
* graphics colors for the window.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotPNMSetDefaults()
|
||
{
|
||
int i, j, style;
|
||
|
||
for (i = TT_SPACE + 1; i < DBNumUserLayers; i++)
|
||
{
|
||
for (j = 0; j < DBWNumStyles; j++)
|
||
{
|
||
style = j + TECHBEGINSTYLES;
|
||
if (TTMaskHasType(DBWStyleToTypes(j), i))
|
||
{
|
||
PaintStyles[i].wmask |= GrStyleTable[style].mask;
|
||
PaintStyles[i].color =
|
||
PNMColorIndexAndBlend(&PaintStyles[i].color,
|
||
GrStyleTable[style].color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotPNMTechFinal --
|
||
*
|
||
* Routine to be run at the end of reading the "plot pnm" techfile
|
||
* section.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* The "Dstyles" array is no longer needed and is free'd.
|
||
* The "PNMTypeTable" is malloc'd and entries filled.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotPNMTechFinal()
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < ndstyles; i++)
|
||
freeMagic(Dstyles[i].name);
|
||
|
||
if (Dstyles != NULL)
|
||
{
|
||
freeMagic(Dstyles);
|
||
Dstyles = NULL;
|
||
ndstyles = 0;
|
||
}
|
||
|
||
if (PNMcolors != NULL)
|
||
{
|
||
freeMagic(PNMcolors);
|
||
PNMcolors = NULL;
|
||
ncolors = 0;
|
||
}
|
||
|
||
/* If no "draw" or "map" lines were declared in the technology */
|
||
/* file, then we put together a default style where we use the */
|
||
/* display dstyles for each layer. We detect the condition as */
|
||
/* having all wmask values 0 in the PaintStyles array. */
|
||
|
||
for (i = TT_SPACE + 1; i < DBNumUserLayers; i++)
|
||
if (PaintStyles[i].wmask != 0)
|
||
break;
|
||
|
||
if (i < DBNumUserLayers)
|
||
return;
|
||
|
||
PlotPNMSetDefaults();
|
||
}
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotLoadStyles --
|
||
*
|
||
* Read in the plotting styles for rendering.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Initializes arrays for drawing/plotting.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotLoadStyles(filename)
|
||
char *filename;
|
||
{
|
||
FILE *inp;
|
||
char fullName[256];
|
||
char *buf;
|
||
int newsec;
|
||
int ord, mask, color, outline, nfill, stipple;
|
||
int ir, ig, ib;
|
||
char shortname;
|
||
char longname[128];
|
||
char fill[42];
|
||
|
||
if (filename == NULL)
|
||
{
|
||
(void) sprintf(fullName, "%.100s.7bit.mraster_dstyle", DBWStyleType);
|
||
buf = fullName;
|
||
}
|
||
else
|
||
{
|
||
buf = filename;
|
||
}
|
||
inp = PaOpen(buf, "r", (char *)NULL, ".", SysLibPath, (char **) NULL);
|
||
if (inp == NULL)
|
||
{
|
||
TxError ("PNM plot: Could not open display style file\n");
|
||
Init_Error = 1;
|
||
return;
|
||
}
|
||
|
||
buf = fullName; /* reuse this space for input */
|
||
|
||
ndstyles = 0;
|
||
Dstyles = (dstyle *)mallocMagic(DBWNumStyles * sizeof(dstyle));
|
||
|
||
/* Read in the dstyle file */
|
||
newsec = FALSE;
|
||
while (fgets (buf, 256, inp))
|
||
{
|
||
if (buf[0] == '#') continue;
|
||
if (StrIsWhite (buf, FALSE))
|
||
{
|
||
newsec = TRUE;
|
||
continue;
|
||
}
|
||
else if (newsec)
|
||
{
|
||
if (strncmp (buf, "display_styles", 14) != 0)
|
||
goto dstyle_err;
|
||
newsec = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (sscanf (buf, "%d %d %d %d %40s %d %c %126s",
|
||
&ord, &mask, &color, &outline, fill, &stipple,
|
||
&shortname, longname) != 8)
|
||
goto dstyle_err;
|
||
if (ndstyles == DBWNumStyles)
|
||
goto dstyle_err;
|
||
Dstyles[ndstyles].wmask = mask;
|
||
if ((ncolors > 0) && (color >=0) && (color < ncolors))
|
||
{
|
||
Dstyles[ndstyles].color = PNMcolors[color];
|
||
}
|
||
else
|
||
{
|
||
GrGetColor(color, &ir, &ig, &ib);
|
||
Dstyles[ndstyles].color.r = (unsigned char)ir;
|
||
Dstyles[ndstyles].color.g = (unsigned char)ig;
|
||
Dstyles[ndstyles].color.b = (unsigned char)ib;
|
||
}
|
||
Dstyles[ndstyles].name = StrDup(NULL, longname);
|
||
ndstyles++;
|
||
if (ndstyles == DBWNumStyles) break;
|
||
}
|
||
}
|
||
fclose (inp);
|
||
return;
|
||
|
||
dstyle_err:
|
||
Init_Error = 1;
|
||
TxError ("Format error in display style file\n");
|
||
fclose (inp);
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotLoadColormap --
|
||
*
|
||
* Read in the colormap for rendering.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Initializes arrays for drawing/plotting.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotLoadColormap(filename)
|
||
char *filename;
|
||
{
|
||
FILE *inp;
|
||
char fullName[256];
|
||
char *buf;
|
||
int red, blue, green;
|
||
|
||
/* read in color map */
|
||
if (filename == NULL)
|
||
{
|
||
(void) sprintf(fullName, "%.100s.7bit.mraster.cmap", DBWStyleType);
|
||
buf = fullName;
|
||
}
|
||
else
|
||
buf = filename;
|
||
|
||
inp = PaOpen(buf, "r", (char *) NULL, ".", SysLibPath, (char **) NULL);
|
||
if (inp == NULL)
|
||
{
|
||
TxError("Couldn't open colormap file \"%s\"\n", buf);
|
||
Init_Error = 1;
|
||
return;
|
||
}
|
||
buf = fullName; /* reuse this space for input */
|
||
|
||
ncolors = 0;
|
||
PNMcolors = (pnmcolor *)mallocMagic(128 * PIXELSZ);
|
||
|
||
while (fgets (buf, 256, inp)) {
|
||
if (buf[0] == '#') continue;
|
||
if (StrIsWhite (buf, FALSE))
|
||
continue;
|
||
if (ncolors == 128) {
|
||
goto color_err;
|
||
}
|
||
if (sscanf (buf, "%d %d %d", &red, &green, &blue) != 3) {
|
||
goto color_err;
|
||
}
|
||
PNMcolors[ncolors].r = (unsigned char)red;
|
||
PNMcolors[ncolors].g = (unsigned char)green;
|
||
PNMcolors[ncolors].b = (unsigned char)blue;
|
||
ncolors++;
|
||
}
|
||
fclose(inp);
|
||
return;
|
||
|
||
color_err:
|
||
Init_Error = 1;
|
||
TxError ("Format error in colormap file\n");
|
||
fclose (inp);
|
||
}
|