123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /* This file defines libxmi's miCanvas class. An miCanvas is an object
- that includes a drawable (a miCanvasPixmap, which by default is a
- miPixmap [essentially a 2-D array of miPixels]) and various data members
- that indicate how any specified set of pixels should be painted. These
- may include a stipple miBitmap and a texture miPixmap; if they are
- non-NULL, they will tile the canvas.
- This file supports a good deal of customization, which would probably be
- needed if libxmi is installed as a rendering module in other software.
- The following preprocessor symbols may be defined:
- MI_PIXEL_TYPE
- MI_CANVAS_DRAWABLE_TYPE
- MI_GET_CANVAS_DRAWABLE_PIXEL()
- MI_SET_CANVAS_DRAWABLE_PIXEL()
- MI_GET_CANVAS_DRAWABLE_BOUNDS()
- MI_DEFAULT_MERGE2_PIXEL()
- MI_DEFAULT_MERGE3_PIXEL()
- See xmi.h for details on what they do. Ideally you should be able to
- #define those symbols appropriately, and never modify this file. */
- #include "sys-defines.h"
- #include "extern.h"
- #include "xmi.h"
- #include "mi_spans.h"
- #include "mi_api.h"
- /* forward references (these are currently used only in this file) */
- static miPixmap * miNewPixmap (unsigned int width, unsigned int height, miPixel initPixel);
- static miPixmap * miCopyPixmap (const miPixmap *pPixmap);
- static void miDeletePixmap (miPixmap *pPixmap);
- #if 0 /* not currently used, so commented out */
- static miBitmap * miNewBitmap (unsigned int width, unsigned int height, int initBit);
- #endif
- static miBitmap * miCopyBitmap (const miBitmap *pBitmap);
- static void miDeleteBitmap (miBitmap *pBitmap);
- static void miPaintCanvas (miCanvas *canvas, miPixel pixel, int n, const miPoint *ppt, const unsigned int *pwidth, miPoint offset);
- /* Ctor/dtor/copy ctor for the miCanvas class. These are defined only if
- the symbol MI_CANVAS_DRAWABLE_TYPE hasn't been defined by the libxmi
- installer. If it's defined, the drawable encapsulated within an
- miCanvas is presumably something other than a miPixmap, and we won't
- know how to create/destroy/copy miCanvas's. */
- #ifndef MI_CANVAS_DRAWABLE_TYPE
- /* create (allocate) a new miCanvas */
- miCanvas *
- miNewCanvas (unsigned int width, unsigned int height, miPixel initPixel)
- {
- miCanvas *new_pCanvas;
-
- if (width < 1 || height < 1)
- return (miCanvas *)NULL;
- new_pCanvas = (miCanvas *)mi_xmalloc (sizeof (miCanvas));
- new_pCanvas->drawable = miNewPixmap (width, height, initPixel);
- /* default values */
- new_pCanvas->texture = (miPixmap *)NULL;
- new_pCanvas->stipple = (miBitmap *)NULL;
- new_pCanvas->pixelMerge2 = (miPixelMerge2)NULL;
- new_pCanvas->pixelMerge3 = (miPixelMerge3)NULL;
- return new_pCanvas;
- }
- /* copy a miCanvas */
- miCanvas *
- miCopyCanvas (const miCanvas *pCanvas)
- {
- miCanvas *new_pCanvas;
-
- if (pCanvas == (const miCanvas *)NULL)
- return (miCanvas *)NULL;
- new_pCanvas = (miCanvas *)mi_xmalloc (sizeof (miCanvas));
- new_pCanvas->drawable = miCopyPixmap (pCanvas->drawable);
- new_pCanvas->pixelMerge2 = pCanvas->pixelMerge2;
- new_pCanvas->pixelMerge3 = pCanvas->pixelMerge3;
- new_pCanvas->texture = miCopyPixmap (pCanvas->texture);
- new_pCanvas->stipple = miCopyBitmap (pCanvas->stipple);
- return new_pCanvas;
- }
- /* destroy (deallocate) an miCanvas */
- void
- miDeleteCanvas (miCanvas *pCanvas)
- {
- if (pCanvas == (miCanvas *)NULL)
- return;
- miDeletePixmap (pCanvas->drawable);
- miDeletePixmap (pCanvas->texture);
- miDeleteBitmap (pCanvas->stipple);
- free (pCanvas);
- }
- #endif /* not MI_CANVAS_DRAWABLE_TYPE */
- /* create a new miPixmap, and fill it with a specified miPixel */
- static miPixmap *
- miNewPixmap (unsigned int width, unsigned int height, miPixel initPixel)
- {
- miPixmap *new_pPixmap;
- miPixel **pixmap;
- int i, j;
-
- new_pPixmap = (miPixmap *)mi_xmalloc (sizeof(miPixmap));
- /* create a pixmap (an array of pointers to rows of miPixels) */
- pixmap = (miPixel **)mi_xmalloc (height * sizeof(miPixel *));
- for (j = 0; j < (int)height; j++)
- {
- pixmap[j] = (miPixel *)mi_xmalloc (width * sizeof(miPixel));
- for (i = 0; i < (int)width; i++)
- pixmap[j][i] = initPixel;
- }
- new_pPixmap->pixmap = pixmap;
- new_pPixmap->width = width;
- new_pPixmap->height = height;
- return new_pPixmap;
- }
- /* copy a miPixmap */
- static miPixmap *
- miCopyPixmap (const miPixmap *pPixmap)
- {
- miPixmap *new_pPixmap;
- miPixel **pixmap;
- miPixel * const *old_pixmap;
- int i, j;
-
- if (pPixmap == (const miPixmap *)NULL)
- return (miPixmap *)NULL;
- new_pPixmap = (miPixmap *)mi_xmalloc (sizeof(miPixmap));
- /* create a pixmap (an array of pointers to rows of miPixels) */
- pixmap = (miPixel **)mi_xmalloc (pPixmap->height * sizeof(miPixel *));
- old_pixmap = pPixmap->pixmap;
- for (j = 0; j < (int)(pPixmap->height); j++)
- {
- pixmap[j] = (miPixel *)mi_xmalloc (pPixmap->width * sizeof(miPixel));
- for (i = 0; i < (int)(pPixmap->width); i++)
- pixmap[j][i] = old_pixmap[j][i];
- }
- new_pPixmap->pixmap = pixmap;
- new_pPixmap->width = pPixmap->width;
- new_pPixmap->height = pPixmap->height;
- return new_pPixmap;
- }
- /* destroy (deallocate) an miPixmap */
- static void
- miDeletePixmap (miPixmap *pPixmap)
- {
- int j;
- if (pPixmap == (miPixmap *)NULL)
- return;
- /* free pixmap (an array of pointers to rows of miPixels) */
- for (j = 0; j < (int)(pPixmap->height); j++)
- free (pPixmap->pixmap[j]);
- free (pPixmap->pixmap);
- free (pPixmap);
- }
- #if 0 /* not currently used, so commented out */
- /* create a new miBitmap, and fill it with a specified value (only 0 and 1
- are meaningful) */
- static miBitmap *
- miNewBitmap (unsigned int width, unsigned int height, int initBit)
- {
- miBitmap *new_pBitmap;
- int **bitmap;
- int i, j;
-
- new_pBitmap = (miBitmap *)mi_xmalloc (sizeof(miBitmap));
- /* create a bitmap (an array of pointers to rows of ints) */
- bitmap = (int **)mi_xmalloc (height * sizeof(int *));
- for (j = 0; j < (int)height; j++)
- {
- bitmap[j] = (int *)mi_xmalloc (width * sizeof(int));
- for (i = 0; i < (int)width; i++)
- bitmap[j][i] = initBit;
- }
- new_pBitmap->bitmap = bitmap;
- new_pBitmap->width = width;
- new_pBitmap->height = height;
- return new_pBitmap;
- }
- #endif
- /* copy a miBitmap */
- static miBitmap *
- miCopyBitmap (const miBitmap *pBitmap)
- {
- miBitmap *new_pBitmap;
- int **bitmap;
- int * const *old_bitmap;
- int i, j;
-
- if (pBitmap == (const miBitmap *)NULL)
- return (miBitmap *)NULL;
- new_pBitmap = (miBitmap *)mi_xmalloc (sizeof(miBitmap));
- /* create a bitmap (an array of pointers to rows of ints) */
- bitmap = (int **)mi_xmalloc (pBitmap->height * sizeof(int *));
- old_bitmap = pBitmap->bitmap;
- for (j = 0; j < (int)(pBitmap->height); j++)
- {
- bitmap[j] = (int *)mi_xmalloc (pBitmap->width * sizeof(int));
- for (i = 0; i < (int)(pBitmap->width); i++)
- bitmap[j][i] = old_bitmap[j][i];
- }
- new_pBitmap->bitmap = bitmap;
- new_pBitmap->width = pBitmap->width;
- new_pBitmap->height = pBitmap->height;
- return new_pBitmap;
- }
- /* destroy (deallocate) an miBitmap */
- static void
- miDeleteBitmap (miBitmap *pBitmap)
- {
- int j;
- if (pBitmap == (miBitmap *)NULL)
- return;
- /* free bitmap (an array of pointers to rows of ints) */
- for (j = 0; j < (int)(pBitmap->height); j++)
- free (pBitmap->bitmap[j]);
- free (pBitmap->bitmap);
- free (pBitmap);
- }
- /* set the binary pixel-merging function in an miCanvas */
- void
- miSetPixelMerge2 (miCanvas *pCanvas, miPixelMerge2 pixelMerge2)
- {
- if (pCanvas == (miCanvas *)NULL)
- return;
- pCanvas->pixelMerge2 = pixelMerge2;
- }
- /* set the ternary pixel-merging function in an miCanvas */
- void
- miSetPixelMerge3 (miCanvas *pCanvas, miPixelMerge3 pixelMerge3)
- {
- if (pCanvas == (miCanvas *)NULL)
- return;
- pCanvas->pixelMerge3 = pixelMerge3;
- }
- /* Copy a stipple miBitmap into an miCanvas. The old stipple, if any, is
- deallocated. */
- void
- miSetCanvasStipple (miCanvas *pCanvas, const miBitmap *pstipple, miPoint stippleOrigin)
- {
- if (pCanvas == (miCanvas *)NULL)
- return;
- miDeleteBitmap (pCanvas->stipple);
- pCanvas->stipple = miCopyBitmap (pstipple);
- pCanvas->stippleOrigin = stippleOrigin;
- }
- /* Copy a texture miPixmap into an miCanvas. The old texture, if any, is
- deallocated. */
- void
- miSetCanvasTexture (miCanvas *pCanvas, const miPixmap *pTexture, miPoint textureOrigin)
- {
- if (pCanvas == (miCanvas *)NULL)
- return;
- miDeletePixmap (pCanvas->texture);
- pCanvas->texture = miCopyPixmap (pTexture);
- pCanvas->textureOrigin = textureOrigin;
- }
- /* Paint a list of spans, in a specified miPixel color, to a canvas. The
- spans must be in y-increasing order. */
- /* ARGS: canvas = canvas
- pixel = source pixel color
- n = number of spans to be painted
- ppt = array of starting points of spans
- pwidth = array of widths of spans
- offset = point that (0,0) gets mapped to */
- static void
- miPaintCanvas (miCanvas *canvas, miPixel pixel, int n, const miPoint *ppt, const unsigned int *pwidth, miPoint offset)
- {
- int i;
- int xleft, xright, ybottom, ytop;
- unsigned int stippleWidth = 0, stippleHeight = 0; /* keep lint happy */
- unsigned int textureWidth = 0, textureHeight = 0; /* keep lint happy */
- int stippleXOrigin = 0, stippleYOrigin = 0; /* keep lint happy */
- int textureXOrigin = 0, textureYOrigin = 0; /* keep lint happy */
- int xstart, xend, xstart_clip, xend_clip, xoffset, yoffset, x, y;
- unsigned int width;
- const miCanvas *pCanvas; /* `const' should be OK here */
- miPixelMerge2 pixelMerge2;
- miPixelMerge3 pixelMerge3;
- pCanvas = canvas;
- xoffset = offset.x;
- yoffset = offset.y;
- /* compute bounds of destination drawable */
- MI_GET_CANVAS_DRAWABLE_BOUNDS(pCanvas, xleft, ytop, xright, ybottom)
- /* if source doesn't overlap with destination drawable, do nothing */
- if (ppt[0].y + yoffset > ybottom || ppt[n-1].y + yoffset < ytop)
- return;
- /* determine user-specified merging functions (if any) */
- pixelMerge2 = pCanvas->pixelMerge2;
- pixelMerge3 = pCanvas->pixelMerge3;
- #define MI_MERGE_CANVAS_PIXEL(pCanvas, x, y, sourcePixel, texturePixel, have_texturePixel) \
- { \
- miPixel destinationPixel, newPixel; \
- MI_GET_CANVAS_DRAWABLE_PIXEL((pCanvas), (x), (y), destinationPixel); \
- if (!have_texturePixel) \
- { \
- if (pixelMerge2 != (miPixelMerge2)NULL) \
- newPixel = (*pixelMerge2)((sourcePixel), destinationPixel); \
- else \
- MI_DEFAULT_MERGE2_PIXEL(newPixel, (sourcePixel), destinationPixel); \
- } \
- else \
- { \
- if (pixelMerge3 != (miPixelMerge3)NULL) \
- newPixel = (*pixelMerge3)((texturePixel), (sourcePixel), destinationPixel); \
- else \
- MI_DEFAULT_MERGE3_PIXEL(newPixel, (texturePixel), (sourcePixel), destinationPixel); \
- } \
- MI_SET_CANVAS_DRAWABLE_PIXEL((pCanvas), (x), (y), newPixel); \
- }
- if (pCanvas->stipple)
- {
- stippleWidth = pCanvas->stipple->width;
- stippleHeight = pCanvas->stipple->height;
- stippleXOrigin = pCanvas->stippleOrigin.x;
- stippleYOrigin = pCanvas->stippleOrigin.y;
- while (stippleXOrigin > 0)
- stippleXOrigin -= stippleWidth;
- while (stippleYOrigin > 0)
- stippleYOrigin -= stippleHeight;
- }
-
- if (pCanvas->texture)
- {
- textureWidth = pCanvas->texture->width;
- textureHeight = pCanvas->texture->height;
- textureXOrigin = pCanvas->textureOrigin.x;
- textureYOrigin = pCanvas->textureOrigin.y;
- while (textureXOrigin > 0)
- textureXOrigin -= textureWidth;
- while (textureYOrigin > 0)
- textureYOrigin -= textureHeight;
- }
- for (i = 0; i < n; i++)
- {
- y = ppt[i].y + yoffset;
- if (y > ybottom)
- return; /* no more spans will be painted */
- if (y >= ytop)
- {
- width = pwidth[i];
- xstart = ppt[i].x + xoffset;
- xend = xstart + (int)width - 1;
-
- xstart_clip = IMAX(xstart,xleft);
- xend_clip = IMIN(xend,xright);
-
- for (x = xstart_clip; x <= xend_clip; x++) /* may be empty */
- /* merge pixel onto canvas */
- {
- miPixel texturePixel, sourcePixel;
- bool have_texturePixel = false;
-
- if (pCanvas->texture)
- {
- texturePixel = pCanvas->texture->pixmap[(y-textureYOrigin) % textureHeight][(x-textureXOrigin) % textureWidth];
- have_texturePixel = true;
- }
- else
- texturePixel = pixel; /* dummy; keep lint happy */
- sourcePixel = pixel;
-
- if (pCanvas->stipple == (miBitmap *)NULL
- || pCanvas->stipple->bitmap[(y-stippleYOrigin) % stippleHeight][(x-stippleXOrigin) % stippleWidth] != 0)
- MI_MERGE_CANVAS_PIXEL(pCanvas, x, y, sourcePixel, texturePixel, have_texturePixel)
- } /* end for x in ... */
- } /* end if */
- } /* end for y in ... */
- }
- /* Copy a miPaintedSet to an miCanvas. The miPaintedSet is assumed to have
- been uniquified (see mi_spans.c), which is the case after any of the
- eight core drawing functions in the libxmi API has been invoked. So
- there is at most one Spans per SpanGroup (i.e., Spans #0), and copying
- pixels out of it trivial. */
- /* ARGS: offset = point that (0,0) is mapped to */
- void
- miCopyPaintedSetToCanvas (const miPaintedSet *paintedSet, miCanvas *canvas, miPoint offset)
- {
- int i;
- /* For each pixel color, the initial Spans in the corresponding SpanGroup
- is effectively a list of spans, in y-increasing order. That is, it's
- a list of starting points and a corresponding list of widths; both are
- of length `count'. */
- for (i = 0; i < paintedSet->ngroups; i++)
- if (paintedSet->groups[i]->group[0].count > 0)
- miPaintCanvas (canvas, paintedSet->groups[i]->pixel,
- paintedSet->groups[i]->group[0].count,
- paintedSet->groups[i]->group[0].points,
- paintedSet->groups[i]->group[0].widths, offset);
- }
|