diff options
Diffstat (limited to 'cd/src/sim')
-rwxr-xr-x | cd/src/sim/sim.c | 53 | ||||
-rwxr-xr-x | cd/src/sim/sim.h | 6 | ||||
-rwxr-xr-x | cd/src/sim/sim_linepolyfill.c | 98 | ||||
-rwxr-xr-x | cd/src/sim/sim_other.c | 411 | ||||
-rwxr-xr-x | cd/src/sim/sim_primitives.c | 1562 | ||||
-rwxr-xr-x | cd/src/sim/truetype.h | 46 |
6 files changed, 1377 insertions, 799 deletions
diff --git a/cd/src/sim/sim.c b/cd/src/sim/sim.c index 3e4ccf1..839e4ff 100755 --- a/cd/src/sim/sim.c +++ b/cd/src/sim/sim.c @@ -88,7 +88,7 @@ void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax) switch(canvas->interior_style) { case CD_SOLID: - simulation->SolidLine(canvas, xmin,y,xmax); + simulation->SolidLine(canvas, xmin,y,xmax, canvas->foreground); break; case CD_PATTERN: simulation->PatternLine(canvas, xmin,xmax,y,canvas->pattern_w, @@ -106,10 +106,20 @@ void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax) } } -static void simSolidLine(cdCanvas* canvas, int xmin, int y, int xmax) +void simFillHorizBox(cdSimulation* simulation, int xmin, int xmax, int ymin, int ymax) { - /* cdpolySIM and cdboxSIM will set line attributes so this can work */ - canvas->cxLine(canvas->ctxcanvas, xmin, y, xmax, y); + int y; + for(y=ymin;y<=ymax;y++) + simFillHorizLine(simulation, xmin, y, xmax); +} + +static void simSolidLine(cdCanvas* canvas, int xmin, int y, int xmax, long color) +{ + int x; + for (x = xmin; x <= xmax; x++) + { + canvas->cxPixel(canvas->ctxcanvas, x,y,color); + } } static void simPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern) @@ -117,12 +127,10 @@ static void simPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, cdSimulation* simulation = canvas->simulation; int x,i; int xb; - long curColor, old_color; + long curColor; i = xmin % pw; - - old_color = canvas->foreground; - + for (x = xmin; x <= xmax;) { if (i == pw) @@ -142,13 +150,8 @@ static void simPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, if(xb==x-1) canvas->cxPixel(canvas->ctxcanvas, xb,y,curColor); else - { - cdCanvasSetForeground(canvas, curColor); - simulation->SolidLine(canvas, xb,y,x-1); - } + simulation->SolidLine(canvas, xb,y,x-1, curColor); } - - cdCanvasSetForeground(canvas, old_color); } static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple) @@ -165,7 +168,7 @@ static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, if(opacity==CD_OPAQUE) { bgColor=canvas->background; - cdCanvasSetForeground(canvas, fgColor); + for (x = xmin, i=xmin%pw ; x <= xmax;) { if(i==pw) @@ -184,10 +187,10 @@ static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, if(xb==x-1) canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor); else - simulation->SolidLine(canvas, xb,y,x-1); + simulation->SolidLine(canvas, xb,y,x-1,fgColor); } } - cdCanvasSetForeground(canvas, bgColor); + for (x = xmin, i=xmin%pw ; x <= xmax;) { if(i==pw) @@ -206,13 +209,12 @@ static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, if(xb==x-1) canvas->cxPixel(canvas->ctxcanvas, xb,y,bgColor); else - simulation->SolidLine(canvas, xb,y,x-1); + simulation->SolidLine(canvas, xb,y,x-1,bgColor); } } } else { - cdCanvasSetForeground(canvas, fgColor); for (x = xmin,i=xmin%pw; x <= xmax;) { xb=x; @@ -229,11 +231,10 @@ static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, if(xb==x-1) canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor); else - simulation->SolidLine(canvas, xb,y,x-1); + simulation->SolidLine(canvas, xb,y,x-1,fgColor); } } } - cdCanvasSetForeground(canvas, fgColor); } static void simHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch) @@ -268,15 +269,11 @@ static void simHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned c if(xb==x) canvas->cxPixel(canvas->ctxcanvas, xb,y,curColor); else - { - cdCanvasSetForeground(canvas, curColor); - simulation->SolidLine(canvas, xb,y,x); - } + simulation->SolidLine(canvas, xb,y,x, curColor); } } else { - cdCanvasSetForeground(canvas, fgColor); for (x = xmin; x <= xmax; x++) { mask=(hatch&0x80)?1:0; @@ -295,12 +292,10 @@ static void simHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned c if(xb==x) canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor); else - simulation->SolidLine(canvas, xb,y,x); + simulation->SolidLine(canvas, xb,y,x,fgColor); } } } - - cdCanvasSetForeground(canvas, fgColor); } cdSimulation* cdCreateSimulation(cdCanvas* canvas) diff --git a/cd/src/sim/sim.h b/cd/src/sim/sim.h index e98b030..2832391 100755 --- a/cd/src/sim/sim.h +++ b/cd/src/sim/sim.h @@ -18,7 +18,7 @@ struct _cdSimulation int font_map_n; /* horizontal line draw functions */ - void (*SolidLine)(cdCanvas* canvas, int xmin, int y, int xmax); + void (*SolidLine)(cdCanvas* canvas, int xmin, int y, int xmax, long color); void (*PatternLine)(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern); void (*StippleLine)(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple); void (*HatchLine)(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch); @@ -28,6 +28,7 @@ struct _cdSimulation void simFillDrawAAPixel(cdCanvas *canvas, int x, int y, unsigned short alpha_weigth); void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax); +void simFillHorizBox(cdSimulation* simulation, int xmin, int xmax, int ymin, int ymax); int simIsPointInPolyWind(cdPoint* poly, int n, int x, int y); /* list of non-horizontal line segments */ @@ -49,10 +50,9 @@ void simPolyMakeSegments(simLineSegment *segments, int *n_seg, cdPoint* poly, in void simPolyFill(cdSimulation* simulation, cdPoint* poly, int n); void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2); void simLineThick(cdCanvas* canvas, int x1, int y1, int x2, int y2); +void simfLineThick(cdCanvas* canvas, double x1, double y1, double x2, double y2); void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b); extern int simLineStyleNoReset; -int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height); - #endif diff --git a/cd/src/sim/sim_linepolyfill.c b/cd/src/sim/sim_linepolyfill.c index 2454a00..f73b26f 100755 --- a/cd/src/sim/sim_linepolyfill.c +++ b/cd/src/sim/sim_linepolyfill.c @@ -712,13 +712,67 @@ void simLineThick(cdCanvas* canvas, int x1, int y1, int x2, int y2) cdCanvasLineStyle(canvas, style); } +void simfLineThick(cdCanvas* canvas, double x1, double y1, double x2, double y2) +{ + const int interior = canvas->interior_style; + const int width = canvas->line_width; + const int style = canvas->line_style; + + const double dx = x2-x1; + const double dy = y2-y1; + + const double len = hypot(dx,dy); + + const double dnx = dx/len; + const double dny = dy/len; + + const double w1 = width/2.0; + const double w2 = width-w1; + + const double n1x = w1*dny; + const double n1y = -w1*dnx; + + const double n2x = -w2*dny; + const double n2y = w2*dnx; + + const double p1x = x1 + n1x; + const double p1y = y1 + n1y; + const double p2x = x1 + n2x; + const double p2y = y1 + n2y; + const double p3x = p2x + dx; + const double p3y = p2y + dy; + const double p4x = p1x + dx; + const double p4y = p1y + dy; + + cdPoint poly[4]; + + cdCanvasLineWidth(canvas, 1); + cdCanvasInteriorStyle(canvas, CD_SOLID); + cdCanvasLineStyle(canvas, CD_CONTINUOUS); + + poly[0].x = _cdRound(p1x); + poly[0].y = _cdRound(p1y); + poly[1].x = _cdRound(p2x); + poly[1].y = _cdRound(p2y); + poly[2].x = _cdRound(p3x); + poly[2].y = _cdRound(p3y); + poly[3].x = _cdRound(p4x); + poly[3].y = _cdRound(p4y); + + simPolyFill(canvas->simulation, poly, 4); + + cdCanvasLineWidth(canvas, width); + cdCanvasInteriorStyle(canvas, interior); + cdCanvasLineStyle(canvas, style); +} + void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2) { unsigned short ErrorInc, ErrorAcc; unsigned short ErrorAccTemp, Weighting; int DeltaX, DeltaY, XDir; long aa_fgcolor; - unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha; + unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha1, aa_alpha2; int no_antialias = !(canvas->simulation->antialias); unsigned short int ls; long fgcolor = canvas->foreground; @@ -840,11 +894,12 @@ void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2) weighting for the paired pixel. Combine the Weighting with the existing alpha, When Weighting is zero alpha must be fully preserved. */ - aa_alpha = (unsigned char)(((255-Weighting) * alpha) / 255); + aa_alpha1 = (unsigned char)(((255-Weighting) * alpha) / 255); + aa_alpha2 = (unsigned char)((Weighting * alpha) / 255); - aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha1); _cdLineDrawPixel(canvas, x1, y1, ls, aa_fgcolor); - aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha2); _cdLineDrawPixel(canvas, x1 + XDir, y1, ls, aa_fgcolor); ls = simRotateLineStyle(ls); } @@ -891,11 +946,12 @@ void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2) weighting for the paired pixel. Combine the Weighting with the existing alpha, When Weighting is zero alpha must be fully preserved. */ - aa_alpha = (unsigned char)(((255-Weighting) * alpha) / 255); + aa_alpha1 = (unsigned char)(((255-Weighting) * alpha) / 255); + aa_alpha2 = (unsigned char)((Weighting * alpha) / 255); - aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha1); _cdLineDrawPixel(canvas, x1, y1, ls, aa_fgcolor); - aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha2); _cdLineDrawPixel(canvas, x1, y1+1, ls, aa_fgcolor); ls = simRotateLineStyle(ls); } @@ -914,7 +970,7 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, { double DeltaX, DeltaY, a, b; long aa_fgcolor; - unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha; + unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha1, aa_alpha2; int no_antialias = !(canvas->simulation->antialias); int yi, xi, update_a = 1, update_b = 1; unsigned short int ls; @@ -975,11 +1031,12 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, /* Combine the Weighting with the existing alpha, When Weighting is zero alpha must be fully preserved. */ - aa_alpha = (unsigned char)((1.0-(x - xi)) * alpha); + aa_alpha1 = (unsigned char)((1.0-(x - xi)) * alpha); + aa_alpha2 = (unsigned char)((x - xi) * alpha); if (no_antialias) { - if (aa_alpha > 128) + if (aa_alpha1 > 128) _cdLineDrawPixel(canvas, xi, yi, ls, fgcolor) else _cdLineDrawPixel(canvas, xi+1, yi, ls, fgcolor) @@ -999,7 +1056,7 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, if ((xi != *last_xi_a || yi != *last_yi_a) && (xi != *last_xi_b || yi != *last_yi_b)) { - aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha1); _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor); if (yi == yi_last) /* one pixel only */ @@ -1009,7 +1066,7 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, if ((xi+1 != *last_xi_a || yi != *last_yi_a) && (xi+1 != *last_xi_b || yi != *last_yi_b)) { - aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha2); _cdLineDrawPixel(canvas, xi+1, yi, ls, aa_fgcolor); if (yi == yi_last) /* one pixel only */ @@ -1018,9 +1075,9 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, } else { - aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha1); _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor); - aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha2); _cdLineDrawPixel(canvas, xi+1, yi, ls, aa_fgcolor); } } @@ -1061,11 +1118,12 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, /* Combine the Weighting with the existing alpha, When Weighting is zero alpha must be fully preserved. */ - aa_alpha = (unsigned char)((1.0-(y - yi)) * alpha); + aa_alpha1 = (unsigned char)((1.0-(y - yi)) * alpha); + aa_alpha2 = (unsigned char)((y - yi) * alpha); if (no_antialias) { - if (aa_alpha > 128) + if (aa_alpha1 > 128) _cdLineDrawPixel(canvas, xi, yi, ls, fgcolor) else _cdLineDrawPixel(canvas, xi, yi+1, ls, fgcolor) @@ -1085,7 +1143,7 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, if ((xi != *last_xi_a || yi != *last_yi_a) && (xi != *last_xi_b || yi != *last_yi_b)) { - aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha1); _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor); if (xi == xi_last) /* one pixel only */ @@ -1095,7 +1153,7 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, if ((xi != *last_xi_a || yi+1 != *last_yi_a) && (xi != *last_xi_b || yi+1 != *last_yi_b)) { - aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha2); _cdLineDrawPixel(canvas, xi, yi+1, ls, aa_fgcolor); if (xi == xi_last) /* one pixel only */ @@ -1104,9 +1162,9 @@ void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, } else { - aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha1); _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor); - aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha); + aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha2); _cdLineDrawPixel(canvas, xi, yi+1, ls, aa_fgcolor); } } diff --git a/cd/src/sim/sim_other.c b/cd/src/sim/sim_other.c deleted file mode 100755 index 0954406..0000000 --- a/cd/src/sim/sim_other.c +++ /dev/null @@ -1,411 +0,0 @@ -/** \file - * \brief Simulation that is independent of the Simulation Base Driver - * - * See Copyright Notice in cd.h - */ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <memory.h> - -#include "cd.h" -#include "cd_private.h" - - -void cdSimMark(cdCanvas* canvas, int x, int y) -{ - int oldinteriorstyle = canvas->interior_style; - int oldlinestyle = canvas->line_style; - int oldlinewidth = canvas->line_width; - int size = canvas->mark_size; - int half_size = size/2; - int bottom = y-half_size; - int top = y+half_size; - int left = x-half_size; - int right = x+half_size; - - if (canvas->interior_style != CD_SOLID && - (canvas->mark_type == CD_CIRCLE || - canvas->mark_type == CD_BOX || - canvas->mark_type == CD_DIAMOND)) - cdCanvasInteriorStyle(canvas, CD_SOLID); - - if (canvas->line_style != CD_CONTINUOUS && - (canvas->mark_type == CD_STAR || - canvas->mark_type == CD_PLUS || - canvas->mark_type == CD_X || - canvas->mark_type == CD_HOLLOW_BOX || - canvas->mark_type == CD_HOLLOW_CIRCLE || - canvas->mark_type == CD_HOLLOW_DIAMOND)) - cdCanvasLineStyle(canvas, CD_CONTINUOUS); - - if (canvas->line_width != 1 && - (canvas->mark_type == CD_STAR || - canvas->mark_type == CD_PLUS || - canvas->mark_type == CD_X || - canvas->mark_type == CD_HOLLOW_BOX || - canvas->mark_type == CD_HOLLOW_CIRCLE || - canvas->mark_type == CD_HOLLOW_DIAMOND)) - cdCanvasLineWidth(canvas, 1); - - switch (canvas->mark_type) - { - case CD_STAR: - canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top); - canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom); - /* continue */ - case CD_PLUS: - canvas->cxLine(canvas->ctxcanvas, left, y, right, y); - canvas->cxLine(canvas->ctxcanvas, x, bottom, x, top); - break; - case CD_HOLLOW_CIRCLE: - canvas->cxArc(canvas->ctxcanvas, x, y, size, size, 0, 360); - break; - case CD_HOLLOW_BOX: - canvas->cxRect(canvas->ctxcanvas, left, right, bottom, top); - break; - case CD_HOLLOW_DIAMOND: - canvas->cxLine(canvas->ctxcanvas, left, y, x, top); - canvas->cxLine(canvas->ctxcanvas, x, top, right, y); - canvas->cxLine(canvas->ctxcanvas, right, y, x, bottom); - canvas->cxLine(canvas->ctxcanvas, x, bottom, left, y); - break; - case CD_X: - canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top); - canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom); - break; - case CD_CIRCLE: - canvas->cxSector(canvas->ctxcanvas, x, y, size, size, 0, 360); - break; - case CD_BOX: - canvas->cxBox(canvas->ctxcanvas, left, right, bottom, top); - break; - case CD_DIAMOND: - { - cdPoint poly[5]; - poly[0].x = left; - poly[0].y = y; - poly[1].x = x; - poly[1].y = top; - poly[2].x = right; - poly[2].y = y; - poly[3].x = x; - poly[3].y = bottom; - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4); - } - break; - } - - if (canvas->interior_style != oldinteriorstyle && - (canvas->mark_type == CD_CIRCLE || - canvas->mark_type == CD_BOX || - canvas->mark_type == CD_DIAMOND)) - cdCanvasInteriorStyle(canvas, oldinteriorstyle); - - if (canvas->line_style != oldlinestyle && - (canvas->mark_type == CD_STAR || - canvas->mark_type == CD_PLUS || - canvas->mark_type == CD_X || - canvas->mark_type == CD_HOLLOW_BOX || - canvas->mark_type == CD_HOLLOW_CIRCLE || - canvas->mark_type == CD_HOLLOW_DIAMOND)) - cdCanvasLineStyle(canvas, oldlinestyle); - - if (canvas->line_width != oldlinewidth && - (canvas->mark_type == CD_STAR || - canvas->mark_type == CD_PLUS || - canvas->mark_type == CD_X || - canvas->mark_type == CD_HOLLOW_BOX || - canvas->mark_type == CD_HOLLOW_CIRCLE || - canvas->mark_type == CD_HOLLOW_DIAMOND)) - cdCanvasLineWidth(canvas, oldlinewidth); -} - -/* Setup Bezier coefficient array once for each control polygon. - */ -static void BezierForm(const cdPoint* p, cdfPoint* c) -{ - int k; - static int choose[4] = {1, 3, 3, 1}; - for (k = 0; k < 4; k++) - { - c[k].x = p[k].x * choose[k]; - c[k].y = p[k].y * choose[k]; - } -} - -static void fBezierForm(const cdfPoint* p, cdfPoint* c) -{ - int k; - static int choose[4] = {1, 3, 3, 1}; - for (k = 0; k < 4; k++) - { - c[k].x = p[k].x * choose[k]; - c[k].y = p[k].y * choose[k]; - } -} - -/* Return Point pt(t), t <= 0 <= 1 from C. - * BezierForm must be called once for any given control polygon. - */ -static void BezierCurve(const cdfPoint* c, cdfPoint *pt, double t) -{ - int k; - double t1, tt, u; - cdfPoint b[4]; - - u = t; - - b[0].x = c[0].x; - b[0].y = c[0].y; - for(k = 1; k < 4; k++) - { - b[k].x = c[k].x * u; - b[k].y = c[k].y * u; - u =u*t; - } - - pt->x = b[3].x; - pt->y = b[3].y; - t1 = 1-t; - tt = t1; - for(k = 2; k >= 0; k--) - { - pt->x += b[k].x * tt; - pt->y += b[k].y * tt; - tt =tt*t1; - } -} - -static int BezierNumSegments(cdCanvas* canvas, const cdPoint* p) -{ - int i, K, dx, dy, d, - xmax = p[0].x, - ymax = p[0].y, - xmin = p[0].x, - ymin = p[0].y; - - for (i = 1; i < 4; i++) - { - if (p[i].x > xmax) - xmax = p[i].x; - if (p[i].y > ymax) - ymax = p[i].y; - if (p[i].x < xmin) - xmin = p[i].x; - if (p[i].y < ymin) - ymin = p[i].y; - } - - if (canvas->use_matrix) - { - cdMatrixTransformPoint(canvas->matrix, xmin, ymin, &xmin, &ymin); - cdMatrixTransformPoint(canvas->matrix, xmax, ymax, &xmax, &ymax); - } - - /* diagonal of the bouding box */ - dx = (xmax-xmin); - dy = (ymax-ymin); - d = (int)(sqrt(dx*dx + dy*dy)); - K = d / 8; - if (K < 8) K = 8; - return K; -} - -static int fBezierNumSegments(cdCanvas* canvas, const cdfPoint* p) -{ - int i, K, d; - double dx, dy, - xmax = p[0].x, - ymax = p[0].y, - xmin = p[0].x, - ymin = p[0].y; - - for (i = 1; i < 4; i++) - { - if (p[i].x > xmax) - xmax = p[i].x; - if (p[i].y > ymax) - ymax = p[i].y; - if (p[i].x < xmin) - xmin = p[i].x; - if (p[i].y < ymin) - ymin = p[i].y; - } - - /* diagonal of the bouding box */ - dx = (xmax-xmin); - dy = (ymax-ymin); - d = (int)(sqrt(dx*dx + dy*dy)); - K = d / 8; - if (K < 8) K = 8; - return K; -} - -/* from sim.h */ -void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b); - -/* Quick and Simple Bezier Curve Drawing --- Robert D. Miller - * Graphics GEMS V */ -void cdSimPolyBezier(cdCanvas* canvas, const cdPoint* points, int n) -{ - int i = 0, k, K, poly_max = 0; - cdfPoint pt, prev_pt; - cdfPoint bezier_control[4]; - cdPoint* poly = NULL; - int use_poly = 0, - last_xi_a = -65535, - last_yi_a = -65535, - last_xi_b = -65535, - last_yi_b = -65535; - - /* Use special floating point anti-alias line draw when - line_width==1, and NOT using cdlineSIM. */ - if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM) - use_poly = 1; - - n--; /* first n is 4 */ - while (n >= 3) - { - BezierForm(points+i, bezier_control); - K = BezierNumSegments(canvas, points+i); - - if (use_poly && poly_max < K+1) - { - poly = realloc(poly, sizeof(cdPoint)*(K+1)); /* K+1 points */ - if (!poly) return; - poly_max = K+1; - } - - /* first segment */ - BezierCurve(bezier_control, &pt, 0); - if (use_poly) - { - poly[0].x = _cdRound(pt.x); - poly[0].y = _cdRound(pt.y); - } - else - prev_pt = pt; - - for(k = 1; k < K+1; k++) - { - BezierCurve(bezier_control, &pt, (double)k/(double)K); - - if (use_poly) - { - poly[k].x = _cdRound(pt.x); - poly[k].y = _cdRound(pt.y); - } - else - { - int old_use_matrix = canvas->use_matrix; - double x1 = prev_pt.x, - y1 = prev_pt.y, - x2 = pt.x, - y2 = pt.y; - - if (canvas->use_matrix && !canvas->invert_yaxis) - { - cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); - cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); - } - - /* must disable transformation here, because line simulation use cxPixel */ - canvas->use_matrix = 0; - - simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b); - - canvas->use_matrix = old_use_matrix; - prev_pt = pt; - } - } - - if (use_poly) - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, k); - - n -= 3; i += 3; - } - - if (poly) free(poly); -} - -void cdfSimPolyBezier(cdCanvas* canvas, const cdfPoint* points, int n) -{ - int i = 0, k, K, poly_max = 0; - cdfPoint pt; - cdfPoint bezier_control[4]; - cdfPoint* poly = NULL; - - n--; /* first n is 4 */ - while (n >= 3) - { - fBezierForm(points+i, bezier_control); - K = fBezierNumSegments(canvas, points+i); - - if (poly_max < K+1) - { - poly = realloc(poly, sizeof(cdfPoint)*(K+1)); /* K+1 points */ - if (!poly) return; - poly_max = K+1; - } - - /* first segment */ - BezierCurve(bezier_control, &pt, 0); - poly[0].x = _cdRound(pt.x); - poly[0].y = _cdRound(pt.y); - - for(k = 1; k < K+1; k++) - { - BezierCurve(bezier_control, &pt, (double)k/(double)K); - - poly[k].x = _cdRound(pt.x); - poly[k].y = _cdRound(pt.y); - } - - canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, k); - n -= 3; i += 3; - } - - if (poly) free(poly); -} - -void cdSimPutImageRectRGBA(cdCanvas* canvas, 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 size, i, j, dst, src, *fx, *fy, rw, rh; - unsigned char *ar, *ag, *ab, al; - - size = w * h; - ar = (unsigned char*)malloc(size*3); - if (!ar) return; - ag = ar + size; - ab = ag + size; - - canvas->cxGetImageRGB(canvas->ctxcanvas, ar, ag, ab, x, y, w, h); - - rw = xmax-xmin+1; - rh = ymax-ymin+1; - - fx = cdGetZoomTable(w, rw, xmin); - fy = cdGetZoomTable(h, rh, ymin); - - for (j = 0; j < h; j++) - { - for (i = 0; i < w; i++) - { - dst = j * w + i; - src = fy[j] * iw + fx[i]; - al = a[src]; - ar[dst] = CD_ALPHA_BLEND(r[src], ar[dst], al); - ag[dst] = CD_ALPHA_BLEND(g[src], ag[dst], al); - ab[dst] = CD_ALPHA_BLEND(b[src], ab[dst], al); - } - } - - canvas->cxPutImageRectRGB(canvas->ctxcanvas, w, h, ar, ag, ab, x, y, w, h, 0, 0, 0, 0); - - free(ar); - - free(fx); - free(fy); -} diff --git a/cd/src/sim/sim_primitives.c b/cd/src/sim/sim_primitives.c index dc991f8..2040c66 100755 --- a/cd/src/sim/sim_primitives.c +++ b/cd/src/sim/sim_primitives.c @@ -11,96 +11,75 @@ #include "cd.h" #include "cd_private.h" -#include "sim.h" -void cdlineSIM(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) + +void cdSimLine(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - int old_use_matrix = canvas->use_matrix; - - if (canvas->use_matrix && !canvas->invert_yaxis) - { - cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); - cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); - } - - /* must disable transformation here, because line simulation use cxPixel */ - canvas->use_matrix = 0; - - if(canvas->line_width > 1) - simLineThick(canvas, x1, y1, x2, y2); - else - simLineThin(canvas, x1, y1, x2, y2); + cdPoint poly[2]; + poly[0].x = x1; poly[0].y = y1; + poly[1].x = x2; poly[1].y = y2; + cdCanvasPoly(canvas, CD_OPEN_LINES, poly, 2); +} - canvas->use_matrix = old_use_matrix; +void cdfSimLine(cdCtxCanvas* ctxcanvas, double x1, double y1, double x2, double y2) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdfPoint poly[2]; + poly[0].x = x1; poly[0].y = y1; + poly[1].x = x2; poly[1].y = y2; + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, 2); } -void cdrectSIM(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +void cdSimRect(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - cdPoint poly[5]; /* leave room of one more point */ + cdPoint poly[5]; /* leave room for one more point */ 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; - canvas->cxPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); + cdCanvasPoly(canvas, CD_CLOSED_LINES, poly, 4); } -void cdboxSIM(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +void cdfSimRect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) { + /* can be used only by drivers that implement cxFPoly */ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - - if (canvas->use_matrix) - { - cdPoint poly[5]; /* leave room of one more point */ - 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; - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4); - } - else - { - cdSimulation* simulation = canvas->simulation; - int y; - - /* must set line attributes here, because fill simulation use cxLine and cxPixel */ - int old_line_style = cdCanvasLineStyle(canvas, CD_CONTINUOUS); - int old_line_width = cdCanvasLineWidth(canvas, 1); - - for(y=ymin;y<=ymax;y++) - simFillHorizLine(simulation, xmin, y, xmax); - - cdCanvasLineStyle(canvas, old_line_style); - cdCanvasLineWidth(canvas, old_line_width); - } + cdfPoint poly[5]; /* leave room for one more point */ + 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; + canvas->cxFPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); } -void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +void cdSimBox(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - cdfPoint poly[5]; /* leave room of one more point */ + cdPoint poly[5]; /* leave room for one more point */ 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; - canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, 4); + cdCanvasPoly(canvas, CD_FILL, poly, 4); } -void cdfSimRect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) { + /* can be used only by drivers that implement cxFPoly */ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - cdfPoint poly[5]; /* leave room of one more point */ + cdfPoint poly[5]; /* leave room for one more point */ 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; - canvas->cxFPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, 4); } -int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height) +static int sCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height, double angle1, double angle2) { - int n, dx, dy, hd; + int K, dx, dy, hd; int w2 = width/2; int h2 = height/2; int x1 = xc-w2, @@ -114,6 +93,8 @@ int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int h cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); } + /* first calculate the number of segments of equivalent poligonal for a full ellipse */ + dx = (x1-x2); dy = (y1-y2); hd = (int)(sqrt(dx*dx + dy*dy)/2); @@ -125,51 +106,61 @@ int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int h The number of segments will be 360 / min_angle. */ - n = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ + K = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ /* multiple of 4 */ - n = ((n + 3)/4)*4; + K = ((K + 3)/4)*4; /* minimum number is 4 */ - if (n < 4) n = 4; + if (K < 4) K = 4; + - return n; + /* finally, calculate the number of segments for the arc */ + K = cdRound((fabs(angle2-angle1)*K)/(360*CD_DEG2RAD)); + if (K < 1) K = 1; + + return K; } -void cdarcSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +static void sFixAngles(cdCanvas* canvas, double *a1, double *a2) { - cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - double c, s, sx, sy, x, y, prev_x, prev_y; - double da; - int i, yc2 = 2*yc, p = 0, - last_xi_a = -65535, - last_yi_a = -65535, - last_xi_b = -65535, - last_yi_b = -65535; - cdPoint* poly = NULL; + /* computation in PolyAddArc is done as if the angles are counterclockwise, + and yaxis is NOT inverted. */ - /* number of segments of equivalent poligonal for a full ellipse */ - int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height); - - /* Use special floating point anti-alias line draw when - line_width==1, and NOT using cdlineSIM. */ - if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM) + if (canvas->invert_yaxis) { - poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+1)); /* n+1 points */ - if (!poly) return; + /* change orientation */ + *a1 *= -1; + *a2 *= -1; + + /* no need to swap, because we will use (angle2-angle1) */ } + /* convert to radians */ + *a1 *= CD_DEG2RAD; + *a2 *= CD_DEG2RAD; +} + +static cdPoint* sPolyAddArc(cdCanvas* canvas, cdPoint* poly, int *n, int xc, int yc, int width, int height, double angle1, double angle2, cdPoint* current) +{ + double c, s, sx, sy, x, y, prev_x, prev_y; + double da; + int i, K, k, p, new_n; + cdPoint* old_poly = poly; + + sFixAngles(canvas, &angle1, &angle2); + /* number of segments for the arc */ - n = cdRound((fabs(angle2-angle1)*n)/360); - if (n < 1) n = 1; + K = sCalcEllipseNumSegments(canvas, xc, yc, width, height, angle1, angle2); - /* converts degrees into radians */ - angle1 *= CD_DEG2RAD; - angle2 *= CD_DEG2RAD; + new_n = *n + K+1; /* add room for K+1 samples */ + poly = (cdPoint*)realloc(poly, sizeof(cdPoint)*(new_n+2)); /* add room also for points at start and end */ + if (!poly) {free(old_poly); return NULL;} + i = *n; /* generates arc points at origin with axis x and y */ - da = (angle2-angle1)/n; + da = (angle2-angle1)/K; c = cos(da); s = sin(da); sx = -(width*s)/height; @@ -179,100 +170,56 @@ void cdarcSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, dou y = (height/2.0f)*sin(angle1); prev_x = x; prev_y = y; - if (poly) - { - poly[0].x = _cdRound(x)+xc; - poly[0].y = _cdRound(y)+yc; - - if (canvas->invert_yaxis) /* must invert because of the angle orientation */ - poly[0].y = yc2 - poly[0].y; - p = 1; + if (current) + { + poly[i] = *current; + i++; + new_n++; /* no need to reallocate */ } - else - simLineStyleNoReset = 1; - for (i = 1; i < n+1; i++) /* n+1 points */ + poly[i].x = _cdRound(x)+xc; + poly[i].y = _cdRound(y)+yc; + + p = i+1; + for (k = 1; k < K+1; k++) { x = c*prev_x + sx*prev_y; y = sy*prev_x + c*prev_y; - if (poly) - { - poly[p].x = _cdRound(x)+xc; - poly[p].y = _cdRound(y)+yc; - - if (canvas->invert_yaxis) /* must invert because of the angle orientation */ - poly[p].y = yc2 - poly[p].y; - - if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) - p++; - } - else - { - int old_use_matrix = canvas->use_matrix; - double x1 = prev_x+xc, - y1 = prev_y+yc, - x2 = x+xc, - y2 = y+yc; - - if (canvas->use_matrix && !canvas->invert_yaxis) - { - cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); - cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); - } - - /* must disable transformation here, because line simulation use cxPixel */ - canvas->use_matrix = 0; - - if (canvas->invert_yaxis) /* must invert because of the angle orientation */ - { - y1 = yc2 - y1; - y2 = yc2 - y2; - } - - simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b); + poly[p].x = _cdRound(x)+xc; + poly[p].y = _cdRound(y)+yc; - canvas->use_matrix = old_use_matrix; - } + if (poly[p-1].x != poly[p].x || + poly[p-1].y != poly[p].y) + p++; prev_x = x; prev_y = y; } - if (poly) - { - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p); - free(poly); - } - else - simLineStyleNoReset = 0; + *n = new_n; + return poly; } -void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2) +static cdfPoint* sfPolyAddArc(cdCanvas* canvas, cdfPoint* poly, int *n, double xc, double yc, double width, double height, double angle1, double angle2, cdfPoint* current) { - cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; double c, s, sx, sy, x, y, prev_x, prev_y, da; - int i, p; - cdfPoint* poly = NULL; - - /* number of segments of equivalent poligonal for a full ellipse */ - int n = simCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height); + int i, k, K, p, new_n; + cdfPoint* old_poly = poly; - poly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+1)); /* n+1 points */ - if (!poly) return; + sFixAngles(canvas, &angle1, &angle2); /* number of segments for the arc */ - n = cdRound((fabs(angle2-angle1)*n)/360); - if (n < 1) n = 1; + K = sCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height, angle1, angle2); - /* converts degrees into radians */ - angle1 *= CD_DEG2RAD; - angle2 *= CD_DEG2RAD; + new_n = *n + K+1; /* add room for K+1 samples */ + poly = (cdfPoint*)realloc(poly, sizeof(cdfPoint)*(new_n+2)); /* add room also for points at start and end */ + if (!poly) {free(old_poly); return NULL;} + i = *n; - /* generates arc points at origin with axis x and y */ - - da = (angle2-angle1)/n; + /* generates arc points at origin with axis x and y */ + da = (angle2-angle1)/K; c = cos(da); s = sin(da); sx = -(width*s)/height; @@ -282,12 +229,19 @@ void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, doubl y = (height/2.0f)*sin(angle1); prev_x = x; prev_y = y; - poly[0].x = x+xc; - poly[0].y = y+yc; - p = 1; + if (current) + { + poly[i] = *current; + i++; + new_n++; /* no need to reallocate */ + } - for (i = 1; i < n+1; i++) /* n+1 points */ + poly[i].x = x+xc; + poly[i].y = y+yc; + + p = i+1; + for (k = 1; k < K+1; k++) /* K+1 points */ { x = c*prev_x + sx*prev_y; y = sy*prev_x + c*prev_y; @@ -303,221 +257,1249 @@ void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, doubl prev_y = y; } - canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p); - free(poly); + *n = new_n; + return poly; } -void cdfSimElipse(cdCtxCanvas* ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2, int sector) +void cdSimArc(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - double c, s, sx, sy, x, y, prev_x, prev_y, da; - int i, p; - cdfPoint* poly; + int n = 0; + cdPoint* poly = NULL; - /* number of segments of equivalent poligonal for a full ellipse */ - int n = simCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height); + if (canvas->line_width == 1 && canvas->cxFPoly) + { + cdfSimArc(ctxcanvas, (double)xc, (double)yc, (double)width, (double)height, angle1, angle2); + return; + } - /* number of segments for the arc */ - n = cdRound(((angle2-angle1)*n)/360); - if (n < 1) n = 1; + poly = sPolyAddArc(canvas, poly, &n, xc, yc, width, height, angle1, angle2, NULL); - poly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+2+1)); /* n+1 points +1 center */ + if (poly) + { + cdCanvasPoly(canvas, CD_OPEN_LINES, poly, n); + free(poly); + } +} - /* converts degrees into radians */ - angle1 *= CD_DEG2RAD; - angle2 *= CD_DEG2RAD; +void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2) +{ + /* can be used only by drivers that implement cxFPoly */ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + int n = 0; + cdfPoint* poly = NULL; - /* generates arc points at origin with axis x and y */ + poly = sfPolyAddArc(canvas, poly, &n, xc, yc, width, height, angle1, angle2, NULL); - da = (angle2-angle1)/n; - c = cos(da); - s = sin(da); - sx = -(width*s)/height; - sy = (height*s)/width; + if (poly) + { + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, n); + free(poly); + } +} - x = xc + (width/2.0)*cos(angle1); - y = yc + (height/2.0)*sin(angle1); - prev_x = x; - prev_y = y; +static void sElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + int n = 0; + cdPoint* poly = NULL; - poly[0].x = x; - poly[0].y = y; - p = 1; + poly = sPolyAddArc(canvas, poly, &n, xc, yc, width, height, angle1, angle2, NULL); + if (!poly) + return; - for (i = 1; i < n+1; i++) /* n+1 points */ + if (poly[n-1].x != poly[0].x || + poly[n-1].y != poly[0].y) { - x = xc + c*(prev_x-xc) + sx*(prev_y-yc); - y = yc + sy*(prev_x-xc) + c*(prev_y-yc); - - poly[p].x = x; - poly[p].y = y; + n++; /* no need to reallocate */ - if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) - p++; + if (sector) /* cdSector */ + { + /* add center */ + poly[n-1].x = xc; + poly[n-1].y = yc; + } + else /* cdChord */ + { + /* add initial point */ + poly[n-1].x = poly[0].x; + poly[n-1].y = poly[0].y; + } + } - prev_x = x; - prev_y = y; + if (poly) + { + cdCanvasPoly(canvas, CD_FILL, poly, n); + free(poly); } +} - if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) +static void sfElipse(cdCtxCanvas* ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2, int sector) +{ + /* can be used only by drivers that implement cxFPoly */ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + int n = 0; + cdfPoint* poly = NULL; + + poly = sfPolyAddArc(canvas, poly, &n, xc, yc, width, height, angle1, angle2, NULL); + + if (poly[n-1].x != poly[0].x || + poly[n-1].y != poly[0].y) { + n++; /* no need to reallocate */ + if (sector) /* cdSector */ { /* add center */ - poly[p].x = xc; - poly[p].y = yc; + poly[n-1].x = xc; + poly[n-1].y = yc; } else /* cdChord */ { /* add initial point */ - poly[p].x = poly[0].x; - poly[p].y = poly[0].y; + poly[n-1].x = poly[0].x; + poly[n-1].y = poly[0].y; } - p++; } - canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, p); - free(poly); + if (poly) + { + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, n); + free(poly); + } } -static void cdSimElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) +void cdSimSector(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) { - cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - float c, s, sx, sy, x, y, prev_x, prev_y; - double da; - int i, p, yc2 = 2*yc; - cdPoint* poly; + sElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 1); +} - /* number of segments of equivalent poligonal for a full ellipse */ - int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height); +void cdSimChord(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +{ + sElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 0); +} - /* number of segments for the arc */ - n = cdRound(((angle2-angle1)*n)/360); - if (n < 1) n = 1; +void cdfSimSector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + sfElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1); +} - poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */ +void cdfSimChord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + sfElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0); +} - /* converts degrees into radians */ - angle1 *= CD_DEG2RAD; - angle2 *= CD_DEG2RAD; +/**************************************************************/ +/* Quick and Simple Bezier Curve Drawing --- Robert D. Miller */ +/* Graphics GEMS V */ +/**************************************************************/ - /* generates arc points at origin with axis x and y */ +/* Setup Bezier coefficient array once for each control polygon. + */ +static void sBezierForm(cdPoint start, const cdPoint* p, cdfPoint* c) +{ + int k; + static int choose[4] = {1, 3, 3, 1}; + for (k = 0; k < 4; k++) + { + if (k == 0) + { + c[k].x = start.x * choose[k]; + c[k].y = start.y * choose[k]; + } + else + { + c[k].x = p[k-1].x * choose[k]; + c[k].y = p[k-1].y * choose[k]; + } + } +} - da = (angle2-angle1)/n; - c = (float)cos(da); - s = (float)sin(da); - sx = -(width*s)/height; - sy = (height*s)/width; +static void sfBezierForm(cdfPoint start, const cdfPoint* p, cdfPoint* c) +{ + int k; + static int choose[4] = {1, 3, 3, 1}; + for (k = 0; k < 4; k++) + { + if (k == 0) + { + c[k].x = start.x * choose[k]; + c[k].y = start.y * choose[k]; + } + else + { + c[k].x = p[k-1].x * choose[k]; + c[k].y = p[k-1].y * choose[k]; + } + } +} - x = xc + (width/2.0f)*(float)cos(angle1); - y = yc + (height/2.0f)*(float)sin(angle1); - prev_x = x; - prev_y = y; +/* Return Point pt(t), t <= 0 <= 1 from C. + * sBezierForm must be called once for any given control polygon. + */ +static void sBezierCurve(const cdfPoint* c, cdfPoint *pt, double t) +{ + int k; + double t1, tt, u; + cdfPoint b[4]; - poly[0].x = _cdRound(x); - poly[0].y = _cdRound(y); - if (canvas->invert_yaxis) - poly[0].y = yc2 - poly[0].y; - p = 1; + u = t; - for (i = 1; i < n+1; i++) /* n+1 points */ + b[0].x = c[0].x; + b[0].y = c[0].y; + for(k = 1; k < 4; k++) { - x = xc + c*(prev_x-xc) + sx*(prev_y-yc); - y = yc + sy*(prev_x-xc) + c*(prev_y-yc); + b[k].x = c[k].x * u; + b[k].y = c[k].y * u; + u =u*t; + } - poly[p].x = _cdRound(x); - poly[p].y = _cdRound(y); + pt->x = b[3].x; + pt->y = b[3].y; + t1 = 1-t; + tt = t1; + for(k = 2; k >= 0; k--) + { + pt->x += b[k].x * tt; + pt->y += b[k].y * tt; + tt =tt*t1; + } +} - if (canvas->invert_yaxis) - poly[p].y = yc2 - poly[p].y; +static int sBezierNumSegments(cdCanvas* canvas, cdPoint start, const cdPoint* p) +{ + int i, K, dx, dy, d, + xmax = start.x, + ymax = start.y, + xmin = start.x, + ymin = start.y; - if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) - p++; + for (i = 1; i < 4; i++) + { + if (p[i].x > xmax) + xmax = p[i].x; + if (p[i].y > ymax) + ymax = p[i].y; + if (p[i].x < xmin) + xmin = p[i].x; + if (p[i].y < ymin) + ymin = p[i].y; + } - prev_x = x; - prev_y = y; + if (canvas->use_matrix) + { + cdMatrixTransformPoint(canvas->matrix, xmin, ymin, &xmin, &ymin); + cdMatrixTransformPoint(canvas->matrix, xmax, ymax, &xmax, &ymax); } - if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) + /* diagonal of the bouding box */ + dx = (xmax-xmin); + dy = (ymax-ymin); + d = (int)(sqrt(dx*dx + dy*dy)); + K = d / 8; + if (K < 8) K = 8; + return K; +} + +static int sfBezierNumSegments(cdCanvas* canvas, cdfPoint start, const cdfPoint* p) +{ + int i, K, d; + double dx, dy, + xmax = start.x, + ymax = start.y, + xmin = start.x, + ymin = start.y; + + for (i = 1; i < 4; i++) { - if (sector) /* cdSector */ + if (p[i].x > xmax) + xmax = p[i].x; + if (p[i].y > ymax) + ymax = p[i].y; + if (p[i].x < xmin) + xmin = p[i].x; + if (p[i].y < ymin) + ymin = p[i].y; + } + + if (canvas->use_matrix) + { + cdfMatrixTransformPoint(canvas->matrix, xmin, ymin, &xmin, &ymin); + cdfMatrixTransformPoint(canvas->matrix, xmax, ymax, &xmax, &ymax); + } + + /* diagonal of the bouding box */ + dx = (xmax-xmin); + dy = (ymax-ymin); + d = (int)(sqrt(dx*dx + dy*dy)); + K = d / 8; + if (K < 8) K = 8; + return K; +} + +static cdPoint* sPolyAddBezier(cdCanvas* canvas, cdPoint* poly, int *n, cdPoint start, const cdPoint* points) +{ + int k, K, new_n, i; + cdfPoint pt; + cdfPoint bezier_control[4]; + cdPoint* old_poly = poly; + + sBezierForm(start, points, bezier_control); + K = sBezierNumSegments(canvas, start, points); + + new_n = *n + K+1; /* add room for K+1 samples */ + poly = realloc(poly, sizeof(cdPoint)*new_n); + if (!poly) {free(old_poly); return NULL;} + i = *n; + + /* first segment */ + sBezierCurve(bezier_control, &pt, 0); + + poly[i].x = _cdRound(pt.x); + poly[i].y = _cdRound(pt.y); + + for(k = 1; k < K+1; k++) + { + sBezierCurve(bezier_control, &pt, (double)k/(double)K); + + poly[i+k].x = _cdRound(pt.x); + poly[i+k].y = _cdRound(pt.y); + } + + *n = new_n; + return poly; +} + +static cdfPoint* sPolyFAddBezier(cdCanvas* canvas, cdfPoint* poly, int *n, cdfPoint start, const cdPoint* points) +{ + int k, K, new_n, i; + cdfPoint pt; + cdfPoint bezier_control[4], bezier[3]; + cdfPoint* old_poly = poly; + + bezier[0].x = points[0].x; bezier[1].x = points[1].x; bezier[2].x = points[2].x; + bezier[0].y = points[0].y; bezier[1].y = points[1].y; bezier[2].y = points[2].y; + + sfBezierForm(start, bezier, bezier_control); + K = sfBezierNumSegments(canvas, start, bezier); + + new_n = *n + K+1; /* add room for K+1 samples */ + poly = realloc(poly, sizeof(cdfPoint)*new_n); + if (!poly) {free(old_poly); return NULL;} + i = *n; + + /* first segment */ + sBezierCurve(bezier_control, &pt, 0); + + poly[i] = pt; + + for(k = 1; k < K+1; k++) + { + sBezierCurve(bezier_control, &pt, (double)k/(double)K); + poly[i+k] = pt; + } + + *n = new_n; + return poly; +} + +static cdfPoint* sfPolyAddBezier(cdCanvas* canvas, cdfPoint* poly, int *n, cdfPoint start, const cdfPoint* points) +{ + int k, K, new_n, i; + cdfPoint pt; + cdfPoint bezier_control[4]; + cdfPoint* old_poly = poly; + + sfBezierForm(start, points, bezier_control); + K = sfBezierNumSegments(canvas, start, points); + + new_n = *n + K+1; /* add room for K+1 samples */ + poly = realloc(poly, sizeof(cdfPoint)*new_n); + if (!poly) {free(old_poly); return NULL;} + i = *n; + + /* first segment */ + sBezierCurve(bezier_control, &pt, 0); + + poly[i] = pt; + + for(k = 1; k < K+1; k++) + { + sBezierCurve(bezier_control, &pt, (double)k/(double)K); + poly[i+k] = pt; + } + + *n = new_n; + return poly; +} + +static void sPolyFBezier(cdCanvas* canvas, const cdPoint* points, int n) +{ + int i = 0, poly_n = 0; + cdfPoint* fpoly = NULL, start; + + start.x = points[0].x; + start.y = points[0].y; + + n--; /* first n is 4 */ + while (n >= 3) + { + fpoly = sPolyFAddBezier(canvas, fpoly, &poly_n, start, points+i+1); + start = fpoly[poly_n-1]; + n -= 3; i += 3; + } + + if (fpoly) + { + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, fpoly, poly_n); + free(fpoly); + } +} + +void cdSimPolyBezier(cdCanvas* canvas, const cdPoint* points, int n) +{ + int i = 0, poly_n = 0; + cdPoint* poly = NULL; + + if (canvas->line_width == 1 && canvas->cxFPoly) + { + sPolyFBezier(canvas, points, n); + return; + } + + n--; /* first n is 4 */ + while (n >= 3) + { + poly = sPolyAddBezier(canvas, poly, &poly_n, points[i], points+i+1); + if (!poly) return; + n -= 3; i += 3; + } + + if (poly) + { + cdCanvasPoly(canvas, CD_OPEN_LINES, poly, poly_n); + free(poly); + } +} + +void cdfSimPolyBezier(cdCanvas* canvas, const cdfPoint* points, int n) +{ + /* can be used only by drivers that implement cxFPoly */ + int i = 0, poly_n = 0; + cdfPoint* poly = NULL; + + n--; /* first n is 4 */ + while (n >= 3) + { + poly = sfPolyAddBezier(canvas, poly, &poly_n, points[i], points+i+1); + n -= 3; i += 3; + } + + if (poly) + { + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, poly_n); + free(poly); + } +} + +static cdPoint* sPolyAddLine(cdPoint* poly, int *n, cdPoint p1, cdPoint p2) +{ + int new_n, i; + cdPoint* old_poly = poly; + + new_n = *n + 2; + poly = realloc(poly, sizeof(cdPoint)*new_n); + if (!poly) {free(old_poly); return NULL;} + i = *n; + + poly[i] = p1; + poly[i+1] = p2; + + *n = new_n; + return poly; +} + +static cdfPoint* sfPolyAddLine(cdfPoint* poly, int *n, cdfPoint p1, cdfPoint p2) +{ + int new_n, i; + cdfPoint* old_poly = poly; + + new_n = *n + 2; + poly = realloc(poly, sizeof(cdfPoint)*new_n); + if (!poly) {free(old_poly); return NULL;} + i = *n; + + poly[i] = p1; + poly[i+1] = p2; + + *n = new_n; + return poly; +} + +void cdfSimPolyPath(cdCanvas* canvas, const cdfPoint* poly, int n) +{ + int p, i, current_set = 0, path_poly_n; + cdfPoint current; + cdfPoint* path_poly, *old_path_poly; + + current.x = 0; + current.y = 0; + current_set = 0; + + /* starts a new path */ + path_poly = NULL; + path_poly_n = 0; + + i = 0; + for (p=0; p<canvas->path_n; p++) + { + switch(canvas->path[p]) { - /* add center */ - poly[p].x = xc; - poly[p].y = yc; + case CD_PATH_NEW: + if (path_poly) + free(path_poly); + path_poly = NULL; + path_poly_n = 0; + current_set = 0; + break; + case CD_PATH_MOVETO: + if (i+1 > n) break; + current = poly[i]; + current_set = 1; + i++; + break; + case CD_PATH_LINETO: + if (i+1 > n) break; + path_poly = sfPolyAddLine(path_poly, &path_poly_n, current, poly[i]); + current = poly[i]; + current_set = 1; + i++; + break; + case CD_PATH_ARC: + { + double xc, yc, w, h; + double a1, a2; + + if (i+3 > n) break; + + if (!cdfCanvasGetArcPath(canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; + + if (current_set) + path_poly = sfPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, ¤t); + else + path_poly = sfPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, NULL); + + current = path_poly[path_poly_n-1]; + current_set = 1; + + i += 3; + } + break; + case CD_PATH_CURVETO: + if (i+3 > n) break; + if (!current_set) + { + current.x = poly[i].x; + current.y = poly[i].y; + } + path_poly = sfPolyAddBezier(canvas, path_poly, &path_poly_n, current, poly+i); + current = path_poly[path_poly_n-1]; + current_set = 1; + i += 3; + break; + case CD_PATH_CLOSE: + if (path_poly[path_poly_n-1].x != path_poly[0].x || + path_poly[path_poly_n-1].y != path_poly[0].y) + { + path_poly_n++; + old_path_poly = path_poly; + path_poly = (cdfPoint*)realloc(path_poly, sizeof(cdfPoint)*path_poly_n); + if (!path_poly) {free(old_path_poly); return;} + + /* add initial point */ + path_poly[path_poly_n-1].x = path_poly[0].x; + path_poly[path_poly_n-1].y = path_poly[0].y; + } + break; + case CD_PATH_FILL: + if (poly) + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, path_poly, path_poly_n); + break; + case CD_PATH_STROKE: + if (poly) + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, path_poly, path_poly_n); + break; + case CD_PATH_FILLSTROKE: + if (poly) + { + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, path_poly, path_poly_n); + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, path_poly, path_poly_n); + } + break; + case CD_PATH_CLIP: + if (poly) + canvas->cxFPoly(canvas->ctxcanvas, CD_CLIP, path_poly, path_poly_n); + break; } - else /* cdChord */ + } + + if (path_poly) + free(path_poly); +} + +static void sSimPolyFPath(cdCanvas* canvas, const cdPoint* poly, int n) +{ + int p, i, current_set = 0, path_poly_n; + cdfPoint current, pt; + cdfPoint* path_poly, *old_path_poly; + + current.x = 0; + current.y = 0; + current_set = 0; + + /* starts a new path */ + path_poly = NULL; + path_poly_n = 0; + + i = 0; + for (p=0; p<canvas->path_n; p++) + { + switch(canvas->path[p]) { - /* add initial point */ - poly[p].x = poly[0].x; - poly[p].y = poly[0].y; + case CD_PATH_NEW: + if (path_poly) + free(path_poly); + path_poly = NULL; + path_poly_n = 0; + current_set = 0; + break; + case CD_PATH_MOVETO: + if (i+1 > n) break; + current.x = poly[i].x; + current.y = poly[i].y; + current_set = 1; + i++; + break; + case CD_PATH_LINETO: + if (i+1 > n) break; + pt.x = poly[i].x; + pt.y = poly[i].y; + path_poly = sfPolyAddLine(path_poly, &path_poly_n, current, pt); + current.x = poly[i].x; + current.y = poly[i].y; + current_set = 1; + i++; + break; + case CD_PATH_ARC: + { + double xc, yc, w, h; + double a1, a2; + + if (i+3 > n) break; + + if (!cdCanvasGetArcPathF(canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; + + if (current_set) + path_poly = sfPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, ¤t); + else + path_poly = sfPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, NULL); + + current = path_poly[path_poly_n-1]; + current_set = 1; + + i += 3; + } + break; + case CD_PATH_CURVETO: + if (i+3 > n) break; + if (!current_set) + { + current.x = poly[i].x; + current.y = poly[i].y; + } + path_poly = sPolyFAddBezier(canvas, path_poly, &path_poly_n, current, poly+i); + current = path_poly[path_poly_n-1]; + current_set = 1; + i += 3; + break; + case CD_PATH_CLOSE: + if (path_poly[path_poly_n-1].x != path_poly[0].x || + path_poly[path_poly_n-1].y != path_poly[0].y) + { + path_poly_n++; + old_path_poly = path_poly; + path_poly = (cdfPoint*)realloc(path_poly, sizeof(cdfPoint)*path_poly_n); + if (!path_poly) {free(old_path_poly); return;} + + /* add initial point */ + path_poly[path_poly_n-1].x = path_poly[0].x; + path_poly[path_poly_n-1].y = path_poly[0].y; + } + break; + case CD_PATH_FILL: + if (poly) + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, path_poly, path_poly_n); + break; + case CD_PATH_STROKE: + if (poly) + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, path_poly, path_poly_n); + break; + case CD_PATH_FILLSTROKE: + if (poly) + { + canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, path_poly, path_poly_n); + canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, path_poly, path_poly_n); + } + break; + case CD_PATH_CLIP: + if (poly) + canvas->cxFPoly(canvas->ctxcanvas, CD_CLIP, path_poly, path_poly_n); + break; } - p++; } - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, p); - - free(poly); + if (path_poly) + free(path_poly); } -void cdsectorSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +void cdSimPolyPath(cdCanvas* canvas, const cdPoint* poly, int n) { - cdSimElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 1); + int p, i, current_set = 0, path_poly_n; + cdPoint current; + cdPoint* path_poly, *old_path_poly; + + if (canvas->line_width == 1 && canvas->cxFPoly) + { + int has_curve = 0; + for (p=0; p<canvas->path_n; p++) + { + if (canvas->path[p] == CD_PATH_ARC || + canvas->path[p] == CD_PATH_CURVETO) + has_curve = 1; + if (canvas->path[p] == CD_PATH_STROKE && + has_curve == 1) + { + sSimPolyFPath(canvas, poly, n); + return; + } + } + } + + current.x = 0; + current.y = 0; + current_set = 0; + + /* starts a new path */ + path_poly = NULL; + path_poly_n = 0; + + i = 0; + for (p=0; p<canvas->path_n; p++) + { + switch(canvas->path[p]) + { + case CD_PATH_NEW: + if (path_poly) + free(path_poly); + path_poly = NULL; + path_poly_n = 0; + current_set = 0; + break; + case CD_PATH_MOVETO: + if (i+1 > n) break; + current = poly[i]; + current_set = 1; + i++; + break; + case CD_PATH_LINETO: + if (i+1 > n) break; + path_poly = sPolyAddLine(path_poly, &path_poly_n, current, poly[i]); + if (!path_poly) return; + current = poly[i]; + current_set = 1; + i++; + break; + case CD_PATH_ARC: + { + int xc, yc, w, h; + double a1, a2; + + if (i+3 > n) break; + + if (!cdCanvasGetArcPath(canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; + + if (current_set) + path_poly = sPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, ¤t); + else + path_poly = sPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, NULL); + if (!path_poly) return; + + current = path_poly[path_poly_n-1]; + current_set = 1; + + i += 3; + } + break; + case CD_PATH_CURVETO: + if (i+3 > n) break; + if (!current_set) + { + current.x = poly[i].x; + current.y = poly[i].y; + } + path_poly = sPolyAddBezier(canvas, path_poly, &path_poly_n, current, poly+i); + if (!path_poly) return; + current = path_poly[path_poly_n-1]; + current_set = 1; + i += 3; + break; + case CD_PATH_CLOSE: + if (path_poly[path_poly_n-1].x != path_poly[0].x || + path_poly[path_poly_n-1].y != path_poly[0].y) + { + path_poly_n++; + old_path_poly = path_poly; + path_poly = (cdPoint*)realloc(path_poly, sizeof(cdPoint)*path_poly_n); + if (!path_poly) {free(old_path_poly); return;} + + /* add initial point */ + path_poly[path_poly_n-1].x = path_poly[0].x; + path_poly[path_poly_n-1].y = path_poly[0].y; + } + break; + case CD_PATH_FILL: + if (poly) + cdCanvasPoly(canvas, CD_FILL, path_poly, path_poly_n); + break; + case CD_PATH_STROKE: + if (poly) + cdCanvasPoly(canvas, CD_OPEN_LINES, path_poly, path_poly_n); + break; + case CD_PATH_FILLSTROKE: + if (poly) + { + cdCanvasPoly(canvas, CD_FILL, path_poly, path_poly_n); + cdCanvasPoly(canvas, CD_OPEN_LINES, path_poly, path_poly_n); + } + break; + case CD_PATH_CLIP: + if (poly) + cdCanvasPoly(canvas, CD_CLIP, path_poly, path_poly_n); + break; + } + } + + if (path_poly) + free(path_poly); } -void cdchordSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) +/************************************************************************/ + +/* Simulation functions that depend on the simulation base driver. */ +static void cdSimPolyFill(cdCanvas* canvas, cdPoint* poly, int n); +static void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n); +static void cdfSimPolyLine(cdCanvas* canvas, const cdfPoint* poly, int n); + +void cdSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) { - cdSimElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 0); + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + + switch(mode) + { + case CD_CLOSED_LINES: + poly[n] = poly[0]; /* can do that because poly is internal of the CD */ + n++; + /* continue */ + case CD_OPEN_LINES: + cdSimPolyLine(canvas, poly, n); + break; + case CD_BEZIER: + cdSimPolyBezier(canvas, poly, n); + break; + case CD_PATH: + cdSimPolyPath(canvas, poly, n); + break; + case CD_FILL: + cdSimPolyFill(canvas, poly, n); + break; + } } -void cdpolySIM(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +void cdfSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* fpoly, int n) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; - int i, reset = 1; switch(mode) { case CD_CLOSED_LINES: - poly[n] = poly[0]; + fpoly[n] = fpoly[0]; n++; /* continue */ case CD_OPEN_LINES: - if (simLineStyleNoReset) /* Bezier simulation use several poly */ - { - reset = 0; - simLineStyleNoReset = 1; - } - for (i = 0; i< n - 1; i++) - canvas->cxLine(canvas->ctxcanvas, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y); - if (reset) simLineStyleNoReset = 0; + cdfSimPolyLine(canvas, fpoly, n); break; case CD_BEZIER: - simLineStyleNoReset = 1; - cdSimPolyBezier(canvas, poly, n); - simLineStyleNoReset = 0; + cdfSimPolyBezier(canvas, fpoly, n); + break; + case CD_PATH: + cdfSimPolyPath(canvas, fpoly, n); break; + case CD_CLIP: case CD_FILL: { - /* must set line attributes here, because fill simulation use cxLine */ - int oldwidth = cdCanvasLineWidth(canvas, 1); - int oldstyle = cdCanvasLineStyle(canvas, CD_CONTINUOUS); - int old_use_matrix = canvas->use_matrix; + cdPoint* poly = malloc(sizeof(cdPoint)*n); + int i; - if (canvas->use_matrix && !canvas->invert_yaxis) + for (i = 0; i<n; i++) { - for(i = 0; i < n; i++) - cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); + poly[i].x = _cdRound(fpoly[i].x); + poly[i].y = _cdRound(fpoly[i].y); } - /* must disable transformation here, because line simulation use cxPixel */ - canvas->use_matrix = 0; + cdCanvasPoly(canvas, mode, poly, n); - simPolyFill(canvas->simulation, poly, n); + free(poly); + } + break; + } +} - canvas->use_matrix = old_use_matrix; - cdCanvasLineStyle(canvas, oldstyle); - cdCanvasLineWidth(canvas, oldwidth); +void cdSimMark(cdCanvas* canvas, int x, int y) +{ + int oldinteriorstyle = canvas->interior_style; + int oldlinestyle = canvas->line_style; + int oldlinewidth = canvas->line_width; + int size = canvas->mark_size; + int half_size = size/2; + int bottom = y-half_size; + int top = y+half_size; + int left = x-half_size; + int right = x+half_size; + + if (canvas->interior_style != CD_SOLID && + (canvas->mark_type == CD_CIRCLE || + canvas->mark_type == CD_BOX || + canvas->mark_type == CD_DIAMOND)) + cdCanvasInteriorStyle(canvas, CD_SOLID); + + if (canvas->line_style != CD_CONTINUOUS && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineStyle(canvas, CD_CONTINUOUS); + + if (canvas->line_width != 1 && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineWidth(canvas, 1); + + switch (canvas->mark_type) + { + case CD_STAR: + canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top); + canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom); + /* continue */ + case CD_PLUS: + canvas->cxLine(canvas->ctxcanvas, left, y, right, y); + canvas->cxLine(canvas->ctxcanvas, x, bottom, x, top); + break; + case CD_X: + canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top); + canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom); + break; + case CD_HOLLOW_CIRCLE: + canvas->cxArc(canvas->ctxcanvas, x, y, size, size, 0, 360); + break; + case CD_HOLLOW_BOX: + canvas->cxRect(canvas->ctxcanvas, left, right, bottom, top); + break; + case CD_CIRCLE: + canvas->cxSector(canvas->ctxcanvas, x, y, size, size, 0, 360); + break; + case CD_BOX: + canvas->cxBox(canvas->ctxcanvas, left, right, bottom, top); + break; + case CD_HOLLOW_DIAMOND: + case CD_DIAMOND: + { + cdPoint poly[5]; /* leave room for one more point */ + poly[0].x = left; + poly[0].y = y; + poly[1].x = x; + poly[1].y = top; + poly[2].x = right; + poly[2].y = y; + poly[3].x = x; + poly[3].y = bottom; + + if (canvas->mark_type == CD_DIAMOND) + cdCanvasPoly(canvas, CD_FILL, poly, 4); + else + cdCanvasPoly(canvas, CD_CLOSED_LINES, poly, 4); } break; } + + if (canvas->interior_style != oldinteriorstyle && + (canvas->mark_type == CD_CIRCLE || + canvas->mark_type == CD_BOX || + canvas->mark_type == CD_DIAMOND)) + cdCanvasInteriorStyle(canvas, oldinteriorstyle); + + if (canvas->line_style != oldlinestyle && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineStyle(canvas, oldlinestyle); + + if (canvas->line_width != oldlinewidth && + (canvas->mark_type == CD_STAR || + canvas->mark_type == CD_PLUS || + canvas->mark_type == CD_X || + canvas->mark_type == CD_HOLLOW_BOX || + canvas->mark_type == CD_HOLLOW_CIRCLE || + canvas->mark_type == CD_HOLLOW_DIAMOND)) + cdCanvasLineWidth(canvas, oldlinewidth); +} + +void cdSimPutImageRectRGBA(cdCanvas* canvas, 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 size, i, j, dst, src, *fx, *fy, rw, rh; + unsigned char *ar, *ag, *ab, al; + (void)ih; + + size = w * h; + ar = (unsigned char*)malloc(size*3); + if (!ar) return; + ag = ar + size; + ab = ag + size; + + canvas->cxGetImageRGB(canvas->ctxcanvas, ar, ag, ab, x, y, w, h); + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + fx = cdGetZoomTable(w, rw, xmin); + fy = cdGetZoomTable(h, rh, ymin); + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + dst = j * w + i; + src = fy[j] * iw + fx[i]; + al = a[src]; + ar[dst] = CD_ALPHA_BLEND(r[src], ar[dst], al); + ag[dst] = CD_ALPHA_BLEND(g[src], ag[dst], al); + ab[dst] = CD_ALPHA_BLEND(b[src], ab[dst], al); + } + } + + canvas->cxPutImageRectRGB(canvas->ctxcanvas, w, h, ar, ag, ab, x, y, w, h, 0, 0, 0, 0); + + free(ar); + + free(fx); + free(fy); +} + +void cdSimPutImageRectRGB(cdCanvas* canvas, 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 height = ymax-ymin+1; + unsigned char* map; + int pal_size = 1L << canvas->bpp; + long colors[256]; + (void)ih; + + map = (unsigned char*)malloc(iw * height); + if (!map) + return; + + if (pal_size == 2) /* probably a laser printer, use a gray image for better results */ + cdRGB2Gray(iw, height, r+ymin*iw, g+ymin*iw, b+ymin*iw, map, colors); + else + cdRGB2Map(iw, height, r+ymin*iw, g+ymin*iw, b+ymin*iw, map, pal_size, colors); + + canvas->cxPutImageRectMap(canvas->ctxcanvas, iw, height, map, colors, x, y, w, h, xmin, xmax, 0, height-1); + + free(map); +} + + +/************************************************************************/ + +#include "cd_truetype.h" +#include "sim.h" + +static void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n) +{ + int i, reset = 1, transform = 0; + int old_use_matrix = canvas->use_matrix; + int x1, y1, x2, y2; + + if (canvas->use_matrix) + transform = 1; + + /* disable line transformation */ + canvas->use_matrix = 0; + + /* prepare the line style for several lines */ + if (simLineStyleNoReset) + { + reset = 0; + simLineStyleNoReset = 1; + } + + x1 = poly[0].x; + y1 = poly[0].y; + + if (transform) + cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); + + for (i = 0; i < n-1; i++) + { + x2 = poly[i+1].x; + y2 = poly[i+1].y; + + if (transform) + cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); + + if(canvas->line_width > 1) + simLineThick(canvas, x1, y1, x2, y2); + else + simLineThin(canvas, x1, y1, x2, y2); + + x1 = x2; + y1 = y2; + } + + if (reset) simLineStyleNoReset = 0; + canvas->use_matrix = old_use_matrix; } + +static void cdfSimPolyLine(cdCanvas* canvas, const cdfPoint* poly, int n) +{ + int i, reset = 1, transform = 0; + int old_use_matrix = canvas->use_matrix; + double x1, y1, x2, y2; + int last_xi_a = -65535, + last_yi_a = -65535, + last_xi_b = -65535, + last_yi_b = -65535; + + if (canvas->use_matrix) + transform = 1; + + /* disable line transformation */ + canvas->use_matrix = 0; + + /* prepare the line style for several lines */ + if (simLineStyleNoReset) + { + reset = 0; + simLineStyleNoReset = 1; + } + + x1 = poly[0].x; + y1 = poly[0].y; + + if (transform) + cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); + + for (i = 0; i < n-1; i++) + { + x2 = poly[i+1].x; + y2 = poly[i+1].y; + + if (transform) + cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); + + if(canvas->line_width > 1) + simfLineThick(canvas, x1, y1, x2, y2); + else + simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b); + + x1 = x2; + y1 = y2; + } + + if (reset) simLineStyleNoReset = 0; + canvas->use_matrix = old_use_matrix; +} + +static int sCheckIsBox(cdPoint* poly) +{ + if (poly[0].x == poly[1].x && + poly[1].y == poly[2].y && + poly[2].x == poly[3].x && + poly[3].y == poly[0].y) + return 1; + + if (poly[0].y == poly[1].y && + poly[1].x == poly[2].x && + poly[2].y == poly[3].y && + poly[3].x == poly[0].x) + return 1; + + return 0; +} + +static void sGetBox(cdPoint* poly, int *xmin, int *xmax, int *ymin, int *ymax) +{ + int i; + *xmin = poly[0].x; + *xmax = poly[0].x; + *ymin = poly[0].y; + *ymax = poly[0].y; + for (i=1; i<4; i++) + { + if (poly[i].x < *xmin) + *xmin = poly[i].x; + if (poly[i].y < *ymin) + *ymin = poly[i].y; + if (poly[i].x > *xmax) + *xmax = poly[i].x; + if (poly[i].y > *ymin) + *ymax = poly[i].y; + } +} + +static void cdSimPolyFill(cdCanvas* canvas, cdPoint* poly, int n) +{ + int old_use_matrix = canvas->use_matrix; + + if (canvas->use_matrix) + { + int i; + for(i = 0; i < n; i++) /* can do that because poly is internal of the CD, and it will NOT be stored */ + cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); + } + + /* disable fill transformation */ + canvas->use_matrix = 0; + + if (n == 4 && sCheckIsBox(poly)) + { + int xmin, xmax, ymin, ymax; + sGetBox(poly, &xmin, &xmax, &ymin, &ymax); + simFillHorizBox(canvas->simulation, xmin, xmax, ymin, ymax); + } + else + simPolyFill(canvas->simulation, poly, n); + + canvas->use_matrix = old_use_matrix; +} + diff --git a/cd/src/sim/truetype.h b/cd/src/sim/truetype.h deleted file mode 100755 index 5675998..0000000 --- a/cd/src/sim/truetype.h +++ /dev/null @@ -1,46 +0,0 @@ -/** \file - * \brief Text and Font Simulation using FreeType library. - * - * See Copyright Notice in cd.h - */ - -#ifndef __TRUETYPE_H -#define __TRUETYPE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ft2build.h" -#include FT_FREETYPE_H - -/* - In CD version 4.4 we start to use FreeType 2. - Only TrueType font support is enabled. -*/ - -typedef struct _cdTT_Text -{ - FT_Library library; - FT_Face face; - - unsigned char* rgba_data; - int rgba_data_size; - - int max_height; - int max_width; - int descent; - int ascent; - -}cdTT_Text; - -cdTT_Text* cdTT_create(void); -void cdTT_free(cdTT_Text * tt_text); -int cdTT_load(cdTT_Text * tt_text, const char *font,int size, double xres, double yres); - -#ifdef __cplusplus -} -#endif - -#endif /* ifndef _CD_TRUETYPE_ */ - |