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,
|
|
(size_t)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,
|
|
(size_t)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[(unsigned char)*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[(unsigned char)*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;
|
|
}
|