|
commit 9f92972729008a87887e1b1e2d35438102e91a9e
Author: Matthias Melcher <github@matthiasm.com>
AuthorDate: Mon Dec 5 19:27:12 2022 +0100
Commit: GitHub <noreply@github.com>
CommitDate: Mon Dec 5 19:27:12 2022 +0100
Implement fl_complex_polygon() for OpenGL (#570)
FL/Fl_Graphics_Driver.H | 2 +-
.../OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx | 144 ++++++++++++++++++++-
test/unittest_complex_shapes.cxx | 2 +-
3 files changed, 141 insertions(+), 7 deletions(-)
diff --git FL/Fl_Graphics_Driver.H FL/Fl_Graphics_Driver.H
index 006721f..2666241 100644
--- FL/Fl_Graphics_Driver.H
+++ FL/Fl_Graphics_Driver.H
@@ -162,7 +162,7 @@ protected:
matrix m; ///< current transformation matrix
int n; ///< For internal use by FLTK
int gap_; ///< For internal use by FLTK
- enum SHAPE {NONE=0, LINE, LOOP, POLYGON, POINTS} what;
+ enum SHAPE {NONE=0, LINE, LOOP, POLYGON, POINTS, COMPLEX_POLYGON} what;
int rstackptr; ///< For internal use by FLTK
static const int region_stack_max = FL_REGION_STACK_SIZE - 1; ///< For internal use by FLTK
Fl_Region rstack[FL_REGION_STACK_SIZE]; ///< For internal use by FLTK
diff --git src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx
index b5ec90b..fd4326e 100644
--- src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx
+++ 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) {
diff --git test/unittest_complex_shapes.cxx test/unittest_complex_shapes.cxx
index c2fdfeb..4362086 100644
--- test/unittest_complex_shapes.cxx
+++ test/unittest_complex_shapes.cxx
@@ -418,7 +418,7 @@ void draw_complex(ComplexShapesTest *p) {
fl_color(FL_DARK2);
fl_begin_complex_polygon();
fl_vertex(-w, 0);
- fl_curve(-w+3, 0, -w+3, -h, w-3, h, w-3, 0);
+ fl_curve(-w+3, 0, 0, -h, 0, h, w-3, 0);
fl_vertex(w, 0);
fl_vertex(w, h); fl_vertex(-w, h);
fl_end_complex_polygon();
[ Direct Link to Message ] | |