mi_canvas.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /* This file defines libxmi's miCanvas class. An miCanvas is an object
  2. that includes a drawable (a miCanvasPixmap, which by default is a
  3. miPixmap [essentially a 2-D array of miPixels]) and various data members
  4. that indicate how any specified set of pixels should be painted. These
  5. may include a stipple miBitmap and a texture miPixmap; if they are
  6. non-NULL, they will tile the canvas.
  7. This file supports a good deal of customization, which would probably be
  8. needed if libxmi is installed as a rendering module in other software.
  9. The following preprocessor symbols may be defined:
  10. MI_PIXEL_TYPE
  11. MI_CANVAS_DRAWABLE_TYPE
  12. MI_GET_CANVAS_DRAWABLE_PIXEL()
  13. MI_SET_CANVAS_DRAWABLE_PIXEL()
  14. MI_GET_CANVAS_DRAWABLE_BOUNDS()
  15. MI_DEFAULT_MERGE2_PIXEL()
  16. MI_DEFAULT_MERGE3_PIXEL()
  17. See xmi.h for details on what they do. Ideally you should be able to
  18. #define those symbols appropriately, and never modify this file. */
  19. #include "sys-defines.h"
  20. #include "extern.h"
  21. #include "xmi.h"
  22. #include "mi_spans.h"
  23. #include "mi_api.h"
  24. /* forward references (these are currently used only in this file) */
  25. static miPixmap * miNewPixmap (unsigned int width, unsigned int height, miPixel initPixel);
  26. static miPixmap * miCopyPixmap (const miPixmap *pPixmap);
  27. static void miDeletePixmap (miPixmap *pPixmap);
  28. #if 0 /* not currently used, so commented out */
  29. static miBitmap * miNewBitmap (unsigned int width, unsigned int height, int initBit);
  30. #endif
  31. static miBitmap * miCopyBitmap (const miBitmap *pBitmap);
  32. static void miDeleteBitmap (miBitmap *pBitmap);
  33. static void miPaintCanvas (miCanvas *canvas, miPixel pixel, int n, const miPoint *ppt, const unsigned int *pwidth, miPoint offset);
  34. /* Ctor/dtor/copy ctor for the miCanvas class. These are defined only if
  35. the symbol MI_CANVAS_DRAWABLE_TYPE hasn't been defined by the libxmi
  36. installer. If it's defined, the drawable encapsulated within an
  37. miCanvas is presumably something other than a miPixmap, and we won't
  38. know how to create/destroy/copy miCanvas's. */
  39. #ifndef MI_CANVAS_DRAWABLE_TYPE
  40. /* create (allocate) a new miCanvas */
  41. miCanvas *
  42. miNewCanvas (unsigned int width, unsigned int height, miPixel initPixel)
  43. {
  44. miCanvas *new_pCanvas;
  45. if (width < 1 || height < 1)
  46. return (miCanvas *)NULL;
  47. new_pCanvas = (miCanvas *)mi_xmalloc (sizeof (miCanvas));
  48. new_pCanvas->drawable = miNewPixmap (width, height, initPixel);
  49. /* default values */
  50. new_pCanvas->texture = (miPixmap *)NULL;
  51. new_pCanvas->stipple = (miBitmap *)NULL;
  52. new_pCanvas->pixelMerge2 = (miPixelMerge2)NULL;
  53. new_pCanvas->pixelMerge3 = (miPixelMerge3)NULL;
  54. return new_pCanvas;
  55. }
  56. /* copy a miCanvas */
  57. miCanvas *
  58. miCopyCanvas (const miCanvas *pCanvas)
  59. {
  60. miCanvas *new_pCanvas;
  61. if (pCanvas == (const miCanvas *)NULL)
  62. return (miCanvas *)NULL;
  63. new_pCanvas = (miCanvas *)mi_xmalloc (sizeof (miCanvas));
  64. new_pCanvas->drawable = miCopyPixmap (pCanvas->drawable);
  65. new_pCanvas->pixelMerge2 = pCanvas->pixelMerge2;
  66. new_pCanvas->pixelMerge3 = pCanvas->pixelMerge3;
  67. new_pCanvas->texture = miCopyPixmap (pCanvas->texture);
  68. new_pCanvas->stipple = miCopyBitmap (pCanvas->stipple);
  69. return new_pCanvas;
  70. }
  71. /* destroy (deallocate) an miCanvas */
  72. void
  73. miDeleteCanvas (miCanvas *pCanvas)
  74. {
  75. if (pCanvas == (miCanvas *)NULL)
  76. return;
  77. miDeletePixmap (pCanvas->drawable);
  78. miDeletePixmap (pCanvas->texture);
  79. miDeleteBitmap (pCanvas->stipple);
  80. free (pCanvas);
  81. }
  82. #endif /* not MI_CANVAS_DRAWABLE_TYPE */
  83. /* create a new miPixmap, and fill it with a specified miPixel */
  84. static miPixmap *
  85. miNewPixmap (unsigned int width, unsigned int height, miPixel initPixel)
  86. {
  87. miPixmap *new_pPixmap;
  88. miPixel **pixmap;
  89. int i, j;
  90. new_pPixmap = (miPixmap *)mi_xmalloc (sizeof(miPixmap));
  91. /* create a pixmap (an array of pointers to rows of miPixels) */
  92. pixmap = (miPixel **)mi_xmalloc (height * sizeof(miPixel *));
  93. for (j = 0; j < (int)height; j++)
  94. {
  95. pixmap[j] = (miPixel *)mi_xmalloc (width * sizeof(miPixel));
  96. for (i = 0; i < (int)width; i++)
  97. pixmap[j][i] = initPixel;
  98. }
  99. new_pPixmap->pixmap = pixmap;
  100. new_pPixmap->width = width;
  101. new_pPixmap->height = height;
  102. return new_pPixmap;
  103. }
  104. /* copy a miPixmap */
  105. static miPixmap *
  106. miCopyPixmap (const miPixmap *pPixmap)
  107. {
  108. miPixmap *new_pPixmap;
  109. miPixel **pixmap;
  110. miPixel * const *old_pixmap;
  111. int i, j;
  112. if (pPixmap == (const miPixmap *)NULL)
  113. return (miPixmap *)NULL;
  114. new_pPixmap = (miPixmap *)mi_xmalloc (sizeof(miPixmap));
  115. /* create a pixmap (an array of pointers to rows of miPixels) */
  116. pixmap = (miPixel **)mi_xmalloc (pPixmap->height * sizeof(miPixel *));
  117. old_pixmap = pPixmap->pixmap;
  118. for (j = 0; j < (int)(pPixmap->height); j++)
  119. {
  120. pixmap[j] = (miPixel *)mi_xmalloc (pPixmap->width * sizeof(miPixel));
  121. for (i = 0; i < (int)(pPixmap->width); i++)
  122. pixmap[j][i] = old_pixmap[j][i];
  123. }
  124. new_pPixmap->pixmap = pixmap;
  125. new_pPixmap->width = pPixmap->width;
  126. new_pPixmap->height = pPixmap->height;
  127. return new_pPixmap;
  128. }
  129. /* destroy (deallocate) an miPixmap */
  130. static void
  131. miDeletePixmap (miPixmap *pPixmap)
  132. {
  133. int j;
  134. if (pPixmap == (miPixmap *)NULL)
  135. return;
  136. /* free pixmap (an array of pointers to rows of miPixels) */
  137. for (j = 0; j < (int)(pPixmap->height); j++)
  138. free (pPixmap->pixmap[j]);
  139. free (pPixmap->pixmap);
  140. free (pPixmap);
  141. }
  142. #if 0 /* not currently used, so commented out */
  143. /* create a new miBitmap, and fill it with a specified value (only 0 and 1
  144. are meaningful) */
  145. static miBitmap *
  146. miNewBitmap (unsigned int width, unsigned int height, int initBit)
  147. {
  148. miBitmap *new_pBitmap;
  149. int **bitmap;
  150. int i, j;
  151. new_pBitmap = (miBitmap *)mi_xmalloc (sizeof(miBitmap));
  152. /* create a bitmap (an array of pointers to rows of ints) */
  153. bitmap = (int **)mi_xmalloc (height * sizeof(int *));
  154. for (j = 0; j < (int)height; j++)
  155. {
  156. bitmap[j] = (int *)mi_xmalloc (width * sizeof(int));
  157. for (i = 0; i < (int)width; i++)
  158. bitmap[j][i] = initBit;
  159. }
  160. new_pBitmap->bitmap = bitmap;
  161. new_pBitmap->width = width;
  162. new_pBitmap->height = height;
  163. return new_pBitmap;
  164. }
  165. #endif
  166. /* copy a miBitmap */
  167. static miBitmap *
  168. miCopyBitmap (const miBitmap *pBitmap)
  169. {
  170. miBitmap *new_pBitmap;
  171. int **bitmap;
  172. int * const *old_bitmap;
  173. int i, j;
  174. if (pBitmap == (const miBitmap *)NULL)
  175. return (miBitmap *)NULL;
  176. new_pBitmap = (miBitmap *)mi_xmalloc (sizeof(miBitmap));
  177. /* create a bitmap (an array of pointers to rows of ints) */
  178. bitmap = (int **)mi_xmalloc (pBitmap->height * sizeof(int *));
  179. old_bitmap = pBitmap->bitmap;
  180. for (j = 0; j < (int)(pBitmap->height); j++)
  181. {
  182. bitmap[j] = (int *)mi_xmalloc (pBitmap->width * sizeof(int));
  183. for (i = 0; i < (int)(pBitmap->width); i++)
  184. bitmap[j][i] = old_bitmap[j][i];
  185. }
  186. new_pBitmap->bitmap = bitmap;
  187. new_pBitmap->width = pBitmap->width;
  188. new_pBitmap->height = pBitmap->height;
  189. return new_pBitmap;
  190. }
  191. /* destroy (deallocate) an miBitmap */
  192. static void
  193. miDeleteBitmap (miBitmap *pBitmap)
  194. {
  195. int j;
  196. if (pBitmap == (miBitmap *)NULL)
  197. return;
  198. /* free bitmap (an array of pointers to rows of ints) */
  199. for (j = 0; j < (int)(pBitmap->height); j++)
  200. free (pBitmap->bitmap[j]);
  201. free (pBitmap->bitmap);
  202. free (pBitmap);
  203. }
  204. /* set the binary pixel-merging function in an miCanvas */
  205. void
  206. miSetPixelMerge2 (miCanvas *pCanvas, miPixelMerge2 pixelMerge2)
  207. {
  208. if (pCanvas == (miCanvas *)NULL)
  209. return;
  210. pCanvas->pixelMerge2 = pixelMerge2;
  211. }
  212. /* set the ternary pixel-merging function in an miCanvas */
  213. void
  214. miSetPixelMerge3 (miCanvas *pCanvas, miPixelMerge3 pixelMerge3)
  215. {
  216. if (pCanvas == (miCanvas *)NULL)
  217. return;
  218. pCanvas->pixelMerge3 = pixelMerge3;
  219. }
  220. /* Copy a stipple miBitmap into an miCanvas. The old stipple, if any, is
  221. deallocated. */
  222. void
  223. miSetCanvasStipple (miCanvas *pCanvas, const miBitmap *pstipple, miPoint stippleOrigin)
  224. {
  225. if (pCanvas == (miCanvas *)NULL)
  226. return;
  227. miDeleteBitmap (pCanvas->stipple);
  228. pCanvas->stipple = miCopyBitmap (pstipple);
  229. pCanvas->stippleOrigin = stippleOrigin;
  230. }
  231. /* Copy a texture miPixmap into an miCanvas. The old texture, if any, is
  232. deallocated. */
  233. void
  234. miSetCanvasTexture (miCanvas *pCanvas, const miPixmap *pTexture, miPoint textureOrigin)
  235. {
  236. if (pCanvas == (miCanvas *)NULL)
  237. return;
  238. miDeletePixmap (pCanvas->texture);
  239. pCanvas->texture = miCopyPixmap (pTexture);
  240. pCanvas->textureOrigin = textureOrigin;
  241. }
  242. /* Paint a list of spans, in a specified miPixel color, to a canvas. The
  243. spans must be in y-increasing order. */
  244. /* ARGS: canvas = canvas
  245. pixel = source pixel color
  246. n = number of spans to be painted
  247. ppt = array of starting points of spans
  248. pwidth = array of widths of spans
  249. offset = point that (0,0) gets mapped to */
  250. static void
  251. miPaintCanvas (miCanvas *canvas, miPixel pixel, int n, const miPoint *ppt, const unsigned int *pwidth, miPoint offset)
  252. {
  253. int i;
  254. int xleft, xright, ybottom, ytop;
  255. unsigned int stippleWidth = 0, stippleHeight = 0; /* keep lint happy */
  256. unsigned int textureWidth = 0, textureHeight = 0; /* keep lint happy */
  257. int stippleXOrigin = 0, stippleYOrigin = 0; /* keep lint happy */
  258. int textureXOrigin = 0, textureYOrigin = 0; /* keep lint happy */
  259. int xstart, xend, xstart_clip, xend_clip, xoffset, yoffset, x, y;
  260. unsigned int width;
  261. const miCanvas *pCanvas; /* `const' should be OK here */
  262. miPixelMerge2 pixelMerge2;
  263. miPixelMerge3 pixelMerge3;
  264. pCanvas = canvas;
  265. xoffset = offset.x;
  266. yoffset = offset.y;
  267. /* compute bounds of destination drawable */
  268. MI_GET_CANVAS_DRAWABLE_BOUNDS(pCanvas, xleft, ytop, xright, ybottom)
  269. /* if source doesn't overlap with destination drawable, do nothing */
  270. if (ppt[0].y + yoffset > ybottom || ppt[n-1].y + yoffset < ytop)
  271. return;
  272. /* determine user-specified merging functions (if any) */
  273. pixelMerge2 = pCanvas->pixelMerge2;
  274. pixelMerge3 = pCanvas->pixelMerge3;
  275. #define MI_MERGE_CANVAS_PIXEL(pCanvas, x, y, sourcePixel, texturePixel, have_texturePixel) \
  276. { \
  277. miPixel destinationPixel, newPixel; \
  278. MI_GET_CANVAS_DRAWABLE_PIXEL((pCanvas), (x), (y), destinationPixel); \
  279. if (!have_texturePixel) \
  280. { \
  281. if (pixelMerge2 != (miPixelMerge2)NULL) \
  282. newPixel = (*pixelMerge2)((sourcePixel), destinationPixel); \
  283. else \
  284. MI_DEFAULT_MERGE2_PIXEL(newPixel, (sourcePixel), destinationPixel); \
  285. } \
  286. else \
  287. { \
  288. if (pixelMerge3 != (miPixelMerge3)NULL) \
  289. newPixel = (*pixelMerge3)((texturePixel), (sourcePixel), destinationPixel); \
  290. else \
  291. MI_DEFAULT_MERGE3_PIXEL(newPixel, (texturePixel), (sourcePixel), destinationPixel); \
  292. } \
  293. MI_SET_CANVAS_DRAWABLE_PIXEL((pCanvas), (x), (y), newPixel); \
  294. }
  295. if (pCanvas->stipple)
  296. {
  297. stippleWidth = pCanvas->stipple->width;
  298. stippleHeight = pCanvas->stipple->height;
  299. stippleXOrigin = pCanvas->stippleOrigin.x;
  300. stippleYOrigin = pCanvas->stippleOrigin.y;
  301. while (stippleXOrigin > 0)
  302. stippleXOrigin -= stippleWidth;
  303. while (stippleYOrigin > 0)
  304. stippleYOrigin -= stippleHeight;
  305. }
  306. if (pCanvas->texture)
  307. {
  308. textureWidth = pCanvas->texture->width;
  309. textureHeight = pCanvas->texture->height;
  310. textureXOrigin = pCanvas->textureOrigin.x;
  311. textureYOrigin = pCanvas->textureOrigin.y;
  312. while (textureXOrigin > 0)
  313. textureXOrigin -= textureWidth;
  314. while (textureYOrigin > 0)
  315. textureYOrigin -= textureHeight;
  316. }
  317. for (i = 0; i < n; i++)
  318. {
  319. y = ppt[i].y + yoffset;
  320. if (y > ybottom)
  321. return; /* no more spans will be painted */
  322. if (y >= ytop)
  323. {
  324. width = pwidth[i];
  325. xstart = ppt[i].x + xoffset;
  326. xend = xstart + (int)width - 1;
  327. xstart_clip = IMAX(xstart,xleft);
  328. xend_clip = IMIN(xend,xright);
  329. for (x = xstart_clip; x <= xend_clip; x++) /* may be empty */
  330. /* merge pixel onto canvas */
  331. {
  332. miPixel texturePixel, sourcePixel;
  333. bool have_texturePixel = false;
  334. if (pCanvas->texture)
  335. {
  336. texturePixel = pCanvas->texture->pixmap[(y-textureYOrigin) % textureHeight][(x-textureXOrigin) % textureWidth];
  337. have_texturePixel = true;
  338. }
  339. else
  340. texturePixel = pixel; /* dummy; keep lint happy */
  341. sourcePixel = pixel;
  342. if (pCanvas->stipple == (miBitmap *)NULL
  343. || pCanvas->stipple->bitmap[(y-stippleYOrigin) % stippleHeight][(x-stippleXOrigin) % stippleWidth] != 0)
  344. MI_MERGE_CANVAS_PIXEL(pCanvas, x, y, sourcePixel, texturePixel, have_texturePixel)
  345. } /* end for x in ... */
  346. } /* end if */
  347. } /* end for y in ... */
  348. }
  349. /* Copy a miPaintedSet to an miCanvas. The miPaintedSet is assumed to have
  350. been uniquified (see mi_spans.c), which is the case after any of the
  351. eight core drawing functions in the libxmi API has been invoked. So
  352. there is at most one Spans per SpanGroup (i.e., Spans #0), and copying
  353. pixels out of it trivial. */
  354. /* ARGS: offset = point that (0,0) is mapped to */
  355. void
  356. miCopyPaintedSetToCanvas (const miPaintedSet *paintedSet, miCanvas *canvas, miPoint offset)
  357. {
  358. int i;
  359. /* For each pixel color, the initial Spans in the corresponding SpanGroup
  360. is effectively a list of spans, in y-increasing order. That is, it's
  361. a list of starting points and a corresponding list of widths; both are
  362. of length `count'. */
  363. for (i = 0; i < paintedSet->ngroups; i++)
  364. if (paintedSet->groups[i]->group[0].count > 0)
  365. miPaintCanvas (canvas, paintedSet->groups[i]->pixel,
  366. paintedSet->groups[i]->group[0].count,
  367. paintedSet->groups[i]->group[0].points,
  368. paintedSet->groups[i]->group[0].widths, offset);
  369. }