summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2022-02-06 15:22:24 +0100
committerGitHub <noreply@github.com>2022-02-06 15:22:24 +0100
commitdb0a1f4baeb928b54d328d5dfbd0ec37b0b58bd3 (patch)
treeed53495f5dd435d7c23cd4267fb785e5ebca679c /src/drivers
parentaf4954aee3483f03ff69e990e80f4e4a18e8b7f6 (diff)
OpenGL implementation of all `fl_` "Drawing Fast Shapes" graphics calls (#385)
* Fix build system for unites, * Updated unittest to check OpenGL drawing. Making sure that OpenGL drawing is exactly the same as native drawing to make FLTK widget rendering look the same in GL windows. * Make OpenGL optional. * Implemented clipping in OpenGL * unites drawing fast shapes * Fixed CMake * Updating unittest. Added tests for fl_pi and fl_arc (int) Renamed tab to render complex shapes. * Improved OpenGL FLTK drawing emulation. * Fixed GTK ROUND DOWN BOX * Fixing Makefile for unittest * Correctly aligning OpenGL text. * Fixed text alignment in GL windows. Explained the "FLTK over GL " example in Cube. * Overlapping test. * Better GL graphics alignment. * Drawing the focus rect. * Adding Alpha Channel support for GL. * Added FLTK-on-GL documentation.
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H19
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx24
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx38
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx30
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx325
5 files changed, 312 insertions, 124 deletions
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H
index b3c7e9de7..274d911dc 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H
@@ -24,12 +24,20 @@
#define FL_OPENGL_GRAPHICS_DRIVER_H
#include <FL/Fl_Graphics_Driver.H>
+#include <FL/fl_draw.H>
/**
\brief OpenGL specific graphics class.
*/
class FL_EXPORT Fl_OpenGL_Graphics_Driver : public Fl_Graphics_Driver {
public:
+ float pixels_per_unit_;
+ float line_width_;
+ int line_stipple_;
+ Fl_OpenGL_Graphics_Driver() :
+ pixels_per_unit_(1.0f),
+ line_width_(1.0f),
+ line_stipple_(FL_SOLID) { }
// --- line and polygon drawing with integer coordinates
void point(int x, int y);
void rect(int x, int y, int w, int h);
@@ -46,10 +54,17 @@ public:
void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
void polygon(int x0, int y0, int x1, int y1, int x2, int y2);
void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
+ void focus_rect(int x, int y, int w, int h);
+ // ---- clipping
void push_clip(int x, int y, int w, int h);
- int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H);
- int not_clipped(int x, int y, int w, int h);
+ void pop_clip();
+ void push_no_clip();
+ Fl_Region clip_region();
+ void clip_region(Fl_Region r);
void restore_clip();
+ int not_clipped(int x, int y, int w, int h);
+ int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H);
+ // ---- matrix transformed drawing
void transformed_vertex(double xf, double yf);
void begin_points();
void end_points();
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx
index f933d10e2..73b216f01 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx
@@ -27,20 +27,21 @@
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#define _USE_MATH_DEFINES
-#include <math.h>
+#include <FL/math.h>
void Fl_OpenGL_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) {
if (w <= 0 || h <= 0) return;
while (a2<a1) a2 += 360.0; // TODO: write a sensible fmod angle alignment here
- a1 = a1/180.0f*M_PI; a2 = a2/180.0f*M_PI;
- double cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f;
- double rMax; if (w<h) rMax = h/2; else rMax = w/2;
+ a1 = a1/180.0*M_PI; a2 = a2/180.0*M_PI;
+ double cx = x + 0.5*w, cy = y + 0.5*h;
+ double rx = 0.5*w-0.3, ry = 0.5*h-0.3;
+ double rMax; if (w>h) rMax = rx; else rMax = ry;
int nSeg = (int)(10 * sqrt(rMax))+1;
double incr = (a2-a1)/(double)nSeg;
glBegin(GL_LINE_STRIP);
- for (int i=0; i<nSeg; i++) {
- glVertex2d(cx+cos(a1)*rMax, cy-sin(a1)*rMax);
+ for (int i=0; i<=nSeg; i++) {
+ glVertex2d(cx+cos(a1)*rx, cy-sin(a1)*ry);
a1 += incr;
}
glEnd();
@@ -53,16 +54,17 @@ void Fl_OpenGL_Graphics_Driver::arc(double x, double y, double r, double start,
void Fl_OpenGL_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) {
if (w <= 0 || h <= 0) return;
while (a2<a1) a2 += 360.0; // TODO: write a sensible fmod angle alignment here
- a1 = a1/180.0f*M_PI; a2 = a2/180.0f*M_PI;
- double cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f;
- double rMax; if (w<h) rMax = h/2; else rMax = w/2;
+ a1 = a1/180.0*M_PI; a2 = a2/180.0*M_PI;
+ double cx = x + 0.5*w, cy = y + 0.5*h;
+ double rx = 0.5*w, ry = 0.5*h;
+ double rMax; if (w>h) rMax = rx; else rMax = ry;
int nSeg = (int)(10 * sqrt(rMax))+1;
double incr = (a2-a1)/(double)nSeg;
glBegin(GL_TRIANGLE_FAN);
glVertex2d(cx, cy);
- for (int i=0; i<nSeg+1; i++) {
- glVertex2d(cx+cos(a1)*rMax, cy-sin(a1)*rMax);
+ for (int i=0; i<=nSeg; i++) {
+ glVertex2d(cx+cos(a1)*rx, cy-sin(a1)*ry);
a1 += incr;
}
glEnd();
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx
index 54810cabf..30bd40a3e 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx
@@ -30,41 +30,21 @@
// Implementation of fl_color(i), fl_color(r,g,b).
+extern unsigned fl_cmap[256]; // defined in fl_color.cxx
+
void Fl_OpenGL_Graphics_Driver::color(Fl_Color i) {
- // FIXME: do we need the code below?
- /*
-#if HAVE_GL_OVERLAY
-#if defined(_WIN32)
- if (fl_overlay && fl_overlay_depth) {
- if (fl_overlay_depth < 8) {
- // only black & white produce the expected colors. This could
- // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx
- int size = 1<<fl_overlay_depth;
- if (!i) glIndexi(size-2);
- else if (i >= size-2) glIndexi(size-1);
- else glIndexi(i);
- } else {
- glIndexi(i ? i : FL_GRAY_RAMP);
- }
- return;
- }
-#else
- if (fl_overlay) {glIndexi(int(fl_xpixel(i))); return;}
-#endif
-#endif
-*/
if (i & 0xffffff00) {
- unsigned rgb = (unsigned)i;
- color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8));
- } else {
+ unsigned rgba = ((unsigned)i)^0x000000ff;
Fl_Graphics_Driver::color(i);
- uchar red, green, blue;
- Fl::get_color(i, red, green, blue);
- glColor3ub(red, green, blue);
+ glColor4ub(rgba>>24, rgba>>16, rgba>>8, rgba);
+ } else {
+ unsigned rgba = ((unsigned)fl_cmap[i])^0x000000ff;
+ Fl_Graphics_Driver::color(fl_cmap[i]);
+ glColor4ub(rgba>>24, rgba>>16, rgba>>8, rgba);
}
}
-void Fl_OpenGL_Graphics_Driver::color(uchar r,uchar g,uchar b) {
+void Fl_OpenGL_Graphics_Driver::color(uchar r, uchar g, uchar b) {
Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) );
glColor3ub(r,g,b);
}
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx
index 89dea699d..c1963352b 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx
@@ -31,27 +31,41 @@
// OpenGL implementation does not support cap and join types
void Fl_OpenGL_Graphics_Driver::line_style(int style, int width, char* dashes) {
-
if (width<1) width = 1;
+ line_width_ = width;
+
+ int stipple = style & 0x00ff;
+ line_stipple_ = stipple;
+// int cap = style & 0x0f00;
+// int join = style & 0xf000;
- if (style==FL_SOLID) {
+ if (stipple==FL_SOLID) {
glLineStipple(1, 0xFFFF);
glDisable(GL_LINE_STIPPLE);
} else {
- switch (style) {
+ char enable = 1;
+ switch (stipple & 0x00ff) {
case FL_DASH:
- glLineStipple(width, 0x0F0F); // ....****....****
+ glLineStipple(pixels_per_unit_*line_width_, 0x0F0F); // ....****....****
break;
case FL_DOT:
- glLineStipple(width, 0x5555); // .*.*.*.*.*.*.*.*
+ glLineStipple(pixels_per_unit_*line_width_, 0x5555); // .*.*.*.*.*.*.*.*
break;
case FL_DASHDOT:
- glLineStipple(width, 0x2727); // ..*..***..*..***
+ glLineStipple(pixels_per_unit_*line_width_, 0x2727); // ..*..***..*..***
break;
case FL_DASHDOTDOT:
- glLineStipple(width, 0x5757); // .*.*.***.*.*.***
+ glLineStipple(pixels_per_unit_*line_width_, 0x5757); // .*.*.***.*.*.***
break;
+ default:
+ glLineStipple(1, 0xFFFF);
+ enable = 0;
}
- glEnable(GL_LINE_STIPPLE);
+ if (enable)
+ glEnable(GL_LINE_STIPPLE);
+ else
+ glDisable(GL_LINE_STIPPLE);
}
+ glLineWidth( (GLfloat)(pixels_per_unit_ * line_width_) );
+ glPointSize( (GLfloat)(pixels_per_unit_) );
}
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx
index f47aaab27..5b61b3a11 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx
@@ -26,105 +26,109 @@
#include <FL/Fl_Gl_Window.H>
#include <FL/Fl_RGB_Image.H>
#include <FL/Fl.H>
+#include <FL/math.h>
// --- line and polygon drawing with integer coordinates
void Fl_OpenGL_Graphics_Driver::point(int x, int y) {
glBegin(GL_POINTS);
- glVertex2i(x, y);
+ glVertex2f(x+0.5f, y+0.5f);
glEnd();
}
void Fl_OpenGL_Graphics_Driver::rect(int x, int y, int w, int h) {
- glBegin(GL_LINE_LOOP);
- glVertex2i(x, y);
- glVertex2i(x+w, y);
- glVertex2i(x+w, y+h);
- glVertex2i(x, y+h);
- glEnd();
+ float offset = line_width_ / 2.0f;
+ float xx = x+0.5f, yy = y+0.5f;
+ float rr = x+w-0.5f, bb = y+h-0.5f;
+ glRectf(xx-offset, yy-offset, rr+offset, yy+offset);
+ glRectf(xx-offset, bb-offset, rr+offset, bb+offset);
+ glRectf(xx-offset, yy-offset, xx+offset, bb+offset);
+ glRectf(rr-offset, yy-offset, rr+offset, bb+offset);
}
void Fl_OpenGL_Graphics_Driver::rectf(int x, int y, int w, int h) {
if (w<=0 || h<=0) return;
- // OpenGL has the natural origin at the bottom left. Drawing in FLTK
- // coordinates requires that we shift the rectangle one pixel up.
- glBegin(GL_POLYGON);
- glVertex2i(x, y-1);
- glVertex2i(x+w, y-1);
- glVertex2i(x+w, y+h-1);
- glVertex2i(x, y+h-1);
- glEnd();
+ glRectf(x, y, x+w, y+h);
}
void Fl_OpenGL_Graphics_Driver::line(int x, int y, int x1, int y1) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x1, y1);
- glEnd();
- point(x1, y1);
+ if (x==x1 && y==y1) return;
+ if (x==x1) {
+ yxline(x, y, y1);
+ return;
+ }
+ if (y==y1) {
+ xyline(x, y, x1);
+ return;
+ }
+ float xx = x+0.5f, xx1 = x1+0.5f;
+ float yy = y+0.5f, yy1 = y1+0.5f;
+ if (line_width_==1.0f) {
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(xx, yy);
+ glVertex2f(xx1, yy1);
+ glEnd();
+ } else {
+ float dx = xx1-xx, dy = yy1-yy;
+ float len = sqrtf(dx*dx+dy*dy);
+ dx = dx/len*line_width_*0.5f;
+ dy = dy/len*line_width_*0.5f;
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glVertex2f(xx-dy, yy+dx);
+ glVertex2f(xx+dy, yy-dx);
+ glVertex2f(xx1-dy, yy1+dx);
+ glVertex2f(xx1+dy, yy1-dx);
+ glEnd();
+ }
}
void Fl_OpenGL_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x1, y1);
- glVertex2i(x2, y2);
- glEnd();
- point(x2, y2);
+ // TODO: no corner types (miter) yet
+ line(x, y, x1, y1);
+ line(x1, y1, x2, y2);
}
void Fl_OpenGL_Graphics_Driver::xyline(int x, int y, int x1) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x1, y);
- glEnd();
- point(x1, y);
+ float offset = line_width_ / 2.0f;
+ float xx = x, yy = y+0.5f, rr = x1+1.0f;
+ glRectf(xx, yy-offset, rr, yy+offset);
}
void Fl_OpenGL_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x1, y);
- glVertex2i(x1, y2);
- glEnd();
- point(x1, y2);
+ float offset = line_width_ / 2.0f;
+ float xx = x, yy = y+0.5f, rr = x1+0.5f, bb = y2+1.0f;
+ glRectf(xx, yy-offset, rr+offset, yy+offset);
+ glRectf(rr-offset, yy+offset, rr+offset, bb);
}
void Fl_OpenGL_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x1, y);
- glVertex2i(x1, y2);
- glVertex2i(x3, y2);
- glEnd();
- point(x3, y2);
+ float offset = line_width_ / 2.0f;
+ float xx = x, yy = y+0.5f, xx1 = x1+0.5f, rr = x3+1.0f, bb = y2+0.5;
+ glRectf(xx, yy-offset, xx1+offset, yy+offset);
+ glRectf(xx1-offset, yy+offset, xx1+offset, bb+offset);
+ glRectf(xx1+offset, bb-offset, rr, bb+offset);
}
void Fl_OpenGL_Graphics_Driver::yxline(int x, int y, int y1) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x, y1);
- glEnd();
- point(x, y1);
+ float offset = line_width_ / 2.0f;
+ float xx = x+0.5f, yy = y, bb = y1+1.0f;
+ glRectf(xx-offset, yy, xx+offset, bb);
}
void Fl_OpenGL_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x, y1);
- glVertex2i(x2, y1);
- glEnd();
- point(x2, y1);
+ float offset = line_width_ / 2.0f;
+ float xx = x+0.5f, yy = y, rr = x2+1.0f, bb = y1+0.5f;
+ glRectf(xx-offset, yy, xx+offset, bb+offset);
+ glRectf(xx+offset, bb-offset, rr, bb+offset);
}
void Fl_OpenGL_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
- glBegin(GL_LINE_STRIP);
- glVertex2i(x, y);
- glVertex2i(x, y1);
- glVertex2i(x2, y1);
- glVertex2i(x2, y3);
- glEnd();
- point(x2, y3);
+ float offset = line_width_ / 2.0f;
+ float xx = x+0.5f, yy = y, yy1 = y1+0.5f, rr = x2+0.5f, bb = y3+1.0f;
+ glRectf(xx-offset, yy, xx+offset, yy1+offset);
+ glRectf(xx+offset, yy1-offset, rr+offset, yy1+offset);
+ glRectf(rr-offset, yy1+offset, rr+offset, bb);
}
void Fl_OpenGL_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) {
@@ -161,24 +165,197 @@ void Fl_OpenGL_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2,
glEnd();
}
+void Fl_OpenGL_Graphics_Driver::focus_rect(int x, int y, int w, int h) {
+ float width = line_width_;
+ int stipple = line_stipple_;
+ line_style(FL_DOT, 1);
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x+0.5f, y+0.5f);
+ glVertex2f(x+w+0.5f, y+0.5f);
+ glVertex2f(x+w+0.5f, y+h+0.5f);
+ glVertex2f(x+0.5f, y+h+0.5f);
+ glEnd();
+ line_style(stipple, width);
+}
+
+
+// -----------------------------------------------------------------------------
+
+static int gl_min(int a, int b) { return (a<b) ? a : b; }
+static int gl_max(int a, int b) { return (a>b) ? a : b; }
+
+enum {
+ kStateFull, // Region is the full window
+ kStateRect, // Region is a rectangle
+ kStateEmpty // Region is an empty space
+};
+
+typedef struct Fl_Gl_Region {
+ int x, y, w, h;
+ int gl_x, gl_y, gl_w, gl_h;
+ char state;
+ void set(int inX, int inY, int inW, int inH) {
+ if (inW<=0 || inH<=0) {
+ state = kStateEmpty;
+ x = inX; y = inY; w = 1; h = 1; // or 0?
+ } else {
+ x = inX; y = inY; w = inW; h = inH;
+ state = kStateRect;
+ }
+ Fl_Gl_Window *win = Fl_Gl_Window::current()->as_gl_window();
+ if (win) {
+ float scale = win->pixels_per_unit();
+ gl_x = x*scale;
+ gl_y = (win->h()-h-y+1)*scale;
+ gl_w = (w-1)*scale;
+ gl_h = (h-1)*scale;
+ if (inX<=0 && inY<=0 && inX+inW>win->w() && inY+inH>=win->h()) {
+ state = kStateFull;
+ }
+ } else {
+ state = kStateFull;
+ }
+ }
+ void set_full() { state = kStateFull; }
+ void set_empty() { state = kStateEmpty; }
+ void set_intersect(int inX, int inY, int inW, int inH, Fl_Gl_Region &g) {
+ if (g.state==kStateFull) {
+ set(inX, inY, inW, inH);
+ } else if (g.state==kStateEmpty) {
+ set_empty();
+ } else {
+ int rx = gl_max(inX, g.x);
+ int ry = gl_max(inY, g.y);
+ int rr = gl_min(inX+inW, g.x+g.w);
+ int rb = gl_max(inY+inH, g.y+g.h);
+ set(rx, ry, rr-rx, rb-ry);
+ }
+ }
+ void apply() {
+ if (state==kStateFull) {
+ glDisable(GL_SCISSOR_TEST);
+ } else {
+ glScissor(gl_x, gl_y, gl_w, gl_h);
+ glEnable(GL_SCISSOR_TEST);
+ }
+ }
+} Fl_Gl_Region;
+
+static int gl_rstackptr = 0;
+static const int gl_region_stack_max = FL_REGION_STACK_SIZE - 1;
+static Fl_Gl_Region gl_rstack[FL_REGION_STACK_SIZE];
+
+/*
+ Intersect the given rect with the current rect, push the result on the stack,
+ and apply the new clipping area.
+ */
void Fl_OpenGL_Graphics_Driver::push_clip(int x, int y, int w, int h) {
- // TODO: implement OpenGL clipping
- if (rstackptr < region_stack_max) rstack[++rstackptr] = 0L;
- else Fl::warning("Fl_OpenGL_Graphics_Driver::push_clip: clip stack overflow!\n");
+ if (gl_rstackptr==gl_region_stack_max) {
+ Fl::warning("Fl_OpenGL_Graphics_Driver::push_clip: clip stack overflow!\n");
+ return;
+ }
+ if (gl_rstackptr==0) {
+ gl_rstack[gl_rstackptr].set(x, y, w, h);
+ } else {
+ gl_rstack[gl_rstackptr].set_intersect(x, y, w, h, gl_rstack[gl_rstackptr-1]);
+ }
+ gl_rstack[gl_rstackptr].apply();
+ gl_rstackptr++;
}
-int Fl_OpenGL_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) {
- // TODO: implement OpenGL clipping
- X = x; Y = y; W = w; H = h;
- return 0;
+/*
+ Remove the current clipping area and apply the previous one on the stack.
+ */
+void Fl_OpenGL_Graphics_Driver::pop_clip() {
+ if (gl_rstackptr==0) {
+ glDisable(GL_SCISSOR_TEST);
+ Fl::warning("Fl_OpenGL_Graphics_Driver::pop_clip: clip stack underflow!\n");
+ return;
+ }
+ gl_rstackptr--;
+ restore_clip();
}
-int Fl_OpenGL_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
- // TODO: implement OpenGL clipping
- return 1;
+/*
+ Push a full area onton the stack, so no clipping will take place.
+ */
+void Fl_OpenGL_Graphics_Driver::push_no_clip() {
+ if (gl_rstackptr==gl_region_stack_max) {
+ Fl::warning("Fl_OpenGL_Graphics_Driver::push_no_clip: clip stack overflow!\n");
+ return;
+ }
+ gl_rstack[gl_rstackptr].set_full();
+ gl_rstack[gl_rstackptr].apply();
+ gl_rstackptr++;
+}
+
+/*
+ We don't know the format of clip regions of the default driver, so return NULL.
+ */
+Fl_Region Fl_OpenGL_Graphics_Driver::clip_region() {
+ return NULL;
+}
+
+/*
+ We don't know the format of clip regions of the default driver, so do the best
+ we can.
+ */
+void Fl_OpenGL_Graphics_Driver::clip_region(Fl_Region r) {
+ if (r==NULL) {
+ glDisable(GL_SCISSOR_TEST);
+ } else {
+ restore_clip();
+ }
}
+/*
+ Apply the current clipping rect.
+ */
void Fl_OpenGL_Graphics_Driver::restore_clip() {
- // TODO: implement OpenGL clipping
- fl_clip_state_number++;
+ if (gl_rstackptr==0) {
+ glDisable(GL_SCISSOR_TEST);
+ } else {
+ gl_rstack[gl_rstackptr-1].apply();
+ }
+}
+
+/*
+ Does the rectangle intersect the current clip region?
+ 0 = regions don't intersect, nothing to draw
+ 1 = region is fully inside current clipping region
+ 2 = region is partially inside current clipping region
+ */
+int Fl_OpenGL_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
+ if (gl_rstackptr==0)
+ return 1;
+ Fl_Gl_Region &g = gl_rstack[gl_rstackptr-1];
+ if (g.state==kStateFull)
+ return 1;
+ if (g.state==kStateEmpty)
+ return 0;
+ int r = x+w, b = y + h;
+ int gr = g.x+g.w, gb = g.y+g.h;
+ if (r<=g.x || x>=gr || b<=g.y || y>=gb) return 0;
+ if (x>=g.x && y>=g.y && r<=gr && b<=gb) return 1;
+ return 2;
+}
+
+/*
+ Calculate the intersection of the given rect and the clipping area.
+ Return 0 if the result did not change.
+ */
+int Fl_OpenGL_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) {
+ X = x; Y = y; W = w; H = h;
+ if (gl_rstackptr==0)
+ return 0;
+ Fl_Gl_Region &g = gl_rstack[gl_rstackptr-1];
+ if (g.state==kStateFull)
+ return 0;
+ int r = x+w, b = y + h;
+ int gr = g.x+g.w, gb = g.y+g.h;
+ X = gl_max(x, g.x);
+ Y = gl_max(y, g.y);
+ W = gl_min(r, gr) - X;
+ H = gl_min(b, gb) - Y;
+ return (x!=X || y!=Y || w!=W || h!=H);
}