1505 lines
36 KiB
C
1505 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>
|
|
|
|
/* C99 compat */
|
|
#include <stdlib.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 > 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 = NULL;
|
|
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 = NULL;
|
|
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;
|
|
}
|
|
else if (strchr(fileName, '.') == NULL)
|
|
{
|
|
/* Add extention ".pnm" if the filename does not have an extension */
|
|
sprintf(tempFile, "%s.pnm", fileName);
|
|
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",
|
|
(strchr(fileName, '.') == NULL) ? ".pnm" : NULL,
|
|
".", 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);
|
|
rtl_args.outfile = NULL;
|
|
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
|
|
{
|
|
if(fp)
|
|
{
|
|
fclose (fp);
|
|
fp = NULL;
|
|
}
|
|
}
|
|
|
|
done:
|
|
PlotPNMdownsample = save_ds;
|
|
freeMagic(rtile);
|
|
rtile = NULL;
|
|
freeMagic(strip);
|
|
freeMagic(lkstep);
|
|
lkstep = NULL;
|
|
#ifdef VERSATEC
|
|
if(rtl_args.outfile) /* theoretical fp leak */
|
|
{
|
|
fclose(rtl_args.outfile);
|
|
rtl_args.outfile = NULL;
|
|
}
|
|
#endif
|
|
if(fp)
|
|
fclose(fp);
|
|
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);
|
|
}
|