diff options
Diffstat (limited to 'src/drivers/OpenGL')
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx | 144 |
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) { |
