Implement fl_complex_polygon() for OpenGL (#570)
This commit is contained in:
parent
a8923a0fd4
commit
9f92972729
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user