summaryrefslogtreecommitdiff
path: root/src/drv/cdirgb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drv/cdirgb.c')
-rw-r--r--src/drv/cdirgb.c2135
1 files changed, 2135 insertions, 0 deletions
diff --git a/src/drv/cdirgb.c b/src/drv/cdirgb.c
new file mode 100644
index 0000000..9fbb540
--- /dev/null
+++ b/src/drv/cdirgb.c
@@ -0,0 +1,2135 @@
+/** \file
+ * \brief Image RGB Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cd_truetype.h"
+#include "sim.h"
+#include "cdirgb.h"
+
+
+struct _cdCtxImage
+{
+ int w, h;
+ unsigned char* red; /* red color buffer */
+ unsigned char* green; /* green color buffer */
+ unsigned char* blue; /* blue color buffer */
+ unsigned char* alpha; /* alpha color buffer */
+};
+
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ int user_image; /* can not free an user image */
+
+ unsigned char* red; /* red color buffer */
+ unsigned char* green; /* green color buffer */
+ unsigned char* blue; /* blue color buffer */
+ unsigned char* alpha; /* alpha color buffer */
+ unsigned char* clip; /* clipping buffer */
+
+ unsigned char* clip_region; /* clipping region used during NewRegion */
+
+ float rotate_angle;
+ int rotate_center_x,
+ rotate_center_y;
+
+ cdCanvas* canvas_dbuffer; /* used by the CD_DBUFFERRGB driver */
+};
+
+/*******************/
+/* Local functions */
+/*******************/
+
+#define _sNormX(_ctxcanvas, _x) (_x < 0? 0: _x < _ctxcanvas->canvas->w? _x: _ctxcanvas->canvas->w-1)
+#define _sNormY(_ctxcanvas, _y) (_y < 0? 0: _y < _ctxcanvas->canvas->h? _y: _ctxcanvas->canvas->h-1)
+
+#define RGBA_COMPOSE(_SRC, _SRC_ALPHA, _DST, _TMP_MULTI, _TMP_ALPHA) (unsigned char)(((_SRC_ALPHA)*(_SRC) + (_TMP_MULTI)*(_DST)) / (_TMP_ALPHA))
+
+#define RGBA_COLOR_COMBINE(_ctxcanvas, _pdst_red, _pdst_green, _pdst_blue, _pdst_alpha, _src_red, _src_green, _src_blue, _src_alpha) \
+{ \
+ unsigned char _tmp_red = 0, _tmp_green = 0, _tmp_blue = 0; \
+ \
+ if (_pdst_alpha) /* (_pdst_alpha != NULL) */ \
+ { \
+ if (_src_alpha != 255) /* some transparency */ \
+ { \
+ if (_src_alpha != 0) /* source not full transparent */ \
+ { \
+ if (*_pdst_alpha == 0) /* destiny full transparent */ \
+ { \
+ _tmp_red = _src_red; \
+ _tmp_green = _src_green; \
+ _tmp_blue = _src_blue; \
+ *_pdst_alpha = _src_alpha; \
+ } \
+ else if (*_pdst_alpha == 255) /* destiny opaque */ \
+ { \
+ _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \
+ _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \
+ _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \
+ /* *_pdst_alpha is not changed */ \
+ } \
+ else /* (0<*_pdst_alpha<255 && 0<_src_alpha<255) destiny and source are semi-transparent */ \
+ { \
+ /* Closed Compositing Formulas for SRC over DST, Colors Not Premultiplied by Alpha: */ \
+ int _tmp_multi = *_pdst_alpha * (255 - _src_alpha); \
+ int _tmp_alpha = _src_alpha + _tmp_multi; \
+ _tmp_red = RGBA_COMPOSE(_src_red, _src_alpha, *_pdst_red, _tmp_multi, _tmp_alpha); \
+ _tmp_green = RGBA_COMPOSE(_src_green, _src_alpha, *_pdst_green, _tmp_multi, _tmp_alpha); \
+ _tmp_blue = RGBA_COMPOSE(_src_blue, _src_alpha, *_pdst_blue, _tmp_multi, _tmp_alpha); \
+ *_pdst_alpha = (unsigned char)(_tmp_alpha / 255); \
+ } \
+ } \
+ else /* (_src_alpha == 0) source full transparent */ \
+ { \
+ _tmp_red = *_pdst_red; \
+ _tmp_green = *_pdst_green; \
+ _tmp_blue = *_pdst_blue; \
+ /* *_pdst_alpha is not changed */ \
+ } \
+ } \
+ else /* (_src_alpha == 255) source has no alpha = opaque */ \
+ { \
+ _tmp_red = _src_red; \
+ _tmp_green = _src_green; \
+ _tmp_blue = _src_blue; \
+ *_pdst_alpha = (unsigned char)255; /* set destiny as opaque */ \
+ } \
+ } \
+ else /* (_pdst_alpha == NULL) */ \
+ { \
+ if (_src_alpha != 255) /* source has some transparency */ \
+ { \
+ if (_src_alpha != 0) /* source semi-transparent */ \
+ { \
+ _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \
+ _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \
+ _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \
+ } \
+ else /* (_src_alpha == 0) source full transparent */ \
+ { \
+ _tmp_red = *_pdst_red; \
+ _tmp_green = *_pdst_green; \
+ _tmp_blue = *_pdst_blue; \
+ } \
+ } \
+ else /* (_src_alpha == 255) source has no alpha = opaque */ \
+ { \
+ _tmp_red = _src_red; \
+ _tmp_green = _src_green; \
+ _tmp_blue = _src_blue; \
+ } \
+ } \
+ \
+ switch (_ctxcanvas->canvas->write_mode) \
+ { \
+ case CD_REPLACE: \
+ *_pdst_red = _tmp_red; \
+ *_pdst_green = _tmp_green; \
+ *_pdst_blue = _tmp_blue; \
+ break; \
+ case CD_XOR: \
+ *_pdst_red ^= _tmp_red; \
+ *_pdst_green ^= _tmp_green; \
+ *_pdst_blue ^= _tmp_blue; \
+ break; \
+ case CD_NOT_XOR: \
+ *_pdst_red = (unsigned char)~(_tmp_red ^ *_pdst_red); \
+ *_pdst_green = (unsigned char)~(_tmp_green ^ *_pdst_green); \
+ *_pdst_blue = (unsigned char)~(_tmp_blue ^ *_pdst_blue); \
+ break; \
+ } \
+}
+
+static void sCombineRGBColor(cdCtxCanvas* ctxcanvas, int offset, long color)
+{
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+
+ unsigned char sr = cdRed(color);
+ unsigned char sg = cdGreen(color);
+ unsigned char sb = cdBlue(color);
+ unsigned char sa = cdAlpha(color);
+
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa);
+}
+
+static void sCombineRGB(cdCtxCanvas* ctxcanvas, int offset, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa)
+{
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa);
+}
+
+static void sCombineRGBLine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, int size)
+{
+ int c;
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+ unsigned char src_a = 255;
+
+ if (size > 0)
+ {
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a);
+ dr++; dg++; db++; clip++;
+ sr++; sg++; sb++;
+ if (da) da++;
+ }
+ }
+ else
+ {
+ size *= -1;
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a);
+ dr--; dg--; db--; clip--;
+ sr--; sg--; sb--;
+ if (da) da--;
+ }
+ }
+}
+
+static void sCombineRGBALine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, const unsigned char *sa, int size)
+{
+ int c;
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+
+ if (size > 0)
+ {
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa);
+ dr++; dg++; db++; clip++;
+ sr++; sg++; sb++; sa++;
+ if (da) da++;
+ }
+ }
+ else
+ {
+ size *= -1;
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa);
+ dr--; dg--; db--; clip--;
+ sr--; sg--; sb--; sa--;
+ if (da) da--;
+ }
+ }
+}
+
+static void irgbSolidLine(cdCanvas* canvas, int xmin, int y, int xmax)
+{
+ int x;
+ unsigned long offset = y * canvas->w;
+
+ if (y < 0)
+ return;
+
+ if (y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ for (x = xmin; x <= xmax; x++)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground);
+}
+
+static void irgbPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern)
+{
+ int x, i;
+ unsigned long offset = y * canvas->w;
+
+ if (y < 0 || y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ i = xmin % pw;
+
+ for (x = xmin; x <= xmax; x++,i++)
+ {
+ if (i == pw)
+ i = 0;
+
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, pattern[i]);
+ }
+}
+
+static void irgbStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple)
+{
+ int x,i;
+ unsigned long offset = y * canvas->w;
+
+ if (y < 0 || y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ i = xmin % pw;
+
+ for (x = xmin; x <= xmax; x++,i++)
+ {
+ if (i == pw)
+ i = 0;
+ if(stipple[i])
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground);
+ else if (canvas->back_opacity == CD_OPAQUE)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background);
+ }
+}
+
+static void irgbHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch)
+{
+ int x;
+ unsigned long offset = y * canvas->w;
+ unsigned char n;
+
+ if (y < 0 || y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ n = (unsigned char)(xmin&7);
+ simRotateHatchN(hatch, n);
+
+ for (x = xmin; x <= xmax; x++)
+ {
+ if (hatch & 0x80)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground);
+ else if (canvas->back_opacity == CD_OPAQUE)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background);
+
+ _cdRotateHatch(hatch);
+ }
+}
+
+/********************/
+/* driver functions */
+/********************/
+
+static void cdkillcanvas(cdCtxCanvas* ctxcanvas)
+{
+ if (!ctxcanvas->user_image)
+ free(ctxcanvas->red);
+
+ if (ctxcanvas->clip_region)
+ free(ctxcanvas->clip_region);
+
+ free(ctxcanvas->clip);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+unsigned char* cdAlphaImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->alpha;
+}
+
+unsigned char* cdRedImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->red;
+}
+
+unsigned char* cdGreenImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->green;
+}
+
+unsigned char* cdBlueImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->blue;
+}
+
+static void cdclear(cdCtxCanvas* ctxcanvas)
+{
+ int size = ctxcanvas->canvas->w * ctxcanvas->canvas->h;
+ memset(ctxcanvas->red, cdRed(ctxcanvas->canvas->background), size);
+ memset(ctxcanvas->green, cdGreen(ctxcanvas->canvas->background), size);
+ memset(ctxcanvas->blue, cdBlue(ctxcanvas->canvas->background), size);
+ if (ctxcanvas->alpha) memset(ctxcanvas->alpha, cdAlpha(ctxcanvas->canvas->background), size);
+}
+
+static void irgPostProcessIntersect(unsigned char* clip, int size)
+{
+ int i;
+ for(i = 0; i < size; i++)
+ {
+ if (*clip == 2)
+ *clip = 1;
+ else
+ *clip = 0;
+
+ clip++;
+ }
+}
+
+#define _irgSetClipPixel(_clip, _combine_mode) \
+{ \
+ switch (_combine_mode) \
+ { \
+ case CD_INTERSECT: \
+ if (_clip) \
+ _clip = 2; /* fills the intersection \
+ with a value to be post-processed */ \
+ break; \
+ case CD_DIFFERENCE: \
+ if (_clip) \
+ _clip = 0; /* clears the intersection */ \
+ break; \
+ case CD_NOTINTERSECT: /* XOR */ \
+ if (_clip) \
+ _clip = 0; /* clears the intersection */ \
+ else \
+ _clip = 1; /* fills the region */ \
+ break; \
+ default: /* CD_UNION */ \
+ _clip = 1; /* fills the region */ \
+ break; \
+ } \
+}
+
+static void irgbClipTextBitmap(FT_Bitmap* bitmap, int x, int y, int w, unsigned char* clip, int combine_mode)
+{
+ unsigned char *bitmap_data;
+ int width = bitmap->width;
+ int height = bitmap->rows;
+ int i, j;
+
+ /* avoid spaces */
+ if (width == 0 || height == 0)
+ return;
+
+ bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */
+
+ clip += y * w + x;
+
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ if (bitmap_data[j] == 255)
+ _irgSetClipPixel(clip[j], combine_mode);
+ }
+ clip += w;
+ bitmap_data -= width;
+ }
+}
+
+static void irgbClipText(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ cdCanvas* canvas = ctxcanvas->canvas;
+ cdSimulation* simulation = canvas->simulation;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ FT_Matrix matrix; /* transformation matrix */
+ FT_Vector pen; /* untransformed origin */
+ FT_Error error;
+
+ if (!simulation->tt_text->face)
+ return;
+
+ face = simulation->tt_text->face;
+ slot = face->glyph;
+
+ /* move the reference point to the baseline-left */
+ simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen);
+
+ while(*s)
+ {
+ /* set transformation */
+ FT_Set_Transform(face, &matrix, &pen);
+
+ /* load glyph image into the slot (erase previous one) */
+ error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER);
+ if (error) {s++; continue;} /* ignore errors */
+
+ x = slot->bitmap_left;
+ y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */
+
+ /* now, draw to our target surface (convert position) */
+ irgbClipTextBitmap(&slot->bitmap, x, y, canvas->w, ctxcanvas->clip_region, canvas->combine_mode);
+
+ /* increment pen position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ s++;
+ }
+
+ if (canvas->combine_mode == CD_INTERSECT)
+ irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static void irgbClipFillLine(unsigned char* clip_line, int combine_mode, int x1, int x2, int width)
+{
+ int x;
+ if (x1 < 0) x1 = 0;
+ if (x2 > width-1) x2 = width-1;
+ for (x = x1; x <= x2; x++)
+ {
+ _irgSetClipPixel(clip_line[x], combine_mode);
+ }
+}
+
+static int compare_int(const int* xx1, const int* xx2)
+{
+ return *xx1 - *xx2;
+}
+
+static void irgbClipPoly(cdCtxCanvas* ctxcanvas, unsigned char* clip_region, cdPoint* poly, int n, int combine_mode)
+{
+ cdCanvas* canvas = ctxcanvas->canvas;
+ unsigned char* clip_line;
+ simLineSegment *seg_i;
+ cdPoint* t_poly = NULL;
+ int y_max, y_min, i, y, i1, fill_mode, num_lines,
+ inter_count, width, height;
+
+ int *xx = (int*)malloc((n+1)*sizeof(int));
+ simLineSegment *segment = (simLineSegment *)malloc(n*sizeof(simLineSegment));
+
+ if (canvas->use_matrix)
+ {
+ t_poly = malloc(sizeof(cdPoint)*n);
+ memcpy(t_poly, poly, sizeof(cdPoint)*n);
+ poly = t_poly;
+
+ for(i = 0; i < n; i++)
+ cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y);
+ }
+
+ width = canvas->w;
+ height = canvas->h;
+ fill_mode = canvas->fill_mode;
+
+ y_max = poly[0].y;
+ y_min = poly[0].y;
+ for(i = 0; i < n; i++)
+ {
+ i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */
+ simAddSegment(segment+i, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y, &y_max, &y_min);
+ }
+
+ if (y_min < 0)
+ y_min = 0;
+
+ if (y_max > height-1)
+ num_lines = height-y_min;
+ else
+ num_lines = y_max-y_min+1;
+
+ /* for all horizontal lines between y_max and y_min */
+ for(y = y_max; y >= y_min; y--)
+ {
+ inter_count = 0;
+
+ /* for all segments, calculates the intervals to be filled. */
+ for(i = 0; i < n; i++)
+ {
+ seg_i = segment + i;
+
+ /* if the minimum Y coordinate of the segment is greater than the current y, then ignore the segment. */
+ /* if it is an horizontal line, then ignore the segment. */
+ if (seg_i->y1 > y ||
+ seg_i->y1 == seg_i->y2)
+ continue;
+
+ if (y == seg_i->y1) /* intersection at the start point (x1,y1) */
+ {
+ int i_next = (i==n-1)? 0: i+1;
+ int i_prev = (i==0)? n-1: i-1;
+ simLineSegment *seg_i_next = segment + i_next;
+ simLineSegment *seg_i_prev = segment + i_prev;
+
+ /* always save at least one intersection point for (y1) */
+
+ xx[inter_count++] = seg_i->x1; /* save the intersection point */
+
+ /* check for missing bottom-corner points (|_|), must duplicate the intersection */
+ if ((seg_i_next->y1 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */
+ (seg_i_prev->y1 == y && seg_i_prev->y2 == seg_i_prev->y1)) /* previous is an horizontal line */
+ {
+ xx[inter_count++] = seg_i->x1; /* save the intersection point */
+ }
+ }
+ else if ((y > seg_i->y1) && (y < seg_i->y2)) /* intersection inside the segment, do not include y2 */
+ {
+ xx[inter_count++] = simSegmentInc(seg_i, canvas, y); /* save the intersection point */
+ }
+ else if (y == seg_i->y2) /* intersection at the end point (x2,y2) */
+ {
+ int i_next = (i==n-1)? 0: i+1;
+ int i_prev = (i==0)? n-1: i-1;
+ simLineSegment *seg_i_next = segment + i_next;
+ simLineSegment *seg_i_prev = segment + i_prev;
+
+ /* only save the intersection point for (y2) if not handled by (y1) of another segment */
+
+ /* check for missing top-corner points (^) or (|ŻŻ|) */
+ if ((seg_i_next->y2 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */
+ (seg_i_prev->y2 == y && seg_i_prev->y2 == seg_i_prev->y1) || /* previous is an horizontal line */
+ (seg_i_next->y2 == y && seg_i_next->x2 == seg_i->x2 && seg_i_next->x1 != seg_i->x1) ||
+ (seg_i_prev->y2 == y && seg_i_prev->x2 == seg_i->x2 && seg_i_prev->x1 != seg_i->x1))
+ {
+ xx[inter_count++] = seg_i->x2; /* save the intersection point */
+ }
+ }
+ }
+
+ /* if outside the canvas, ignore the intervals and */
+ /* continue since the segments where updated. */
+ if (y > height-1 || inter_count == 0)
+ continue;
+
+ /* sort the intervals */
+ qsort(xx, inter_count, sizeof(int), (int (*)(const void*,const void*))compare_int);
+
+ clip_line = clip_region + y*width;
+
+ /* for all intervals, fill the interval */
+ for(i = 0; i < inter_count; i += 2)
+ {
+ if (fill_mode == CD_EVENODD)
+ {
+ /* since it fills only pairs of intervals, */
+ /* it is the EVENODD fill rule. */
+ irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width);
+ }
+ else
+ {
+ irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width);
+ if ((i+2 < inter_count) && (xx[i+1] < xx[i+2])) /* avoid point intervals */
+ if (simIsPointInPolyWind(poly, n, (xx[i+1]+xx[i+2])/2, y)) /* if the next interval is inside the polygon then fill it */
+ irgbClipFillLine(clip_line, combine_mode, xx[i+1], xx[i+2], width);
+ }
+ }
+ }
+
+ if (t_poly) free(t_poly);
+ free(xx);
+ free(segment);
+
+ if (combine_mode == CD_INTERSECT)
+ irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static void irgbClipElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector)
+{
+ float c, s, sx, sy, x, y, prev_x, prev_y;
+ double da;
+ int i, p;
+ cdPoint* poly;
+
+ /* number of segments of equivalent poligonal for a full ellipse */
+ int n = simCalcEllipseNumSegments(ctxcanvas->canvas, xc, yc, width, height);
+
+ /* number of segments for the arc */
+ n = cdRound((fabs(angle2-angle1)*n)/360);
+ if (n < 1) n = 1;
+
+ poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */
+
+ /* converts degrees into radians */
+ angle1 *= CD_DEG2RAD;
+ angle2 *= CD_DEG2RAD;
+
+ /* generates arc points at origin with axis x and y */
+
+ da = (angle2-angle1)/n;
+ c = (float)cos(da);
+ s = (float)sin(da);
+ sx = -(width*s)/height;
+ sy = (height*s)/width;
+
+ x = xc + (width/2.0f)*(float)cos(angle1);
+ y = yc + (height/2.0f)*(float)sin(angle1);
+ poly[0].x = _cdRound(x);
+ poly[0].y = _cdRound(y);
+ prev_x = x;
+ prev_y = y;
+ p = 1;
+
+ for (i = 1; i < n+1; i++) /* n+1 points */
+ {
+ x = xc + c*(prev_x-xc) + sx*(prev_y-yc);
+ y = yc + sy*(prev_x-xc) + c*(prev_y-yc);
+
+ poly[p].x = _cdRound(x);
+ poly[p].y = _cdRound(y);
+
+ if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y)
+ p++;
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y)
+ {
+ if (sector) /* cdSector */
+ {
+ /* add center */
+ poly[p].x = xc;
+ poly[p].y = yc;
+ }
+ else /* cdChord */
+ {
+ /* add initial point */
+ poly[p].x = poly[0].x;
+ poly[p].y = poly[0].y;
+ }
+ p++;
+ }
+
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, p, ctxcanvas->canvas->combine_mode);
+
+ free(poly);
+}
+
+static void irgbClipBox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ int combine_mode = ctxcanvas->canvas->combine_mode;
+ unsigned char* clip_line;
+ int x, y, width;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdPoint poly[4];
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, 4, ctxcanvas->canvas->combine_mode);
+ return;
+ }
+
+ xmin = _sNormX(ctxcanvas, xmin);
+ ymin = _sNormY(ctxcanvas, ymin);
+ xmax = _sNormX(ctxcanvas, xmax);
+ ymax = _sNormY(ctxcanvas, ymax);
+ width = ctxcanvas->canvas->w;
+
+ for(y = ymin; y <= ymax; y++)
+ {
+ clip_line = ctxcanvas->clip_region + y*width;
+ for(x = xmin; x <= xmax; x++)
+ {
+ _irgSetClipPixel(clip_line[x], combine_mode);
+ }
+ }
+
+ if (combine_mode == CD_INTERSECT)
+ irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static void irgbClipArea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ unsigned char* clip_line = ctxcanvas->clip; /* set directly to clip */
+ int y, xsize, ysize, height, width, xrigth;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdPoint poly[4];
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, 4, CD_UNION);
+ return;
+ }
+
+ xmin = _sNormX(ctxcanvas, xmin);
+ ymin = _sNormY(ctxcanvas, ymin);
+ xmax = _sNormX(ctxcanvas, xmax);
+ ymax = _sNormY(ctxcanvas, ymax);
+ xsize = xmax-xmin+1;
+ ysize = ymax-ymin+1;
+ height = ctxcanvas->canvas->h;
+ width = ctxcanvas->canvas->w;
+ xrigth = width-(xmax+1);
+
+ for(y = 0; y < ymin; y++)
+ {
+ memset(clip_line, 0, width);
+ clip_line += width;
+ }
+
+ for(y = ymin; y <= ymax; y++)
+ {
+ if (xmin)
+ memset(clip_line, 0, xmin);
+
+ memset(clip_line+xmin, 1, xsize);
+
+ if (xrigth)
+ memset(clip_line+xmax+1, 0, xrigth);
+
+ clip_line += width;
+ }
+
+ for(y = ymax+1; y < height; y++)
+ {
+ memset(clip_line, 0, width);
+ clip_line += width;
+ }
+}
+
+static int cdclip(cdCtxCanvas* ctxcanvas, int mode)
+{
+ switch(mode)
+ {
+ case CD_CLIPAREA:
+ irgbClipArea(ctxcanvas, ctxcanvas->canvas->clip_rect.xmin,
+ ctxcanvas->canvas->clip_rect.xmax,
+ ctxcanvas->canvas->clip_rect.ymin,
+ ctxcanvas->canvas->clip_rect.ymax);
+ break;
+ case CD_CLIPPOLYGON:
+ memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip, ctxcanvas->canvas->clip_poly, ctxcanvas->canvas->clip_poly_n, CD_UNION);
+ break;
+ case CD_CLIPREGION:
+ if (ctxcanvas->clip_region)
+ memcpy(ctxcanvas->clip, ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ break;
+ default:
+ memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */
+ break;
+ }
+
+ return mode;
+}
+
+static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
+ irgbClipArea(ctxcanvas, xmin, xmax, ymin, ymax);
+}
+
+static void cdnewregion(cdCtxCanvas* ctxcanvas)
+{
+ if (ctxcanvas->clip_region)
+ free(ctxcanvas->clip_region);
+ ctxcanvas->clip_region = malloc(ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ memset(ctxcanvas->clip_region, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->clip_region)
+ return 0;
+
+ if (x >= 0 && y >= 0 && x < ctxcanvas->canvas->w && y < ctxcanvas->canvas->h)
+ {
+ if (ctxcanvas->clip_region[y*ctxcanvas->canvas->w + x])
+ return 1;
+ }
+
+ return 0;
+}
+
+static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int dx, int dy)
+{
+ unsigned char* clip_region = ctxcanvas->clip_region;
+ int x, y, X, Y, old_X, old_Y, width, height;
+
+ if (!ctxcanvas->clip_region)
+ return;
+
+ height = ctxcanvas->canvas->h;
+ width = ctxcanvas->canvas->w;
+
+ for (y = 0; y < height; y++)
+ {
+ if (dy > 0)
+ Y = height-1 - y;
+ else
+ Y = y;
+ old_Y = Y - dy;
+ for(x = 0; x < width; x++)
+ {
+ if (dx > 0)
+ X = width-1 - x;
+ else
+ X = x;
+ old_X = X - dx;
+
+ if (old_X >= 0 && old_Y >= 0 && old_Y < height && old_X < width)
+ clip_region[Y*width + X] = clip_region[old_Y*width + old_X];
+ else
+ clip_region[Y*width + X] = 0;
+ }
+ }
+}
+
+static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax)
+{
+ unsigned char* clip_line = ctxcanvas->clip_region;
+ int x, y, width, height;
+
+ if (!ctxcanvas->clip_region)
+ return;
+
+ *xmin = ctxcanvas->canvas->w-1;
+ *xmax = 0;
+ *ymin = ctxcanvas->canvas->h-1;
+ *ymax = 0;
+ height = ctxcanvas->canvas->h;
+ width = ctxcanvas->canvas->w;
+
+ for (y = 0; y < height; y++)
+ {
+ for(x = 0; x < width; x++)
+ {
+ if (*clip_line)
+ {
+ if (x < *xmin)
+ *xmin = x;
+ if (y < *ymin)
+ *ymin = y;
+ if (x > *xmax)
+ *xmax = x;
+ if (y > *ymax)
+ *ymax = y;
+ }
+
+ clip_line++;
+ }
+ }
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipBox(ctxcanvas, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax);
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1);
+ return;
+ }
+
+ cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0);
+ return;
+ }
+
+ cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipText(ctxcanvas, x, y, s);
+ return;
+ }
+
+ cdtextSIM(ctxcanvas, x, y, s);
+}
+
+static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, n, ctxcanvas->canvas->combine_mode);
+ return;
+ }
+
+ if (mode == CD_CLIP)
+ {
+ /* set directly to clip */
+ memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, n, CD_UNION);
+ }
+ else
+ cdpolySIM(ctxcanvas, mode, poly, n);
+}
+
+static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h)
+{
+ int dst_offset, src_offset, l, xsize, ysize, xpos, ypos;
+ unsigned char *src_red, *src_green, *src_blue;
+
+ if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h ||
+ x + w < 0 || y + h < 0)
+ return;
+
+ /* ajusta parametros de entrada */
+ xpos = _sNormX(ctxcanvas, x);
+ ypos = _sNormY(ctxcanvas, y);
+
+ xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos;
+ ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos;
+
+ /* ajusta posicao inicial em source */
+ src_offset = xpos + ypos * ctxcanvas->canvas->w;
+ src_red = ctxcanvas->red + src_offset;
+ src_green = ctxcanvas->green + src_offset;
+ src_blue = ctxcanvas->blue + src_offset;
+
+ /* offset para source */
+ src_offset = ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = (xpos - x) + (ypos - y) * w;
+ r += dst_offset;
+ g += dst_offset;
+ b += dst_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ memcpy(r, src_red, xsize);
+ memcpy(g, src_green, xsize);
+ memcpy(b, src_blue, xsize);
+
+ src_red += src_offset;
+ src_green += src_offset;
+ src_blue += src_offset;
+
+ r += w;
+ g += w;
+ b += w;
+ }
+}
+
+static void cdputimagerectrgba_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int t_xmin, t_xmax, t_ymin, t_ymax,
+ t_x, t_y, img_topdown = 0, dst_offset;
+ float i_x, i_y, xfactor, yfactor;
+ unsigned char sr, sg, sb, sa = 255;
+ double inv_matrix[6];
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* calculate the destination limits */
+ cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL);
+
+ /* Setup inverse transform */
+ cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix);
+
+ /* for all pixels in the destiny area */
+ for(t_y = t_ymin; t_y <= t_ymax; t_y++)
+ {
+ dst_offset = t_y * ctxcanvas->canvas->w;
+
+ for(t_x = t_xmin; t_x <= t_xmax; t_x++)
+ {
+ cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix);
+
+ if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1)
+ {
+ if (img_topdown) /* image is top-bottom */
+ i_y = ih-1 - i_y;
+
+ if (t_x == 350 && t_y == 383)
+ t_x = 350;
+
+ sr = cdBilinearInterpolation(iw, ih, r, i_x, i_y);
+ sg = cdBilinearInterpolation(iw, ih, g, i_x, i_y);
+ sb = cdBilinearInterpolation(iw, ih, b, i_x, i_y);
+ if (a) sa = cdBilinearInterpolation(iw, ih, a, i_x, i_y);
+
+ if (sr > 210 && sg > 210 && sb > 210)
+ sr = sr;
+
+ sCombineRGB(ctxcanvas, t_x + dst_offset, sr, sg, sb, sa);
+ }
+ }
+ }
+}
+
+static void cdputimagerectmap_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int t_xmin, t_xmax, t_ymin, t_ymax,
+ t_x, t_y, img_topdown = 0, dst_offset;
+ float i_x, i_y, xfactor, yfactor;
+ unsigned char si;
+ double inv_matrix[6];
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left (undocumented feature) */
+ }
+
+ /* calculate the destination limits */
+ cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL);
+
+ /* Setup inverse transform */
+ cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix);
+
+ /* for all pixels in the destiny area */
+ for(t_y = t_ymin; t_y <= t_ymax; t_y++)
+ {
+ dst_offset = t_y * ctxcanvas->canvas->w;
+
+ for(t_x = t_xmin; t_x <= t_xmax; t_x++)
+ {
+ cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix);
+
+ if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1)
+ {
+ if (img_topdown) /* image is top-bottom */
+ i_y = ih-1 - i_y;
+
+ si = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y);
+ sCombineRGBColor(ctxcanvas, t_x + dst_offset, colors[si]);
+ }
+ }
+ }
+}
+
+static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rh, rw, img_topdown = 0;
+ const unsigned char *src_red, *src_green, *src_blue;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, NULL, x, y, w, h, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ (x+w) < 0 || (y+h) < 0)
+ return;
+
+ xpos = x < 0? 0: x;
+ ypos = y < 0? 0: y;
+
+ xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1;
+ ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ /* testa se tem que fazer zoom */
+ if (rw != w || rh != h)
+ {
+ int* XTab = cdGetZoomTable(w, rw, xmin);
+ int* YTab = cdGetZoomTable(h, rh, ymin);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ for(l = 0; l < ysize; l++)
+ {
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw;
+ else
+ src_offset = YTab[l + (ypos - y)] * iw;
+
+ src_red = r + src_offset;
+ src_green = g + src_offset;
+ src_blue = b + src_offset;
+
+ for(c = 0; c < xsize; c++)
+ {
+ src_offset = XTab[c + (xpos - x)];
+ sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], 255);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw;
+ else
+ src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw;
+
+ r += src_offset;
+ g += src_offset;
+ b += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize);
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ if (img_topdown)
+ {
+ r -= iw;
+ g -= iw;
+ b -= iw;
+ }
+ else
+ {
+ r += iw;
+ g += iw;
+ b += iw;
+ }
+ }
+ }
+}
+
+static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, img_topdown = 0;
+ const unsigned char *src_red, *src_green, *src_blue, *src_alpha;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ (x+w) < 0 || (y+h) < 0)
+ return;
+
+ xpos = x < 0? 0: x;
+ ypos = y < 0? 0: y;
+
+ xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1;
+ ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ /* testa se tem que fazer zoom */
+ if (rw != w || rh != h)
+ {
+ int* XTab = cdGetZoomTable(w, rw, xmin);
+ int* YTab = cdGetZoomTable(h, rh, ymin);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ for(l = 0; l < ysize; l++)
+ {
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw;
+ else
+ src_offset = YTab[l + (ypos - y)] * iw;
+
+ src_red = r + src_offset;
+ src_green = g + src_offset;
+ src_blue = b + src_offset;
+ src_alpha = a + src_offset;
+
+ for(c = 0; c < xsize; c++)
+ {
+ src_offset = XTab[c + (xpos - x)];
+ sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], src_alpha[src_offset]);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw;
+ else
+ src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw;
+
+ r += src_offset;
+ g += src_offset;
+ b += src_offset;
+ a += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize);
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ if (img_topdown)
+ {
+ r -= iw;
+ g -= iw;
+ b -= iw;
+ a -= iw;
+ }
+ else
+ {
+ r += iw;
+ g += iw;
+ b += iw;
+ a += iw;
+ }
+ }
+ }
+}
+
+static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, pal_size, idx, img_topdown = 0;
+ const unsigned char *src_index;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdputimagerectmap_matrix(ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ (x+w) < 0 || (y+h) < 0)
+ return;
+
+ xpos = x < 0? 0: x;
+ ypos = y < 0? 0: y;
+
+ xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1;
+ ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ /* Como nao sabemos o tamanho da palette a priori,
+ teremos que ver qual o maior indice usado na imagem. */
+ pal_size = 0;
+
+ for (l=0; l<ih; l++)
+ {
+ for (c=0; c<iw; c++)
+ {
+ idx = index[l*iw + c];
+ if (idx > pal_size)
+ pal_size = idx;
+ }
+ }
+
+ pal_size++;
+
+ /* testa se tem que fazer zoom */
+ if (rw != w || rh != h)
+ {
+ int* XTab = cdGetZoomTable(w, rw, xmin);
+ int* YTab = cdGetZoomTable(h, rh, ymin);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ for(l = 0; l < ysize; l++)
+ {
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw;
+ else
+ src_offset = YTab[l + (ypos - y)] * iw;
+
+ src_index = index + src_offset;
+
+ for(c = 0; c < xsize; c++)
+ {
+ src_offset = XTab[c + (xpos - x)];
+ idx = src_index[src_offset];
+ sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw;
+ else
+ src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw;
+
+ index += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ for(c = 0; c < xsize; c++)
+ {
+ idx = index[c];
+ sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ if (img_topdown)
+ index -= iw;
+ else
+ index += iw;
+ }
+ }
+}
+
+static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int color)
+{
+ int offset;
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->canvas->matrix, x, y, &x, &y);
+
+ offset = ctxcanvas->canvas->w * y + x;
+
+ /* verifica se esta dentro da area de desenho */
+ if (x < 0 ||
+ x > (ctxcanvas->canvas->w-1) ||
+ y < 0 ||
+ y > (ctxcanvas->canvas->h-1))
+ return;
+
+ sCombineRGBColor(ctxcanvas, offset, color);
+}
+
+static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h)
+{
+ cdCtxImage* ctximage;
+ int size = w * h;
+ int num_c = ctxcanvas->alpha? 4: 3;
+
+ ctximage = (cdCtxImage*)malloc(sizeof(cdCtxImage));
+ memset(ctximage, 0, sizeof(cdCtxImage));
+
+ ctximage->w = w;
+ ctximage->h = h;
+
+ ctximage->red = (unsigned char*) malloc(num_c*size);
+ if (!ctximage->red)
+ {
+ free(ctximage);
+ return NULL;
+ }
+
+ ctximage->green = ctximage->red + size;
+ ctximage->blue = ctximage->red + 2*size;
+ if (ctxcanvas->alpha)
+ ctximage->alpha = ctximage->red + 3*size;
+
+ memset(ctximage->red, 0xFF, 3*size);
+ if (ctximage->alpha) memset(ctximage->alpha, 0, size); /* transparent */
+
+ return ctximage;
+}
+
+static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y)
+{
+ unsigned char *r, *g, *b, *a = NULL;
+ int w, h, dst_offset, src_offset, l, xsize, ysize, xpos, ypos, do_alpha = 0;
+ unsigned char *src_red, *src_green, *src_blue, *src_alpha = NULL;
+
+ w = ctximage->w;
+ h = ctximage->h;
+
+ if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h ||
+ x + w < 0 || y + h < 0)
+ return;
+
+ if (ctximage->alpha && ctxcanvas->alpha)
+ do_alpha = 1;
+
+ r = ctximage->red;
+ g = ctximage->green;
+ b = ctximage->blue;
+ if (do_alpha) a = ctximage->alpha;
+
+ /* ajusta parametros de entrada */
+ xpos = _sNormX(ctxcanvas, x);
+ ypos = _sNormY(ctxcanvas, y);
+
+ xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos;
+ ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos;
+
+ /* ajusta posicao inicial em source */
+ src_offset = xpos + ypos * ctxcanvas->canvas->w;
+ src_red = ctxcanvas->red + src_offset;
+ src_green = ctxcanvas->green + src_offset;
+ src_blue = ctxcanvas->blue + src_offset;
+ if (do_alpha) src_alpha = ctxcanvas->alpha + src_offset;
+
+ /* offset para source */
+ src_offset = ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = (xpos - x) + (ypos - y) * w;
+ r += dst_offset;
+ g += dst_offset;
+ b += dst_offset;
+ if (do_alpha) a += dst_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ memcpy(r, src_red, xsize);
+ memcpy(g, src_green, xsize);
+ memcpy(b, src_blue, xsize);
+ if (do_alpha) memcpy(a, src_alpha, xsize);
+
+ src_red += src_offset;
+ src_green += src_offset;
+ src_blue += src_offset;
+ if (do_alpha) src_alpha += src_offset;
+
+ r += w;
+ g += w;
+ b += w;
+ if (do_alpha) a += w;
+ }
+}
+
+static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax)
+{
+ int iw, ih, w, h;
+ unsigned char *r, *g, *b, *a;
+ int l, xsize, ysize, xpos, ypos, src_offset, dst_offset;
+
+ iw = ctximage->w;
+ ih = ctximage->h;
+
+ r = ctximage->red;
+ g = ctximage->green;
+ b = ctximage->blue;
+ a = ctximage->alpha;
+
+ w = xmax-xmin+1;
+ h = ymax-ymin+1;
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ x + w < 0 || y + h < 0)
+ return;
+
+ xpos = x;
+ ypos = y;
+
+ if (ypos < 0) ypos = 0;
+ if (xpos < 0) xpos = 0;
+
+ xsize = w < ((ctxcanvas->canvas->w-1)+1 - xpos)? w: ((ctxcanvas->canvas->w-1)+1 - xpos);
+ ysize = h < ((ctxcanvas->canvas->h-1)+1 - ypos)? h: ((ctxcanvas->canvas->h-1)+1 - ypos);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ src_offset = ((xpos - x) + xmin) + ((ypos - y) + ymin) * iw;
+ r += src_offset;
+ g += src_offset;
+ b += src_offset;
+ if (a) a += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ if (a)
+ sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize);
+ else
+ sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize);
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ r += iw;
+ g += iw;
+ b += iw;
+ if (a) a += iw;
+ }
+}
+
+static void cdkillimage(cdCtxImage* ctximage)
+{
+ free(ctximage->red);
+ memset(ctximage, 0, sizeof(cdCtxImage));
+ free(ctximage);
+}
+
+static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy)
+{
+ int l;
+ long src_offset, dst_offset;
+ int incx,incy, xsize, ysize;
+ int dst_xmin, dst_xmax, dst_ymin, dst_ymax;
+
+ /* corrige valores de entrada */
+
+ xmin = _sNormX(ctxcanvas, xmin);
+ ymin = _sNormY(ctxcanvas, ymin);
+ xmax = _sNormX(ctxcanvas, xmax);
+ ymax = _sNormY(ctxcanvas, ymax);
+
+ dst_xmin = xmin + dx;
+ dst_ymin = ymin + dy;
+ dst_xmax = xmax + dx;
+ dst_ymax = ymax + dy;
+
+ /* verifica se esta dentro da area de desenho */
+ if (dst_xmin > (ctxcanvas->canvas->w-1) || dst_ymin > (ctxcanvas->canvas->h-1) ||
+ dst_xmax < 0 || dst_ymax < 0)
+ return;
+
+ if (dst_ymin < 0) dst_ymin = 0;
+ if (dst_xmin < 0) dst_xmin = 0;
+
+ if (dst_ymax > (ctxcanvas->canvas->h-1)) dst_ymax = (ctxcanvas->canvas->h-1);
+ if (dst_xmax > (ctxcanvas->canvas->w-1)) dst_xmax = (ctxcanvas->canvas->w-1);
+
+ if (dst_xmin > dst_xmax || dst_ymin > dst_ymax)
+ return;
+
+ /* Decide de onde vai comecar a copiar, isto e' necessario pois pode haver
+ uma intersecao entre a imagem original e a nova imagem, assim devo
+ garantir que nao estou colocando um ponto, em cima de um ponto ainda nao
+ lido da imagem antiga. */
+
+ xsize = dst_xmax - dst_xmin + 1;
+ ysize = dst_ymax - dst_ymin + 1;
+
+ /* sentido de copia da direita para a esquerda ou ao contrario. */
+ if (dx < 0)
+ {
+ incx = 1;
+ dst_offset = dst_xmin;
+ src_offset = xmin;
+ }
+ else
+ {
+ incx = -1;
+ dst_offset = dst_xmax;
+ src_offset = xmax;
+ }
+
+ /* sentido de copia de cima para baixo ou ao contrario. */
+ if (dy < 0)
+ {
+ incy = ctxcanvas->canvas->w;
+ dst_offset += dst_ymin * ctxcanvas->canvas->w;
+ src_offset += ymin * ctxcanvas->canvas->w;
+ }
+ else
+ {
+ incy = -(ctxcanvas->canvas->w);
+ dst_offset += dst_ymax * ctxcanvas->canvas->w;
+ src_offset += ymax * ctxcanvas->canvas->w;
+ }
+
+ xsize *= incx;
+
+ for (l = 0; l < ysize; l++)
+ {
+ sCombineRGBLine(ctxcanvas, dst_offset, ctxcanvas->red + src_offset, ctxcanvas->green + src_offset, ctxcanvas->blue + src_offset, xsize);
+ dst_offset += incy;
+ src_offset += incy;
+ }
+}
+
+static char* get_green_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->green;
+}
+
+static cdAttribute green_attrib =
+{
+ "GREENIMAGE",
+ NULL,
+ get_green_attrib
+};
+
+static char* get_blue_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->blue;
+}
+
+static cdAttribute blue_attrib =
+{
+ "BLUEIMAGE",
+ NULL,
+ get_blue_attrib
+};
+
+static char* get_red_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->red;
+}
+
+static cdAttribute red_attrib =
+{
+ "REDIMAGE",
+ NULL,
+ get_red_attrib
+};
+
+static char* get_alpha_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->alpha;
+}
+
+static cdAttribute alpha_attrib =
+{
+ "ALPHAIMAGE",
+ NULL,
+ get_alpha_attrib
+};
+
+static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (!data || data[0] == '0')
+ ctxcanvas->canvas->simulation->antialias = 0;
+ else
+ ctxcanvas->canvas->simulation->antialias = 1;
+}
+
+static char* get_aa_attrib(cdCtxCanvas* ctxcanvas)
+{
+ if (ctxcanvas->canvas->simulation->antialias)
+ return "0";
+ else
+ return "1";
+}
+
+static cdAttribute aa_attrib =
+{
+ "ANTIALIAS",
+ set_aa_attrib,
+ get_aa_attrib
+};
+
+static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data)
+ {
+ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle,
+ &ctxcanvas->rotate_center_x,
+ &ctxcanvas->rotate_center_y);
+
+ cdCanvasTransformTranslate(ctxcanvas->canvas, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y);
+ cdCanvasTransformRotate(ctxcanvas->canvas, ctxcanvas->rotate_angle);
+ cdCanvasTransformTranslate(ctxcanvas->canvas, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y);
+ }
+ else
+ {
+ ctxcanvas->rotate_angle = 0;
+ ctxcanvas->rotate_center_x = 0;
+ ctxcanvas->rotate_center_y = 0;
+
+ cdCanvasTransform(ctxcanvas->canvas, NULL);
+ }
+}
+
+static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas)
+{
+ static char data[100];
+
+ if (!ctxcanvas->rotate_angle)
+ return NULL;
+
+ sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle,
+ ctxcanvas->rotate_center_x,
+ ctxcanvas->rotate_center_y);
+
+ return data;
+}
+
+static cdAttribute rotate_attrib =
+{
+ "ROTATE",
+ set_rotate_attrib,
+ get_rotate_attrib
+};
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ int w = 0, h = 0, use_alpha = 0;
+ float res = (float)3.78;
+ unsigned char *r = NULL, *g = NULL, *b = NULL, *a = NULL;
+ char* str_data = (char*)data;
+ char* res_ptr = NULL;
+
+ if (strstr(str_data, "-a"))
+ use_alpha = 1;
+
+ res_ptr = strstr(str_data, "-r");
+ if (res_ptr)
+ sscanf(res_ptr+2, "%g", &res);
+
+ /* size and rgb */
+#ifdef SunOS_OLD
+ if (use_alpha)
+ sscanf(str_data, "%dx%d %d %d %d %d", &w, &h, &r, &g, &b, &a);
+ else
+ sscanf(str_data, "%dx%d %d %d %d", &w, &h, &r, &g, &b);
+#else
+ if (use_alpha)
+ sscanf(str_data, "%dx%d %p %p %p %p", &w, &h, &r, &g, &b, &a);
+ else
+ sscanf(str_data, "%dx%d %p %p %p", &w, &h, &r, &g, &b);
+#endif
+
+ if (w == 0 || h == 0)
+ return;
+
+ ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->yres = res;
+ canvas->xres = res;
+ canvas->w_mm = ((double)w) / res;
+ canvas->h_mm = ((double)h) / res;
+ if (use_alpha)
+ canvas->bpp = 32;
+ else
+ canvas->bpp = 24;
+
+ if (r && g && b)
+ {
+ ctxcanvas->user_image = 1;
+
+ ctxcanvas->red = r;
+ ctxcanvas->green = g;
+ ctxcanvas->blue = b;
+ ctxcanvas->alpha = a;
+ }
+ else
+ {
+ int size = w * h;
+ int num_c = use_alpha? 4: 3;
+
+ ctxcanvas->user_image = 0;
+
+ ctxcanvas->red = (unsigned char*)malloc(num_c*size);
+ if (!ctxcanvas->red)
+ {
+ free(ctxcanvas);
+ return;
+ }
+
+ ctxcanvas->green = ctxcanvas->red + size;
+ ctxcanvas->blue = ctxcanvas->red + 2*size;
+ if (use_alpha)
+ ctxcanvas->alpha = ctxcanvas->red + 3*size;
+
+ memset(ctxcanvas->red, 0xFF, 3*size); /* white */
+ if (ctxcanvas->alpha) memset(ctxcanvas->alpha, 0, size); /* transparent */
+ }
+
+ ctxcanvas->clip = (unsigned char*)malloc(w*h);
+ memset(ctxcanvas->clip, 1, w*h); /* CD_CLIPOFF */
+
+ canvas->ctxcanvas = ctxcanvas;
+ ctxcanvas->canvas = canvas;
+
+ cdSimInitText(canvas->simulation);
+ /* nao preciso inicializar a fonte,
+ pois isso sera' feito na inicializacao dos atributos default do driver */
+
+ canvas->simulation->antialias = 1;
+
+ cdRegisterAttribute(canvas, &red_attrib);
+ cdRegisterAttribute(canvas, &green_attrib);
+ cdRegisterAttribute(canvas, &blue_attrib);
+ cdRegisterAttribute(canvas, &alpha_attrib);
+ cdRegisterAttribute(canvas, &aa_attrib);
+ cdRegisterAttribute(canvas, &rotate_attrib);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdSimulation* sim;
+
+ /* initialize function table*/
+ canvas->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxNewRegion = cdnewregion;
+ canvas->cxIsPointInRegion = cdispointinregion;
+ canvas->cxOffsetRegion = cdoffsetregion;
+ canvas->cxGetRegionBox = cdgetregionbox;
+
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxGetImageRGB = cdgetimagergb;
+
+ canvas->cxCreateImage = cdcreateimage;
+ canvas->cxGetImage = cdgetimage;
+ canvas->cxPutImageRect = cdputimagerect;
+ canvas->cxKillImage = cdkillimage;
+ canvas->cxScrollArea = cdscrollarea;
+
+ canvas->cxClear = cdclear;
+ canvas->cxPixel = cdpixel;
+
+ canvas->cxLine = cdlineSIM;
+ canvas->cxRect = cdrectSIM;
+ canvas->cxBox = cdbox;
+ canvas->cxArc = cdarcSIM;
+ canvas->cxSector = cdsector;
+ canvas->cxChord = cdchord;
+ canvas->cxPoly = cdpoly;
+ canvas->cxText = cdtext;
+
+ canvas->cxKillCanvas = cdkillcanvas;
+
+ /* use simulation */
+ canvas->cxFont = cdfontSIM;
+ canvas->cxGetFontDim = cdgetfontdimSIM;
+ canvas->cxGetTextSize = cdgettextsizeSIM;
+
+ sim = canvas->simulation;
+
+ sim->SolidLine = irgbSolidLine;
+ sim->PatternLine = irgbPatternLine;
+ sim->StippleLine = irgbStippleLine;
+ sim->HatchLine = irgbHatchLine;
+}
+
+static cdContext cdImageRGBContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_FPRIMTIVES |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION |
+ CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextImageRGB(void)
+{
+ return &cdImageRGBContext;
+}
+
+static void cdflushDB(cdCtxCanvas *ctxcanvas)
+{
+ int old_writemode;
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* this is done in the canvas_dbuffer context */
+
+ /* Flush can be affected by Origin and Clipping, but not WriteMode */
+
+ old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE);
+ cdCanvasPutImageRectRGB(canvas_dbuffer, ctxcanvas->canvas->w, ctxcanvas->canvas->h, ctxcanvas->red, ctxcanvas->green, ctxcanvas->blue, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0, 0, 0);
+ cdCanvasWriteMode(canvas_dbuffer, old_writemode);
+}
+
+static void cdcreatecanvasDB(cdCanvas* canvas, cdCanvas* canvas_dbuffer)
+{
+ char rgbdata[100];
+ sprintf(rgbdata, "%dx%d -r%g", canvas_dbuffer->w, canvas_dbuffer->h, canvas_dbuffer->xres);
+ cdcreatecanvas(canvas, rgbdata);
+ if (canvas->ctxcanvas)
+ canvas->ctxcanvas->canvas_dbuffer = canvas_dbuffer;
+}
+
+static int cdactivateDB(cdCtxCanvas *ctxcanvas)
+{
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* this is done in the canvas_dbuffer context */
+ /* this will update canvas size */
+ cdCanvasActivate(canvas_dbuffer);
+
+ /* check if the size changed */
+ if (canvas_dbuffer->w != ctxcanvas->canvas->w ||
+ canvas_dbuffer->h != ctxcanvas->canvas->h)
+ {
+ cdCanvas* canvas = ctxcanvas->canvas;
+ /* save the current, if the rebuild fail */
+ cdCtxCanvas* old_ctxcanvas = ctxcanvas;
+
+ /* if the image is rebuild, the canvas that uses the image must be also rebuild */
+
+ /* rebuild the image and the canvas */
+ canvas->ctxcanvas = NULL;
+ cdcreatecanvasDB(canvas, canvas_dbuffer);
+ if (!canvas->ctxcanvas)
+ {
+ canvas->ctxcanvas = old_ctxcanvas;
+ return CD_ERROR;
+ }
+
+ /* remove the old image and canvas */
+ cdkillcanvas(old_ctxcanvas);
+
+ ctxcanvas = canvas->ctxcanvas;
+
+ /* update canvas attributes */
+ if (canvas->cxBackground) canvas->cxBackground(ctxcanvas, canvas->background);
+ if (canvas->cxForeground) canvas->cxForeground(ctxcanvas, canvas->foreground);
+ if (canvas->cxBackOpacity) canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity);
+ if (canvas->cxWriteMode) canvas->cxWriteMode(ctxcanvas, canvas->write_mode);
+ if (canvas->cxLineStyle) canvas->cxLineStyle(ctxcanvas, canvas->line_style);
+ if (canvas->cxLineWidth) canvas->cxLineWidth(ctxcanvas, canvas->line_width);
+ if (canvas->cxLineCap) canvas->cxLineCap(ctxcanvas, canvas->line_cap);
+ if (canvas->cxLineJoin) canvas->cxLineJoin(ctxcanvas, canvas->line_join);
+ if (canvas->cxHatch) canvas->cxHatch(ctxcanvas, canvas->hatch_style);
+ if (canvas->stipple && canvas->cxStipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple);
+ if (canvas->pattern && canvas->cxPattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern);
+ if (canvas->cxInteriorStyle) canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style);
+ if (canvas->native_font[0] && canvas->cxNativeFont)
+ canvas->cxNativeFont(ctxcanvas, canvas->native_font);
+ else if (canvas->cxFont) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size);
+ if (canvas->cxTextAlignment) canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment);
+ if (canvas->cxTextOrientation) canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation);
+ if (canvas->use_matrix && canvas->cxTransform) canvas->cxTransform(ctxcanvas, canvas->matrix);
+ if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax);
+ if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax);
+ if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n);
+ if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n);
+ if (canvas->clip_mode != CD_CLIPOFF && canvas->cxClip) canvas->cxClip(ctxcanvas, canvas->clip_mode);
+ }
+
+ return CD_OK;
+}
+
+static void cddeactivateDB(cdCtxCanvas *ctxcanvas)
+{
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+ /* this is done in the canvas_dbuffer context */
+ cdCanvasDeactivate(canvas_dbuffer);
+}
+
+static void cdinittableDB(cdCanvas* canvas)
+{
+ cdinittable(canvas);
+
+ canvas->cxActivate = cdactivateDB;
+ canvas->cxDeactivate = cddeactivateDB;
+
+ canvas->cxFlush = cdflushDB;
+}
+
+static cdContext cdDBufferRGBContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_FPRIMTIVES |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION |
+ CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION),
+ 0,
+ cdcreatecanvasDB,
+ cdinittableDB,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextDBufferRGB(void)
+{
+ return &cdDBufferRGBContext;
+}