diff options
Diffstat (limited to 'src/drv/cdirgb.c')
-rw-r--r-- | src/drv/cdirgb.c | 2135 |
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; +} |