summaryrefslogtreecommitdiff
path: root/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx')
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx325
1 files changed, 251 insertions, 74 deletions
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);
}