FLTK logo

[master] 9f92972 - Implement fl_complex_polygon() for OpenGL (#570)

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 9f92972 - Implement fl_complex_polygon() for OpenGL (#570) "Matthias Melcher" Dec 05, 2022  
 
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 ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.