summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2022-12-05 19:27:12 +0100
committerGitHub <noreply@github.com>2022-12-05 19:27:12 +0100
commit9f92972729008a87887e1b1e2d35438102e91a9e (patch)
treed6a0fd12508ab89a9189aaaba46f608761357f89 /src/drivers
parenta8923a0fd4424a07fff247fe1167909264f8a117 (diff)
Implement fl_complex_polygon() for OpenGL (#570)
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx144
1 files changed, 139 insertions, 5 deletions
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx
index b5ec90bf4..fd4326e08 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx
@@ -26,6 +26,21 @@
#include <FL/gl.h>
#include <FL/math.h>
+// OpenGL does not support rednering non-convex polygons. Calling
+// glBegin(GL_POLYGON); witha complex outline will create rather random
+// errors, often overwrinting gaps and holes.
+//
+// Defining SLOW_COMPLEX_POLY will activate a line-by-line drawing method
+// for complex polygons that is correct for FLTK, but also a lot slower.
+//
+// It's recommended that SLOW_COMPLEX_POLY is defined, but fl_begin_polygon()
+// is used instead of fl_begin_complex_polygon() whenever possible.
+
+//#undef SLOW_COMPLEX_POLY
+#define SLOW_COMPLEX_POLY
+#ifdef SLOW_COMPLEX_POLY
+# define GAP (1e9f)
+#endif
// Event though there are faster versions of the functions in OpenGL,
// we use the default FLTK implementation for compatibility in the
@@ -41,7 +56,8 @@
// double Fl_OpenGL_Graphics_Driver::transform_dy(double x, double y)
void Fl_OpenGL_Graphics_Driver::begin_points() {
- Fl_Graphics_Driver::begin_points();
+ n = 0; gap_ = 0;
+ what = POINTS;
glBegin(GL_POINTS);
}
@@ -50,7 +66,8 @@ void Fl_OpenGL_Graphics_Driver::end_points() {
}
void Fl_OpenGL_Graphics_Driver::begin_line() {
- Fl_Graphics_Driver::begin_line();
+ n = 0; gap_ = 0;
+ what = LINE;
glBegin(GL_LINE_STRIP);
}
@@ -59,7 +76,8 @@ void Fl_OpenGL_Graphics_Driver::end_line() {
}
void Fl_OpenGL_Graphics_Driver::begin_loop() {
- Fl_Graphics_Driver::begin_loop();
+ n = 0; gap_ = 0;
+ what = LOOP;
glBegin(GL_LINE_LOOP);
}
@@ -68,7 +86,8 @@ void Fl_OpenGL_Graphics_Driver::end_loop() {
}
void Fl_OpenGL_Graphics_Driver::begin_polygon() {
- Fl_Graphics_Driver::begin_polygon();
+ n = 0; gap_ = 0;
+ what = POLYGON;
glBegin(GL_POLYGON);
}
@@ -77,26 +96,141 @@ void Fl_OpenGL_Graphics_Driver::end_polygon() {
}
void Fl_OpenGL_Graphics_Driver::begin_complex_polygon() {
- Fl_Graphics_Driver::begin_complex_polygon();
+ n = 0;
+ what = COMPLEX_POLYGON;
+#ifndef SLOW_COMPLEX_POLY
glBegin(GL_POLYGON);
+#endif
}
void Fl_OpenGL_Graphics_Driver::gap() {
+#ifdef SLOW_COMPLEX_POLY
+ // drop gaps at the start or gap after gap
+ if (n==0 || n==gap_) // || pnVertex==pVertexGapStart)
+ return;
+ // create a loop
+ XPOINT& p = xpoint[gap_];
+ transformed_vertex(p.x, p.y);
+ transformed_vertex(GAP, 0.0);
+ gap_ = n;
+#else
glEnd();
glBegin(GL_POLYGON);
+#endif
}
+#ifdef SLOW_COMPLEX_POLY
+
+// Draw a complex polygon line by line from the top to the bottom.
+void Fl_OpenGL_Graphics_Driver::end_complex_polygon()
+{
+ int i, y;
+ XPOINT *v0, *v1;
+
+ // don't bother if no polygon is defined
+ if (n < 2) return;
+
+ // make sure that we always have a closed loop by appending the first
+ // coordinate again as the alst coordinate
+ gap();
+
+ // find the bounding box for this polygon
+ v0 = xpoint;
+ float xMin = v0->x, xMax = xMin;
+ int yMin = v0->y, yMax = yMin;
+ for (i = 1; i < n; i++) {
+ v0++;
+ if (v0->x == GAP) continue;
+ if (v0->x <= xMin) xMin = v0->x;
+ if (v0->x >= xMax) xMax = v0->x;
+ if (v0->y <= yMin) yMin = v0->y;
+ if (v0->y >= yMax) yMax = v0->y;
+ }
+
+ int nNodes, j;
+ float nodeX[n-1], pixelX, swap;
+
+ // loop through the rows of the image
+ for (y = yMin; y < yMax; y++) {
+ // Build a list of all crossing points with this y axis
+ XPOINT *v0 = xpoint + 0, *v1 = xpoint + 1;
+ nNodes = 0;
+ for (i = 1; i < n; i++) {
+ j = i-1;
+ if (v1->x==GAP) { // skip the gap
+ i++; v0++; v1++;
+ continue;
+ }
+ if ( (v1->y < y && v0->y >= y)
+ || (v0->y < y && v1->y >= y) )
+ {
+ float dy = v0->y - v1->y;
+ if (fabsf(dy)>.0001f) {
+ nodeX[nNodes++] = v1->x + ((y - v1->y) / dy) * (v0->x - v1->x);
+ } else {
+ nodeX[nNodes++] = v1->x;
+ }
+ }
+ v0++; v1++;
+ }
+
+ // sort the nodes, via a simple Bubble sort
+ i = 0;
+ while (i < nNodes-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
+ glBegin(GL_LINES);
+ for (i = 0; i < nNodes; i += 2) {
+ float x0 = nodeX[i];
+ if (x0 >= xMax)
+ break;
+ float x1 = nodeX[i+1];
+ if (x1 > xMin) {
+ if (x0 < xMin)
+ x0 = xMin;
+ if (x1 > xMax)
+ x1 = xMax;
+ glVertex2f(x0, y);
+ glVertex2f(x1, y);
+ }
+ }
+ glEnd();
+ }
+}
+
+#else
+
// FXIME: non-convex polygons are not supported yet
// use gluTess* functions to do this; search for gluBeginPolygon
void Fl_OpenGL_Graphics_Driver::end_complex_polygon() {
glEnd();
}
+#endif
+
+
// remove equal points from closed path
void Fl_OpenGL_Graphics_Driver::fixloop() { }
void Fl_OpenGL_Graphics_Driver::transformed_vertex(double xf, double yf) {
+#ifdef SLOW_COMPLEX_POLY
+ if (what==COMPLEX_POLYGON) {
+ Fl_Graphics_Driver::transformed_vertex(xf, yf);
+ } else {
+ glVertex2d(xf, yf);
+ }
+#else
glVertex2d(xf, yf);
+#endif
}
void Fl_OpenGL_Graphics_Driver::circle(double cx, double cy, double r) {