summaryrefslogtreecommitdiff
path: root/src/drivers/Android/Fl_Android_Graphics_Driver.cxx
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2018-03-22 15:27:02 +0000
committerMatthias Melcher <fltk@matthiasm.com>2018-03-22 15:27:02 +0000
commit0b8116ff72145816c3e1d4909038c126327e7bf2 (patch)
tree6559a0aca4e1047fe4906fa474ab463fc3229778 /src/drivers/Android/Fl_Android_Graphics_Driver.cxx
parent3a20682764807173ec6b0e354ede9b57930ff6a7 (diff)
Android: Implemented vector drawing and polygons.
Started to implement arc and pie drawing git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12783 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/drivers/Android/Fl_Android_Graphics_Driver.cxx')
-rw-r--r--src/drivers/Android/Fl_Android_Graphics_Driver.cxx447
1 files changed, 447 insertions, 0 deletions
diff --git a/src/drivers/Android/Fl_Android_Graphics_Driver.cxx b/src/drivers/Android/Fl_Android_Graphics_Driver.cxx
index 71ffa6224..fbd85fc34 100644
--- a/src/drivers/Android/Fl_Android_Graphics_Driver.cxx
+++ b/src/drivers/Android/Fl_Android_Graphics_Driver.cxx
@@ -24,7 +24,9 @@
#include <FL/Fl.H>
#include <FL/platform.H>
#include <errno.h>
+#include <math.h>
+static int sign(int v) { return (v<0) ? -1 : 1; }
/*
* By linking this module, the following static method will instantiate the
@@ -229,6 +231,451 @@ void Fl_Android_Graphics_Driver::point_unscaled(float x, float y)
}
+/**
+ * Draw a line.
+ * FIXME: it is incredibly inefficient to call 'point', especially for long lines
+ * FIXME: clipping maust be moved into this call and drawing to the screen should happen right here
+ * FIXME: line width is not considered
+ */
+void Fl_Android_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1)
+{
+ if (x==x1) {
+ return yxline(x, y, y1);
+ }
+ if (y==y1) {
+ return xyline(x, y, x1);
+ }
+ // Bresenham
+ int w = x1 - x, dx = abs(w);
+ int h = y1 - y, dy = abs(h);
+ int dx1 = sign(w), dy1 = sign(h), dx2, dy2;
+ int min, max;
+ if (dx < dy) {
+ min = dx; max = dy;
+ dx2 = 0;
+ dy2 = dy1;
+ } else {
+ min = dy; max = dx;
+ dx2 = dx1;
+ dy2 = 0;
+ }
+ int num = max/2;
+ for (int i=max+1; i>0; i--) {
+ point_unscaled(x, y);
+ num += min;
+ if (num>=max) {
+ num -= max;
+ x += dx1;
+ y += dy1;
+ } else {
+ x += dx2;
+ y += dy2;
+ }
+ }
+}
+
+/**
+ * Reset the vertex counter to zero.
+ */
+void Fl_Android_Graphics_Driver::begin_vertices()
+{
+ pnVertex = 0;
+ pVertexGapStart = 0;
+}
+
+/**
+ * Add a vertex to the vertex list. Dynamically allocates memory.
+ * @param x, y position of the vertex after matrix transformation
+ * @param gap line and loop call offer to leave a gap in the drawing
+ */
+void Fl_Android_Graphics_Driver::add_vertex(float x, float y, bool gap)
+{
+ if (pnVertex == pNVertex) {
+ pNVertex += 16;
+ pVertex = (Vertex*)::realloc(pVertex, pNVertex*sizeof(Vertex));
+ }
+ pVertex[pnVertex].set(x, y);
+ pVertex[pnVertex].pIsGap = gap;
+ pnVertex++;
+}
+
+/**
+ * Start a list of vertices to draw multiple points.
+ */
+void Fl_Android_Graphics_Driver::begin_points()
+{
+ begin_vertices();
+ Fl_Scalable_Graphics_Driver::begin_points();
+}
+
+/**
+ * Start a list of vertices to draw a polyline.
+ */
+void Fl_Android_Graphics_Driver::begin_line()
+{
+ begin_vertices();
+ Fl_Scalable_Graphics_Driver::begin_line();
+}
+
+/**
+ * Start a list of vertices to draw a line loop.
+ */
+void Fl_Android_Graphics_Driver::begin_loop()
+{
+ begin_vertices();
+ Fl_Scalable_Graphics_Driver::begin_loop();
+}
+
+/**
+ * Start a list of vertices to draw a polygon.
+ */
+void Fl_Android_Graphics_Driver::begin_polygon()
+{
+ begin_vertices();
+ Fl_Scalable_Graphics_Driver::begin_polygon();
+}
+
+/**
+ * Start a list of vertices to draw a complex polygon.
+ */
+void Fl_Android_Graphics_Driver::begin_complex_polygon()
+{
+ begin_vertices();
+ Fl_Scalable_Graphics_Driver::begin_complex_polygon();
+}
+
+/**
+ * Draw all stored vertices as points.
+ */
+void Fl_Android_Graphics_Driver::end_points()
+{
+ for (int i=0; i<pnVertex; ++i) {
+ Vertex &v = pVertex[i];
+ if (!v.pIsGap)
+ point_unscaled(v.pX, v.pY);
+ }
+}
+
+/**
+ * Draw all stored vertices as a polyline.
+ */
+void Fl_Android_Graphics_Driver::end_line()
+{
+ Vertex &v1 = pVertex[0];
+ for (int i=1; i<pnVertex; ++i) {
+ Vertex &v2 = pVertex[i];
+ if (!v1.pIsGap && !v2.pIsGap)
+ line_unscaled(v1.pX, v1.pY, v2.pX, v2.pY);
+ v1 = v2;
+ }
+}
+
+/**
+ * Draw all stored vertices as a polyline loop.
+ */
+void Fl_Android_Graphics_Driver::end_loop()
+{
+ gap();
+ Vertex &v1 = pVertex[0];
+ for (int i=1; i<pnVertex; ++i) {
+ Vertex &v2 = pVertex[i];
+ if (!v1.pIsGap)
+ line_unscaled(v1.pX, v1.pY, v2.pX, v2.pY);
+ v1 = v2;
+ }
+}
+
+/**
+ * Draw all stored vertices as a polygon.
+ * FIXME: these calls are very ineffiecient. Avoid pointer lookup.
+ * FIXME: use the current clipping rect to accelerate rendering
+ * FIXME: unmix float and int
+ */
+void Fl_Android_Graphics_Driver::end_polygon(int begin, int end)
+{
+ if (end - begin < 2) return;
+
+ Vertex *v = pVertex+0;
+ int xMin = v->pX, xMax = xMin, yMin = v->pY, yMax = yMin;
+ for (int i = begin+1; i < end; i++) {
+ v = pVertex+i;
+ if (v->pX < xMin) xMin = v->pX;
+ if (v->pX > xMax) xMax = v->pX;
+ if (v->pY < yMin) yMin = v->pY;
+ if (v->pY > yMax) yMax = v->pY;
+ }
+ xMax++; yMax++;
+
+ int nodes, nodeX[end - begin], pixelX, pixelY, i, j, swap;
+
+ // Loop through the rows of the image.
+ for (pixelY = yMin; pixelY < yMax; pixelY++) {
+ // Build a list of nodes.
+ nodes = 0;
+ j = begin;
+ for (i = begin+1; i < end; i++) {
+ if ( pVertex[i].pY < pixelY && pVertex[j].pY >= pixelY
+ || pVertex[j].pY < pixelY && pVertex[i].pY >= pixelY)
+ {
+ float dy = pVertex[j].pY - pVertex[i].pY;
+ if (fabsf(dy)>.0001) {
+ nodeX[nodes++] = (int)(pVertex[i].pX +
+ (pixelY - pVertex[i].pY) / dy
+ * (pVertex[j].pX - pVertex[i].pX));
+ } else {
+ nodeX[nodes++] = pVertex[i].pX;
+ }
+ }
+ j = i;
+ }
+
+ // Sort the nodes, via a simple “Bubble” sort.
+ i = 0;
+ while (i < nodes - 1) {
+ if (nodeX[i] > nodeX[i + 1]) {
+ swap = nodeX[i];
+ nodeX[i] = nodeX[i + 1];
+ nodeX[i + 1] = swap;
+ if (i) i--;
+ } else {
+ i++;
+ }
+ }
+
+ // Fill the pixels between node pairs.
+ for (i = 0; i < nodes; i += 2) {
+ if (nodeX[i] >= xMax) break;
+ if (nodeX[i + 1] > xMin) {
+ if (nodeX[i] < xMin) nodeX[i] = xMin;
+ if (nodeX[i + 1] > xMax) nodeX[i + 1] = xMax;
+ xyline_unscaled(nodeX[i], pixelY, nodeX[i + 1]);
+ }
+ }
+ }
+
+}
+
+/**
+ * Draw all stored vertices as a polygon.
+ * Mind the gap!
+ */
+void Fl_Android_Graphics_Driver::end_polygon()
+{
+ if (pnVertex==0) return;
+ gap();
+ int start = 0, end = 0;
+ for (int i=0; i<pnVertex; i++) {
+ if (pVertex[i].pIsGap) {
+ end = i+1;
+ end_polygon(start, end);
+ start = end;
+ i++;
+ }
+ }
+}
+
+/**
+ * Draw all stored vertices as a possibly self-intersecting polygon.
+ * FIXME: these calls are very ineffiecient. Avoid pointer lookup.
+ * FIXME: use the current clipping rect to accelerate rendering
+ * FIXME: unmix float and int
+ */
+void Fl_Android_Graphics_Driver::end_complex_polygon()
+{
+ if (pnVertex < 2) return;
+
+ gap(); // adds the first coordinate of this loop and marks it as a gap
+ int begin = 0, end = pnVertex;
+
+ Vertex *v = pVertex+0;
+ int xMin = v->pX, xMax = xMin, yMin = v->pY, yMax = yMin;
+ for (int i = begin+1; i < end; i++) {
+ v = pVertex+i;
+ if (v->pX < xMin) xMin = v->pX;
+ if (v->pX > xMax) xMax = v->pX;
+ if (v->pY < yMin) yMin = v->pY;
+ if (v->pY > yMax) yMax = v->pY;
+ }
+ xMax++; yMax++;
+
+ int nodes, nodeX[end - begin], pixelX, pixelY, i, j, swap;
+
+ // Loop through the rows of the image.
+ for (pixelY = yMin; pixelY < yMax; pixelY++) {
+ // Build a list of nodes.
+ nodes = 0;
+ for (i = begin+1; i < end; i++) {
+ j = i-1;
+ if (pVertex[j].pIsGap)
+ continue;
+ if ( pVertex[i].pY < pixelY && pVertex[j].pY >= pixelY
+ || pVertex[j].pY < pixelY && pVertex[i].pY >= pixelY)
+ {
+ float dy = pVertex[j].pY - pVertex[i].pY;
+ if (fabsf(dy)>.0001) {
+ nodeX[nodes++] = (int)(pVertex[i].pX +
+ (pixelY - pVertex[i].pY) / dy
+ * (pVertex[j].pX - pVertex[i].pX));
+ } else {
+ nodeX[nodes++] = pVertex[i].pX;
+ }
+ }
+ }
+ //Fl_Android_Application::log_e("%d nodes (must be even!)", nodes);
+
+ // Sort the nodes, via a simple “Bubble” sort.
+ i = 0;
+ while (i < nodes - 1) {
+ if (nodeX[i] > nodeX[i + 1]) {
+ swap = nodeX[i];
+ nodeX[i] = nodeX[i + 1];
+ nodeX[i + 1] = swap;
+ if (i) i--;
+ } else {
+ i++;
+ }
+ }
+
+ // Fill the pixels between node pairs.
+ for (i = 0; i < nodes; i += 2) {
+ if (nodeX[i] >= xMax) break;
+ if (nodeX[i + 1] > xMin) {
+ if (nodeX[i] < xMin) nodeX[i] = xMin;
+ if (nodeX[i + 1] > xMax) nodeX[i + 1] = xMax;
+ xyline_unscaled(nodeX[i], pixelY, nodeX[i + 1]);
+ }
+ }
+ }
+}
+
+/**
+ * Add a gap to a polyline drawing
+ */
+void Fl_Android_Graphics_Driver::gap()
+{
+ // drop gaps at the start or gap after gap
+ if (pnVertex==0 || pnVertex==pVertexGapStart)
+ return;
+
+ // create a loop
+ Vertex &v = pVertex[pVertexGapStart];
+ add_vertex(v.pX, v.pY, true);
+ pVertexGapStart = pnVertex;
+}
+
+/**
+ * Add a vertex to the list.
+ * TODO: we should maintain a bounding box for faster clipping.
+ */
+void Fl_Android_Graphics_Driver::transformed_vertex0(float x, float y)
+{
+ add_vertex(x, y);
+}
+
+
+//void Fl_Pico_Graphics_Driver::circle(double x, double y, double r)
+//{
+// begin_loop();
+// double X = r;
+// double Y = 0;
+// fl_vertex(x+X,y+Y);
+//
+// double rx = fabs(transform_dx(r, r));
+// double ry = fabs(transform_dy(r, r));
+//
+// double circ = M_PI*0.5*(rx+ry);
+// int segs = circ * 360 / 1000; // every line is about three pixels long
+// if (segs<16) segs = 16;
+//
+// double A = 2*M_PI;
+// int i = segs;
+//
+// if (i) {
+// double epsilon = A/i; // Arc length for equal-size steps
+// double cos_e = cos(epsilon); // Rotation coefficients
+// double sin_e = sin(epsilon);
+// do {
+// double Xnew = cos_e*X + sin_e*Y;
+// Y = -sin_e*X + cos_e*Y;
+// fl_vertex(x + (X=Xnew), y + Y);
+// } while (--i);
+// }
+// end_loop();
+//}
+
+/**
+ * Draw an arc.
+ * @param xi
+ * @param yi
+ * @param w
+ * @param h
+ * @param a1
+ * @param a2
+ * FIXME: float-to-int interpolation is horrible!
+ */
+void Fl_Android_Graphics_Driver::arc_unscaled(float xi, float yi, float w, float h, double a1, double a2)
+{
+ if (a2<=a1) return;
+
+ double rx = w/2.0;
+ double ry = h/2.0;
+ double x = xi + rx;
+ double y = yi + ry;
+ double circ = M_PI*0.5*(rx+ry);
+ int i, segs = circ * (a2-a1) / 1000; // every line is about three pixels long
+ if (segs<3) segs = 3;
+
+ int px, py;
+ a1 = a1/180*M_PI;
+ a2 = a2/180*M_PI;
+ double step = (a2-a1)/segs;
+
+ int nx = x + cos(a1)*rx;
+ int ny = y - sin(a1)*ry;
+ for (i=segs; i>0; i--) {
+ a1+=step;
+ px = nx; py = ny;
+ nx = x + cos(a1)*rx;
+ ny = y - sin(a1)*ry;
+ line_unscaled(px, py, nx, ny);
+ }
+}
+
+void Fl_Android_Graphics_Driver::pie_unscaled(float xi, float yi, float w, float h, double b1, double b2)
+{
+ Fl_Color c = fl_color();
+ fl_color(FL_RED);
+ double a1 = b1/180*M_PI;
+ double a2 = b2/180*M_PI;
+ double rx = w/2.0;
+ double ry = h/2.0;
+ double x = xi + rx;
+ double y = yi + ry;
+ double yMin = y - sin(a1), yMax = y - sin(a2);
+ if (yMin>yMax) { double s = yMin; yMin = yMax; yMax = s; }
+ Fl_Android_Application::log_e("------ PI");
+ for (double i=y-ry; i<=y+ry; i++) {
+ double a = asin((i-y)/ry);
+ double aR = a; if (aR<0.0) aR+=2*M_PI;
+ double aL = M_PI-a;
+ Fl_Android_Application::log_e("%g %g", aL, aR);
+#if 0
+ if (aL>=a1 && aL<=a2)
+ xyline_unscaled(x-cos(a)*rx, i, x);
+
+ if (aR>=a1 && aR<=a2)
+ xyline_unscaled(x, i, x+cos(a)*rx);
+#else
+ xyline_unscaled(x-cos(a)*rx, i, x+cos(a)*rx);
+#endif
+ //xyline_unscaled(sin(a)*rx, i, y);
+ }
+ fl_color(FL_GREEN);
+ line_unscaled(x, y, x+cos(0.5*M_PI)*rx, y+sin(0.5*M_PI)*ry);
+ fl_color(c);
+}
+
+
#if 0