summaryrefslogtreecommitdiff
path: root/src/sim/sim_other.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/sim_other.c')
-rw-r--r--src/sim/sim_other.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/src/sim/sim_other.c b/src/sim/sim_other.c
new file mode 100644
index 0000000..0954406
--- /dev/null
+++ b/src/sim/sim_other.c
@@ -0,0 +1,411 @@
+/** \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);
+}