1143 lines
30 KiB
C
1143 lines
30 KiB
C
/*
|
||
* plotRastUtils.c --
|
||
*
|
||
* This file contains several procedures for manipulating rasters.
|
||
* The procedures are used to create bitmaps to directly drive
|
||
* printers such as the black-and-white Versatec. For example,
|
||
* the procedures draw stippled areas and raster-ize text strings
|
||
* using fonts.
|
||
*
|
||
* *********************************************************************
|
||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||
* * 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. The University of California *
|
||
* * 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. *
|
||
* *********************************************************************
|
||
*/
|
||
|
||
#ifndef lint
|
||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plot/plotRutils.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
||
#endif /* not lint */
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <errno.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/malloc.h"
|
||
#include "plot/plotInt.h"
|
||
#include "textio/textio.h"
|
||
#include "utils/utils.h"
|
||
|
||
extern double sqrt();
|
||
|
||
int rasFileByteCount = 0;
|
||
/* A solid black stipple: */
|
||
|
||
Stipple PlotBlackStipple =
|
||
{
|
||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||
};
|
||
|
||
/* The following two arrays are used to select a range of bits within
|
||
* a word. The first array selects all the bits at or to the left of
|
||
* the given bit-position. "To the left" means in a lower-numbered
|
||
* byte (according to byte order) or in a more significant bit of the
|
||
* same byte. The second array selects the bits at or to the right of
|
||
* the given bit-position. Bit position 0 is considered to be the
|
||
* leftmost bit of the word; it's the highest-order bit in the 0th
|
||
* byte.
|
||
*/
|
||
|
||
static unsigned int leftBits[32] =
|
||
{
|
||
0x00000080, 0x000000c0, 0x000000e0, 0x000000f0,
|
||
0x000000f8, 0x000000fc, 0x000000fe, 0x000000ff,
|
||
0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff,
|
||
0x0000f8ff, 0x0000fcff, 0x0000feff, 0x0000ffff,
|
||
0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff,
|
||
0x00f8ffff, 0x00fcffff, 0x00feffff, 0x00ffffff,
|
||
0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff,
|
||
0xf8ffffff, 0xfcffffff, 0xfeffffff, 0xffffffff
|
||
};
|
||
static unsigned int rightBits[32] =
|
||
{
|
||
0xffffffff, 0xffffff7f, 0xffffff3f, 0xffffff1f,
|
||
0xffffff0f, 0xffffff07, 0xffffff03, 0xffffff01,
|
||
0xffffff00, 0xffff7f00, 0xffff3f00, 0xffff1f00,
|
||
0xffff0f00, 0xffff0700, 0xffff0300, 0xffff0100,
|
||
0xffff0000, 0xff7f0000, 0xff3f0000, 0xff1f0000,
|
||
0xff0f0000, 0xff070000, 0xff030000, 0xff010000,
|
||
0xff000000, 0x7f000000, 0x3f000000, 0x1f000000,
|
||
0x0f000000, 0x07000000, 0x03000000, 0x01000000
|
||
};
|
||
|
||
/* The following arrray selects a single bit within a word. The
|
||
* zeroth entry selects the bit that will be leftmost in the plot.
|
||
*/
|
||
static unsigned int singleBit[32] =
|
||
{
|
||
0x00000080, 0x00000040, 0x00000020, 0x00000010,
|
||
0x00000008, 0x00000004, 0x00000002, 0x00000001,
|
||
0x00008000, 0x00004000, 0x00002000, 0x00001000,
|
||
0x00000800, 0x00000400, 0x00000200, 0x00000100,
|
||
0x00800000, 0x00400000, 0x00200000, 0x00100000,
|
||
0x00080000, 0x00040000, 0x00020000, 0x00010000,
|
||
0x80000000, 0x40000000, 0x20000000, 0x10000000,
|
||
0x08000000, 0x04000000, 0x02000000, 0x01000000
|
||
};
|
||
|
||
RasterFont *PlotFontList; /* Linked list of all fonts that have
|
||
* been read in so far.
|
||
*/
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotRastInit --
|
||
*
|
||
* Initialize data structures related to rasters.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* All this procedure does is to swap bytes in the stipple
|
||
* masks if we're running on a non-VAX.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotRastInit()
|
||
{
|
||
#ifdef WORDS_BIGENDIAN
|
||
int i;
|
||
|
||
for (i = 0; i < 32; i++)
|
||
{
|
||
leftBits[i] = PlotSwapBytes(leftBits[i]);
|
||
rightBits[i] = PlotSwapBytes(rightBits[i]);
|
||
singleBit[i] = PlotSwapBytes(singleBit[i]);
|
||
}
|
||
#endif /* WORDS_BIGENDIAN */
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotNewRaster --
|
||
*
|
||
* Allocate and initialize a new raster structure.
|
||
*
|
||
* Results:
|
||
* The return value is a pointer to the new raster object.
|
||
*
|
||
* Side effects:
|
||
* Memory is allocated.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
Raster *
|
||
PlotNewRaster(height, width)
|
||
int height; /* Raster's height in pixels. Should generally
|
||
* be a multiple of 16.
|
||
*/
|
||
int width; /* Raster's width in pixels. Should generally
|
||
* be a multiple of 32 bits.
|
||
*/
|
||
{
|
||
Raster *new;
|
||
|
||
new = (Raster *) mallocMagic(sizeof(Raster));
|
||
new->ras_width = width;
|
||
new->ras_intsPerLine = (width+31)/32;
|
||
new->ras_bytesPerLine = new->ras_intsPerLine*4;
|
||
new->ras_height = height;
|
||
new->ras_bits = (int *) mallocMagic(
|
||
(unsigned) (height * new->ras_intsPerLine * 4));
|
||
|
||
return new;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotFreeRaster --
|
||
*
|
||
* Frees up the memory associated with an existing raster structure.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* The storage associated with raster is returned to the allocator.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotFreeRaster(raster)
|
||
Raster *raster; /* Raster whose memory is to be freed. Should
|
||
* have been created with PlotNewRaster.
|
||
*/
|
||
{
|
||
if (raster == NULL) return;
|
||
freeMagic((char *) raster->ras_bits);
|
||
freeMagic((char *) raster);
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotClearRaster --
|
||
*
|
||
* This procedure clears out an area of the raster.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* The area of the raster indicated by "area" is set to all zeroes.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotClearRaster(raster, area)
|
||
Raster *raster; /* Raster that's to be cleared. */
|
||
Rect *area; /* Area to be cleared, in raster
|
||
* coords. NULL means clear the
|
||
* whole raster.
|
||
*/
|
||
{
|
||
int *left, *right, *cur;
|
||
int leftMask, rightMask, line;
|
||
|
||
if (area == NULL)
|
||
{
|
||
bzero((char *) raster->ras_bits,
|
||
raster->ras_bytesPerLine * raster->ras_height);
|
||
return;
|
||
}
|
||
|
||
/* Compute the address of the leftmost word in the topmost line
|
||
* to be cleared, and the rightmost word in the topmost line to
|
||
* be cleared.
|
||
*/
|
||
|
||
left = raster->ras_bits +
|
||
((raster->ras_height-1) - area->r_ytop)*raster->ras_intsPerLine;
|
||
right = left + area->r_xtop/32;
|
||
left += area->r_xbot/32;
|
||
|
||
/* Divide the x-span of the area into three parts: the leftmost
|
||
* word, of which only the rightmost bits are cleared, the
|
||
* rightmost word, of which only the leftmost bits are cleared,
|
||
* and the middle section, in which all bits of each word are
|
||
* cleared. Compute masks that determine which bits of the end
|
||
* words will be cleared. There's a special case when the left
|
||
* and right ends are in the same word.
|
||
*/
|
||
|
||
leftMask = rightBits[area->r_xbot&037];
|
||
rightMask = leftBits[area->r_xtop&037];
|
||
if (left == right)
|
||
leftMask &= rightMask;
|
||
|
||
/* Clear the area one raster line at a time, top to bottom. */
|
||
|
||
for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
|
||
{
|
||
/* Clear the leftmost word on this line. */
|
||
|
||
*left &= ~leftMask;
|
||
|
||
if (left != right)
|
||
{
|
||
/* Clear the center of the line. */
|
||
|
||
for (cur = left+1; cur < right; cur += 1)
|
||
*cur = 0;
|
||
|
||
/* Clear the rightmost word on this line. */
|
||
|
||
*cur &= ~rightMask;
|
||
}
|
||
|
||
left += raster->ras_intsPerLine;
|
||
right += raster->ras_intsPerLine;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotPolyRaster --
|
||
*
|
||
* Fill a polygonal raster area, given the area of a triangular
|
||
* tile (in pixel coordinates), information about what side and
|
||
* direction are filled, and the area to clip to (also in raster
|
||
* coordinates). This is *not* a general-purpose polygon-filling
|
||
* routine. It can only handle clipped right triangles.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotPolyRaster(raster, tileArea, clipArea, dinfo, stipple)
|
||
Raster *raster; /* Pointer to raster whose bits are
|
||
* to be filled in.
|
||
*/
|
||
Rect *tileArea; /* Area of split tile, in pixel coordinates */
|
||
Rect *clipArea; /* Area to clip, in pixel coordinates */
|
||
TileType dinfo; /* Split tile side and direction information */
|
||
Stipple stipple; /* Stipple pattern to be used to fill
|
||
* in the raster area.
|
||
*/
|
||
{
|
||
int *cur, *rasleft, *tbase, *right, *left;
|
||
int leftMask, rightMask, curStipple;
|
||
int line, width, height, locleft, locright;
|
||
Rect area;
|
||
|
||
/* Compute the address of the leftmost word in the topmost line
|
||
* to be filled, and the rightmost word in the topmost line to
|
||
* be filled.
|
||
*/
|
||
|
||
area = *tileArea;
|
||
GEOCLIP(&area, clipArea);
|
||
|
||
/* Ensure that we have not been clipped out of existence */
|
||
if (area.r_xbot > area.r_xtop) return;
|
||
if (area.r_ybot >= area.r_ytop) return;
|
||
|
||
rasleft = raster->ras_bits +
|
||
((raster->ras_height-1) - area.r_ytop)*raster->ras_intsPerLine;
|
||
width = tileArea->r_xtop - tileArea->r_xbot;
|
||
height = tileArea->r_ytop - tileArea->r_ybot;
|
||
|
||
/* Process the stippled area one raster line at a time, top to bottom. */
|
||
|
||
if (dinfo & TT_SIDE)
|
||
{
|
||
locright = area.r_xtop;
|
||
tbase = rasleft + area.r_xtop / 32; /* base is on right */
|
||
}
|
||
else
|
||
{
|
||
locleft = area.r_xbot;
|
||
tbase = rasleft + area.r_xbot / 32; /* base is on left */
|
||
}
|
||
|
||
for (line = area.r_ytop; line >= area.r_ybot; line -= 1)
|
||
{
|
||
if (dinfo & TT_SIDE)
|
||
{
|
||
if (dinfo & TT_DIRECTION)
|
||
locleft = tileArea->r_xbot + (((tileArea->r_ytop - line) * width)
|
||
/ height);
|
||
else
|
||
locleft = tileArea->r_xbot + (((line - tileArea->r_ybot) * width)
|
||
/ height);
|
||
right = tbase;
|
||
left = rasleft + locleft / 32;
|
||
}
|
||
else
|
||
{
|
||
if (dinfo & TT_DIRECTION)
|
||
locright = tileArea->r_xbot + (((tileArea->r_ytop - line) * width)
|
||
/ height);
|
||
else
|
||
locright = tileArea->r_xbot + (((line - tileArea->r_ybot) * width)
|
||
/ height);
|
||
right = rasleft + locright / 32;
|
||
left = tbase;
|
||
}
|
||
if (left > right) continue;
|
||
|
||
leftMask = rightBits[locleft & 037];
|
||
rightMask = leftBits[locright & 037];
|
||
if (left == right)
|
||
leftMask &= rightMask;
|
||
|
||
curStipple = stipple[(-line)&017];
|
||
|
||
/* Fill the leftmost word on this line. */
|
||
|
||
*left |= curStipple & leftMask;
|
||
|
||
if (left != right)
|
||
{
|
||
/* Fill the center of the line. */
|
||
|
||
for (cur = left+1; cur < right; cur += 1)
|
||
*cur |= curStipple;
|
||
|
||
/* Fill the rightmost word on this line. */
|
||
|
||
*cur |= curStipple & rightMask;
|
||
}
|
||
|
||
rasleft += raster->ras_intsPerLine;
|
||
tbase += raster->ras_intsPerLine;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotFillRaster --
|
||
*
|
||
* Given a raster and an area, this procedure fills the given area
|
||
* of the raster with a particular stipple pattern.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotFillRaster(raster, area, stipple)
|
||
Raster *raster; /* Pointer to raster whose bits are
|
||
* to be filled in.
|
||
*/
|
||
Rect *area; /* Area to be filled in pixel coords.
|
||
* This is an inclusive area: it
|
||
* includes the boundary pixels. The
|
||
* caller must ensure that it is
|
||
* clipped to the raster area.
|
||
*/
|
||
Stipple stipple; /* Stipple pattern to be used to fill
|
||
* in the raster area.
|
||
*/
|
||
{
|
||
int *left, *cur, line;
|
||
int *right;
|
||
int leftMask, rightMask, curStipple;
|
||
|
||
/* Compute the address of the leftmost word in the topmost line
|
||
* to be filled, and the rightmost word in the topmost line to
|
||
* be filled.
|
||
*/
|
||
|
||
left = raster->ras_bits +
|
||
((raster->ras_height-1) - area->r_ytop)*raster->ras_intsPerLine;
|
||
right = left + area->r_xtop/32;
|
||
left += area->r_xbot/32;
|
||
|
||
/* Divide the x-span of the area into three parts: the leftmost
|
||
* word, of which only the rightmost bits are modified, the
|
||
* rightmost word, of which only the leftmost bits are modified,
|
||
* and the middle section, in which all bits of each word are
|
||
* modified. Compute masks that determine which bits of the end
|
||
* words will be modified. There's a special case when the left
|
||
* and right ends are in the same word.
|
||
*/
|
||
|
||
leftMask = rightBits[area->r_xbot&037];
|
||
rightMask = leftBits[area->r_xtop&037];
|
||
if (left == right)
|
||
leftMask &= rightMask;
|
||
|
||
/* Process the stippled area one raster line at a time, top to bottom. */
|
||
|
||
for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
|
||
{
|
||
curStipple = stipple[(-line)&017];
|
||
|
||
/* Fill the leftmost word on this line. */
|
||
|
||
*left |= curStipple & leftMask;
|
||
|
||
if (left != right)
|
||
{
|
||
/* Fill the center of the line. */
|
||
|
||
for (cur = left+1; cur < right; cur += 1)
|
||
*cur |= curStipple;
|
||
|
||
/* Fill the rightmost word on this line. */
|
||
|
||
*cur |= curStipple & rightMask;
|
||
}
|
||
|
||
left += raster->ras_intsPerLine;
|
||
right += raster->ras_intsPerLine;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotDumpRaster --
|
||
*
|
||
* Writes out the contents of the given raster to the given file,
|
||
* in binary format.
|
||
*
|
||
* Results:
|
||
* Returns 0 if all was well. Returns non-zero if there was
|
||
* an I/O error. In this event, this procedure prints an
|
||
* error message before returning.
|
||
*
|
||
* Side effects:
|
||
* Information is added to file.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
PlotDumpRaster(raster, file)
|
||
Raster *raster; /* Raster to be dumped. */
|
||
FILE *file; /* File in which to dump it. */
|
||
{
|
||
int count;
|
||
|
||
count = write(fileno(file), (char *) raster->ras_bits,
|
||
raster->ras_bytesPerLine*raster->ras_height);
|
||
if (count < 0)
|
||
{
|
||
TxError("I/O error in writing raster file: %s.\n",
|
||
strerror(errno));
|
||
return 1;
|
||
}
|
||
rasFileByteCount += count;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotLoadFont --
|
||
*
|
||
* Loads a font into memory, if it isn't already there.
|
||
*
|
||
** Patched to accommodate both VAX format and Sun format vfont(5) files,
|
||
** regardless of the native byte order of the processor. J. Gealow 3/30/94
|
||
*
|
||
* Results:
|
||
* The return value is a pointer to the font. This must be used
|
||
* when calling procedures like PlotTextSize. If the font file
|
||
* couldn't be found, an error message is output and NULL is
|
||
* returned.
|
||
*
|
||
* Side effects:
|
||
* New memory gets allocated.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
RasterFont *
|
||
PlotLoadFont(name)
|
||
char *name; /* Name of font file. */
|
||
{
|
||
FILE *f;
|
||
RasterFont *new;
|
||
struct dispatch *d;
|
||
|
||
/* See if we've already got the font. */
|
||
|
||
for (new = PlotFontList; new != NULL; new = new->fo_next)
|
||
{
|
||
if (strcmp(new->fo_name, name) == 0)
|
||
return new;
|
||
}
|
||
|
||
f = PaOpen(name, "r", (char *) NULL, ".", SysLibPath, (char **) NULL);
|
||
if (f == NULL)
|
||
{
|
||
TxError("Couldn't read font file \"%s\".\n", name);
|
||
return NULL;
|
||
}
|
||
|
||
new = (RasterFont *) mallocMagic(sizeof(RasterFont));
|
||
new->fo_name = NULL;
|
||
StrDup(&new->fo_name, name);
|
||
|
||
/* Read in the font's header and check the magic number. */
|
||
|
||
if (read(fileno(f), (char *) &new->fo_hdr, sizeof(new->fo_hdr))
|
||
!= sizeof(new->fo_hdr))
|
||
{
|
||
fontError:
|
||
TxError("Error in reading font file \"%s\".\n", name);
|
||
fclose(f);
|
||
return NULL;
|
||
}
|
||
if (PlotSwapShort(new->fo_hdr.magic) == 0436)
|
||
{
|
||
new->fo_hdr.size = (PlotSwapShort(new->fo_hdr.size));
|
||
new->fo_hdr.maxx = (PlotSwapShort(new->fo_hdr.maxx));
|
||
new->fo_hdr.maxy = (PlotSwapShort(new->fo_hdr.maxy));
|
||
new->fo_hdr.xtend = (PlotSwapShort(new->fo_hdr.xtend));
|
||
}
|
||
else if (new->fo_hdr.magic != 0436)
|
||
{
|
||
TxError("Bad magic number in font file \"%s\".\n", name);
|
||
fclose(f);
|
||
return NULL;
|
||
}
|
||
|
||
/* Read the character descriptors and the bit map. */
|
||
|
||
if (read(fileno(f), (char *) new->fo_chars, sizeof(new->fo_chars))
|
||
!= sizeof(new->fo_chars))
|
||
goto fontError;
|
||
new->fo_bits = mallocMagic(new->fo_hdr.size);
|
||
if (read(fileno(f), new->fo_bits, (unsigned) new->fo_hdr.size)
|
||
!= new->fo_hdr.size)
|
||
goto fontError;
|
||
fclose(f);
|
||
|
||
/* Compute the bounding box of all characters in the font. */
|
||
|
||
new->fo_bbox.r_xbot = new->fo_bbox.r_xtop = 0;
|
||
new->fo_bbox.r_ybot = new->fo_bbox.r_ytop = 0;
|
||
for (d = &new->fo_chars[0]; d < &new->fo_chars[256]; d++)
|
||
{
|
||
if (PlotSwapShort(new->fo_hdr.magic) == 0436)
|
||
{
|
||
d->addr = PlotSwapShort(d->addr);
|
||
d->nbytes = PlotSwapShort(d->nbytes);
|
||
d->width = PlotSwapShort(d->width);
|
||
}
|
||
if (d->nbytes == 0) continue;
|
||
if (d->up > new->fo_bbox.r_ytop)
|
||
new->fo_bbox.r_ytop = d->up;
|
||
if (d->down > new->fo_bbox.r_ybot)
|
||
new->fo_bbox.r_ybot = d->down;
|
||
if (d->right > new->fo_bbox.r_xtop)
|
||
new->fo_bbox.r_xtop = d->right;
|
||
if (d->left > new->fo_bbox.r_xbot)
|
||
new->fo_bbox.r_xbot = d->left;
|
||
#ifdef DEBUG_FONT
|
||
if (d == &new->fo_chars['d'])
|
||
{
|
||
char *fontcp;
|
||
int count;
|
||
|
||
TxError("Character 'd' in font '%s' is at addr 0x%x, bytes %d, width %d\n",
|
||
new->fo_name, d->addr, d->nbytes, d->width);
|
||
count = 0;
|
||
for (fontcp = new->fo_bits + d->addr;
|
||
fontcp < new->fo_bits + d->addr + d->nbytes; fontcp++)
|
||
{
|
||
int i;
|
||
char ch;
|
||
ch = *fontcp;
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
TxError("%c", ((ch & 0x80) ? 'X' : '.'));
|
||
ch = (ch << 1);
|
||
}
|
||
count++;
|
||
if (count >= (d->left + d->right + 7) >> 3)
|
||
{
|
||
TxError("\n");
|
||
count = 0;
|
||
}
|
||
}
|
||
TxError("\n");
|
||
}
|
||
#endif /* DEBUG_FONT */
|
||
}
|
||
new->fo_bbox.r_xbot = - new->fo_bbox.r_xbot;
|
||
new->fo_bbox.r_ybot = - new->fo_bbox.r_ybot;
|
||
|
||
new->fo_next = PlotFontList;
|
||
PlotFontList = new;
|
||
return new;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotTextSize --
|
||
*
|
||
* Compute the area that a string will occupy.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* The rectangle "area" is filled in with the bounding
|
||
* box of the bits in "string", assuming that the origin
|
||
* for the text is (0,0) and the text is rendered in font
|
||
* "font".
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotTextSize(font, string, area)
|
||
RasterFont *font; /* Font to use in computing text size. */
|
||
char *string; /* String to compute size of. */
|
||
Rect *area; /* Place to store bounding box. */
|
||
{
|
||
int x;
|
||
struct dispatch *d;
|
||
|
||
area->r_xbot = area->r_xtop = 0;
|
||
area->r_ybot = area->r_ytop = 0;
|
||
x = 0;
|
||
|
||
for ( ; *string != 0; string ++)
|
||
{
|
||
if ((*string == ' ') || (*string == '\t'))
|
||
d = &font->fo_chars['t'];
|
||
else d = &font->fo_chars[*string];
|
||
if (d->nbytes == 0) continue;
|
||
if (d->up > area->r_ytop)
|
||
area->r_ytop = d->up;
|
||
if (d->down > area->r_ybot)
|
||
area->r_ybot = d->down;
|
||
if ((x+d->right) > area->r_xtop)
|
||
area->r_xtop = x + d->right;
|
||
if ((x-d->left) < area->r_ybot)
|
||
area->r_ybot = x - d->left;
|
||
x += d->width;
|
||
}
|
||
area->r_ybot = -area->r_ybot;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotRasterText --
|
||
*
|
||
* Given a text string and a font, this procedure scan-converts
|
||
* the string and sets bits in the current raster that correspond
|
||
* to on-bits in the text.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Bits are modified in the raster.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotRasterText(raster, clip, font, string, point)
|
||
Raster *raster; /* Raster whose bits are to be filled in. */
|
||
Rect *clip; /* Area to which to clip the text. Must be
|
||
* entirely within the area of the raster.
|
||
*/
|
||
RasterFont *font; /* Font to use for rasterizing string. Must
|
||
* have been obtained by calling PlotLoadFont.
|
||
*/
|
||
char *string; /* String of text to rasterize. */
|
||
Point *point; /* X-Y coordinates of origin of text. The
|
||
* origin need not be inside the area of
|
||
* the raster, but only raster points inside
|
||
* the area will be modified.
|
||
*/
|
||
{
|
||
int xOrig; /* X-origin for current character. */
|
||
|
||
|
||
/* Outer loop: process each character. */
|
||
|
||
xOrig = point->p_x;
|
||
for ( ; *string != 0; string++)
|
||
{
|
||
int cBytesPerLine, i;
|
||
struct dispatch *d; /* Descriptor for current character. */
|
||
|
||
/* Handle spaces and tabs specially by just spacing over. */
|
||
|
||
if ((*string == ' ') || (*string == '\t'))
|
||
{
|
||
xOrig += font->fo_chars['t'].width;
|
||
continue;
|
||
}
|
||
|
||
/* Middle loop: render each character one raster line at a
|
||
* time, from top to bottom. Skip rows that are outside the
|
||
* area of the raster.
|
||
*/
|
||
|
||
d = &font->fo_chars[*string];
|
||
cBytesPerLine = (d->left + d->right + 7) >> 3;
|
||
for (i = 0; i < d->up + d->down; i++)
|
||
{
|
||
int y, j;
|
||
char *charBitPtr;
|
||
|
||
y = point->p_y + d->up - 1 - i;
|
||
if (y < clip->r_ybot) break;
|
||
if (y > clip->r_ytop) continue;
|
||
|
||
/* Inner loop: process a series of bytes in a row to
|
||
* render one raster line of one character. Be sure
|
||
* to skip areas that fall outside the raster to the
|
||
* left or right.
|
||
*/
|
||
|
||
for (j = -d->left,
|
||
charBitPtr = font->fo_bits + d->addr + i*cBytesPerLine;
|
||
j < d->right;
|
||
j += 8, charBitPtr++)
|
||
{
|
||
char *rPtr;
|
||
int charBits, x;
|
||
|
||
x = xOrig + j;
|
||
if (x > clip->r_xtop) break;
|
||
if (x < clip->r_xbot - 7) continue;
|
||
|
||
rPtr = (char *) raster->ras_bits;
|
||
rPtr += (raster->ras_height - 1 - y)*raster->ras_bytesPerLine
|
||
+ (x>>3);
|
||
charBits = *charBitPtr & 0xff;
|
||
|
||
/* One byte of the character's bit map may span two
|
||
* bytes of the raster, so process each of the two
|
||
* raster bytes separately. Either of the two bytes
|
||
* may be off the edge of the raster, in which case
|
||
* it must be skipped.
|
||
*/
|
||
|
||
if (x >= 0)
|
||
*rPtr |= charBits >> (x & 0x7);
|
||
rPtr += 1;
|
||
if (x+8 <= clip->r_xtop)
|
||
{
|
||
charBits = charBits << (8 - (x & 0x7));
|
||
*rPtr |= charBits;
|
||
}
|
||
}
|
||
}
|
||
|
||
xOrig += d->width;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotRastPoint --
|
||
*
|
||
* Sets a particular pixel of a raster.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* If x and y lie inside the raster then the pixel that they select
|
||
* is set to 1. If x or y is outside the raster area then nothing
|
||
* happens.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotRastPoint(raster, x, y)
|
||
Raster *raster; /* Raster containing pixel to be
|
||
* filled.
|
||
*/
|
||
int x, y; /* Coordinates of pixel. */
|
||
{
|
||
if ((x < 0) || (x >= raster->ras_width)) return;
|
||
y = (raster->ras_height - 1) - y;
|
||
if ((y < 0) || (y >= raster->ras_height)) return;
|
||
|
||
raster->ras_bits[((y*raster->ras_intsPerLine) + (x>>5))]
|
||
|= singleBit[x&037];
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotRastLine --
|
||
*
|
||
* Draws a one-pixel-wide line between two points.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* A line is drawn between pixels src and dst. Only the portion
|
||
* of the line that lies inside the raster is drawn; the endpoints
|
||
* may lie outside the raster (this feature is necessary to draw
|
||
* straight lines that cross multiple swaths).
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotRastLine(raster, src, dst)
|
||
Raster *raster; /* Where to render the line. */
|
||
Point *src; /* One endpoint of line, in raster coords. */
|
||
Point *dst; /* The other endpoint, in raster coords. */
|
||
{
|
||
int x, y, dx, dy, xinc, incr1, incr2, d, done;
|
||
|
||
/* Compute the total x- and y-motions, and arrange for the line to be
|
||
* drawn in increasing order of y-coordinate.
|
||
*/
|
||
|
||
dx = dst->p_x - src->p_x;
|
||
dy = dst->p_y - src->p_y;
|
||
if (dy < 0)
|
||
{
|
||
dy = -dy;
|
||
dx = -dx;
|
||
x = dst->p_x;
|
||
y = dst->p_y;
|
||
dst = src;
|
||
}
|
||
else
|
||
{
|
||
x = src->p_x;
|
||
y = src->p_y;
|
||
}
|
||
|
||
/* The code below is just the Bresenham algorithm from Foley and
|
||
* Van Dam (pp. 435), modified slightly so that it can work in
|
||
* all directions.
|
||
*/
|
||
|
||
if (dx < 0)
|
||
{
|
||
xinc = -1;
|
||
dx = -dx;
|
||
}
|
||
else xinc = 1;
|
||
if (dx >= dy)
|
||
{
|
||
d = 2*dy - dx;
|
||
incr1 = 2*dy;
|
||
incr2 = 2*(dy - dx);
|
||
done = dst->p_x;
|
||
for ( ; x != done ; x += xinc)
|
||
{
|
||
PlotRastPoint(raster, x, y);
|
||
if (d < 0)
|
||
d += incr1;
|
||
else
|
||
{
|
||
d += incr2;
|
||
y += 1;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
d = 2*dx - dy;
|
||
incr1 = 2*dx;
|
||
incr2 = 2*(dx - dy);
|
||
done = dst->p_y;
|
||
for ( ; y != done ; y += 1)
|
||
{
|
||
PlotRastPoint(raster, x, y);
|
||
if (d < 0)
|
||
d += incr1;
|
||
else
|
||
{
|
||
d += incr2;
|
||
x += xinc;
|
||
}
|
||
}
|
||
}
|
||
PlotRastPoint(raster, x, y);
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotRastFatLine --
|
||
*
|
||
* Draws a line many pixels wide between two points.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* A line is drawn between pixels src and dst. Only the portion
|
||
* of the line that lies inside the raster is drawn; the endpoints
|
||
* may lie outside the raster (this feature is necessary to draw
|
||
* straight lines that cross multiple swaths). The line is drawn
|
||
* several pixels wide, as determined by the "widen" parameter.
|
||
* The ends of the line are square, not rounded, which may cause
|
||
* upleasant effects for some uses. If the line is Manhattan,
|
||
* this procedure is very inefficient: it's better to use the
|
||
* PlotFillRaster procedure.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotRastFatLine(raster, src, dst, widen)
|
||
Raster *raster; /* Where to render the line. */
|
||
Point *src; /* One endpoint of line, in raster coords. */
|
||
Point *dst; /* The other endpoint, in raster coords. */
|
||
int widen; /* How much to widen the line. 0 means the
|
||
* line is one pixel wide, 1 means it's 3
|
||
* pixels wide, and so on.
|
||
*/
|
||
{
|
||
double dx, dy, x, y;
|
||
int nLines;
|
||
|
||
/* Just draw (2*widen) + 1 lines spaced about one pixel apart.
|
||
* The first lines here compute how far apart to space the lines.
|
||
*/
|
||
|
||
nLines = (2*widen) + 1;
|
||
x = dst->p_x - src->p_x;
|
||
y = dst->p_y - src->p_y;
|
||
dy = sqrt(x*x + y*y);
|
||
dx = y/dy;
|
||
dy = -x/dy;
|
||
x = -dy*(widen);
|
||
y = dx*(widen);
|
||
|
||
for (x = -dx*widen, y = -dy*widen;
|
||
nLines > 0;
|
||
nLines -= 1, x += dx, y += dy)
|
||
{
|
||
Point newSrc, newDst;
|
||
|
||
if (x > 0)
|
||
newSrc.p_x = (x + .5);
|
||
else newSrc.p_x = (x - .5);
|
||
if (y > 0)
|
||
newSrc.p_y = (y + .5);
|
||
else newSrc.p_y = (y - .5);
|
||
newDst.p_x = dst->p_x + newSrc.p_x;
|
||
newDst.p_y = dst->p_y + newSrc.p_y;
|
||
newSrc.p_x += src->p_x;
|
||
newSrc.p_y += src->p_y;
|
||
|
||
PlotRastLine(raster, &newSrc, &newDst);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotSwapBytes --
|
||
* PlotSwapShort --
|
||
*
|
||
* These two procedures do byte swapping in the way that's
|
||
* required when moving binary files between VAXes and Suns.
|
||
*
|
||
* Results:
|
||
* Each procedure returns a value in which the order of bytes
|
||
* has been reversed. PlotSwapBytes takes an integer and returns
|
||
* an integer with the four bytes in reverse order; PlotSwapShort
|
||
* takes a short and swaps the two bytes.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
PlotSwapBytes(value)
|
||
int value; /* 4-byte Value whose bytes are to
|
||
* be reversed.
|
||
*/
|
||
{
|
||
int result;
|
||
|
||
#define src ((char *) &value)
|
||
#define dst ((char *) &result)
|
||
|
||
dst[0] = src[3];
|
||
dst[1] = src[2];
|
||
dst[2] = src[1];
|
||
dst[3] = src[0];
|
||
|
||
return result;
|
||
}
|
||
|
||
short
|
||
PlotSwapShort(value)
|
||
short value; /* Value whose bytes are to be swapped. */
|
||
{
|
||
short result;
|
||
|
||
#define src ((char *) &value)
|
||
#define dst ((char *) &result)
|
||
|
||
dst[0] = src[1];
|
||
dst[1] = src[0];
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotDumpColorPreamble --
|
||
*
|
||
* Dump a color preamble in vdmpc format for the color Versatec. See
|
||
* the vdmpc(5) man page for details on the format.
|
||
*
|
||
* Format:
|
||
* preamble is a 1K block
|
||
* first word is 0xA5CF4DFB (a magic number)
|
||
* second word gives the number of scan lines
|
||
* third word gives width of the plot in pixels (must be multiple of 8)
|
||
* rest of the words are zero
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
#define VERSATEC_BLOCK 1024
|
||
#define VERSATEC_MAGIC_WORD 0xA5CF4DFB
|
||
unsigned int VersHeader[VERSATEC_BLOCK/sizeof(unsigned int)] = {VERSATEC_MAGIC_WORD};
|
||
|
||
int
|
||
PlotDumpColorPreamble(color, file, lines, columns)
|
||
VersatecColor color; /* The color that the following raster will
|
||
* be printed in.
|
||
*/
|
||
FILE *file; /* file in which to place header */
|
||
int lines; /* number of scan lines */
|
||
int columns; /* Width in pixels. */
|
||
{
|
||
|
||
int count;
|
||
|
||
if (color == BLACK)
|
||
{
|
||
VersHeader[1] = lines;
|
||
VersHeader[2] = columns;
|
||
count = write(fileno(file), &VersHeader[0], sizeof(VersHeader));
|
||
TxPrintf("Wrote %d bytes of control.\n", count);
|
||
}
|
||
return 0;
|
||
}
|