diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl_Gl_Window.cxx | 86 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H | 19 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx | 24 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx | 38 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx | 30 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx | 325 | ||||
| -rw-r--r-- | src/fl_color.cxx | 33 | ||||
| -rw-r--r-- | src/fl_gtk.cxx | 10 |
8 files changed, 420 insertions, 145 deletions
diff --git a/src/Fl_Gl_Window.cxx b/src/Fl_Gl_Window.cxx index 06253bfd4..b87872ed2 100644 --- a/src/Fl_Gl_Window.cxx +++ b/src/Fl_Gl_Window.cxx @@ -26,6 +26,7 @@ extern int fl_gl_load_plugin; #include <FL/Fl_Graphics_Driver.H> #include <FL/fl_utf8.h> #include "drivers/OpenGL/Fl_OpenGL_Display_Device.H" +#include "drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H" #include <stdlib.h> # if (HAVE_DLSYM && HAVE_DLFCN_H) @@ -337,6 +338,53 @@ void Fl_Gl_Window::init() { void Fl_Gl_Window::draw_overlay() {} +void Fl_Gl_Window::draw_begin() { + Fl_Surface_Device::push_current( Fl_OpenGL_Display_Device::display_device() ); + Fl_OpenGL_Graphics_Driver *drv = (Fl_OpenGL_Graphics_Driver*)fl_graphics_driver; + drv->pixels_per_unit_ = pixels_per_unit(); + + if (!valid()) { + glViewport(0, 0, pixel_w(), pixel_h()); + valid(1); + } + + glPushAttrib(GL_ENABLE_BIT); + glPushAttrib(GL_TRANSFORM_BIT); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); +// glOrtho(-0.5, w()-0.5, h()-0.5, -0.5, -1, 1); + glOrtho(0.0, w(), h(), 0.0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_POINT_SMOOTH); + + glLineWidth((GLfloat)(drv->pixels_per_unit_*drv->line_width_)); + glPointSize((GLfloat)(drv->pixels_per_unit_)); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + // TODO: all of the settings should be saved on the GL stack +} + +void Fl_Gl_Window::draw_end() { + glMatrixMode(GL_MODELVIEW_MATRIX); + glPopMatrix(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glPopAttrib(); // GL_TRANSFORM_BIT + glPopAttrib(); // GL_ENABLE_BIT + + Fl_Surface_Device::pop_current(); +} + /** Draws the Fl_Gl_Window. You \e \b must subclass Fl_Gl_Window and provide an implementation for draw(). You may also provide an implementation of draw_overlay() @@ -389,32 +437,28 @@ void Fl_Gl_Window::draw_overlay() {} } \endcode -*/ -void Fl_Gl_Window::draw() { - Fl_Surface_Device::push_current( Fl_OpenGL_Display_Device::display_device() ); - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_DEPTH_TEST); - glPushMatrix(); - glLoadIdentity(); - GLint viewport[4]; - glGetIntegerv (GL_VIEWPORT, viewport); - if (viewport[2] != pixel_w() || viewport[3] != pixel_h()) { - glViewport(0, 0, pixel_w(), pixel_h()); + Regular FLTK widgets can be added as children to the Fl_Gl_Window. To + correctly overlay the widgets, Fl_Gl_Window::draw() must be called after + rendering the main scene. + \code + void mywindow::draw() { + // draw 3d graphics scene + Fl_Gl_Window::draw(); + // -- or -- + draw_begin(); + Fl_Window::draw(); + // other 2d drawing calls, overlays, etc. + draw_end(); } - glOrtho(-0.5, w()-0.5, h()-0.5, -0.5, -1, 1); -// glOrtho(0, w(), h(), 0, -1, 1); - glLineWidth((GLfloat)pixels_per_unit()); // should be 1 or 2 (2 if highres OpenGL) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // FIXME: push on state stack - glEnable(GL_BLEND); // FIXME: push on state stack + \endcode +*/ +void Fl_Gl_Window::draw() { + draw_begin(); Fl_Window::draw(); - - glPopMatrix(); - glPopAttrib(); - Fl_Surface_Device::pop_current(); + draw_end(); } - /** Handle some FLTK events as needed. */ 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); } diff --git a/src/fl_color.cxx b/src/fl_color.cxx index 861f8d77f..8d3d04561 100644 --- a/src/fl_color.cxx +++ b/src/fl_color.cxx @@ -64,6 +64,19 @@ void Fl::set_color(Fl_Color i, uchar red, uchar green, uchar blue) { ((unsigned)red<<24)+((unsigned)green<<16)+((unsigned)blue<<8)); } +/** + Sets an entry in the fl_color index table. + + You can set it to any 8-bit RGBA color. + */ +void Fl::set_color(Fl_Color i, uchar red, uchar green, uchar blue, uchar alpha) { + Fl::set_color((Fl_Color)(i & 255), + ((unsigned)red<<24) + |((unsigned)green<<16) + |((unsigned)blue<<8) + |(alpha^0xff)); +} + void Fl::set_color(Fl_Color i, unsigned c) { @@ -97,6 +110,26 @@ void Fl::get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue) { } /** + Returns the RGBA value(s) for the given FLTK color index. + + This form returns the red, green, blue, and alpha values + separately in referenced variables. + + \see unsigned get_color(Fl_Color c) + */ +void Fl::get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue, uchar &alpha) { + unsigned c; + + if (i & 0xffffff00) c = (unsigned)i; + else c = fl_cmap[i]; + + red = uchar(c>>24); + green = uchar(c>>16); + blue = uchar(c>>8); + alpha = uchar(c^0x000000ff); +} + +/** Returns the weighted average color between the two given colors. The red, green and blue values are averages using the following formula: diff --git a/src/fl_gtk.cxx b/src/fl_gtk.cxx index bceae8ebb..eb47c6c2a 100644 --- a/src/fl_gtk.cxx +++ b/src/fl_gtk.cxx @@ -234,6 +234,16 @@ static void gtk_round_down_box(int x, int y, int w, int h, Fl_Color c) { gtk_color(c); draw(FILL, x, y, w, h, 2); + gtk_color(fl_color_average(FL_WHITE, c, 0.1f)); + draw(LOWER_RIGHT, x+1, y, w-2, h, 2); + draw(LOWER_RIGHT, x, y, w, h, 3); + gtk_color(fl_color_average(FL_WHITE, c, 0.2f)); + draw(LOWER_RIGHT, x+1, y, w-2, h, 1); + draw(LOWER_RIGHT, x, y, w, h, 2); + gtk_color(fl_color_average(FL_WHITE, c, 0.5f)); + draw(LOWER_RIGHT, x+1, y, w-2, h, 0); + draw(LOWER_RIGHT, x, y, w, h, 1); + gtk_color(fl_color_average(FL_BLACK, c, 0.05f)); draw(UPPER_LEFT, x, y, w, h, 2); draw(UPPER_LEFT, x+1, y, w-2, h, 1); |
