FLTK logo

[master] db0a1f4 - OpenGL implementation of all `fl_` "Drawing Fast Shapes" graphics calls (#385)

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] db0a1f4 - OpenGL implementation of all `fl_` "Drawing Fast Shapes" graphics calls (#385) "Matthias Melcher" Feb 06, 2022  
 
commit db0a1f4baeb928b54d328d5dfbd0ec37b0b58bd3
Author:     Matthias Melcher <github@matthiasm.com>
AuthorDate: Sun Feb 6 15:22:24 2022 +0100
Commit:     GitHub <noreply@github.com>
CommitDate: Sun Feb 6 15:22:24 2022 +0100

    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.

 FL/Fl.H                                            |   2 +
 FL/Fl_Gl_Window.H                                  |   2 +
 documentation/src/opengl.dox                       |  69 ++++
 src/Fl_Gl_Window.cxx                               |  86 +++--
 src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H     |  19 +-
 .../OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx      |  24 +-
 .../OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx     |  38 +-
 .../Fl_OpenGL_Graphics_Driver_line_style.cxx       |  30 +-
 .../OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx      | 325 +++++++++++++----
 src/fl_color.cxx                                   |  33 ++
 src/fl_gtk.cxx                                     |  10 +
 test/CMakeLists.txt                                |  21 +-
 test/Makefile                                      |  49 ++-
 test/cube.cxx                                      |  18 +-
 test/makedepend                                    |   4 +-
 test/unittest_about.cxx                            |   4 +-
 test/unittest_circles.cxx                          | 236 ++++++++++---
 test/unittest_complex_shapes.cxx                   | 121 +++++++
 test/unittest_fast_shapes.cxx                      | 383 +++++++++++++++++++++
 test/unittest_images.cxx                           |   6 +-
 test/unittest_lines.cxx                            |  77 -----
 test/unittest_points.cxx                           | 294 ++++++++++++++--
 test/unittest_rects.cxx                            |  51 ---
 test/unittest_schemes.cxx                          |   4 +-
 test/unittest_scrollbarsize.cxx                    |   5 +-
 test/unittest_simple_terminal.cxx                  |   4 +-
 test/unittest_symbol.cxx                           |   4 +-
 test/unittest_text.cxx                             |   4 +-
 test/unittest_viewport.cxx                         |   4 +-
 test/unittests.cxx                                 | 208 +++++------
 test/unittests.h                                   |  87 +++++
 31 files changed, 1734 insertions(+), 488 deletions(-)

diff --git FL/Fl.H FL/Fl.H
index a197885..5c84a8d 100644
--- FL/Fl.H
+++ FL/Fl.H
@@ -1063,6 +1063,7 @@ int main() {
 
   // color map:
   static void   set_color(Fl_Color, uchar, uchar, uchar);
+  static void   set_color(Fl_Color, uchar, uchar, uchar, uchar);
   /**
     Sets an entry in the fl_color index table. You can set it to any
     8-bit RGB color. The color is not allocated until fl_color(i) is used.
@@ -1070,6 +1071,7 @@ int main() {
   static void   set_color(Fl_Color i, unsigned c); // platform dependent
   static unsigned get_color(Fl_Color i);
   static void   get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue);
+  static void   get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue, uchar &alpha);
   /**
     Frees the specified color from the colormap, if applicable.
     If overlay is non-zero then the color is freed from the
diff --git FL/Fl_Gl_Window.H FL/Fl_Gl_Window.H
index e3279f9..7d99f1a 100644
--- FL/Fl_Gl_Window.H
+++ FL/Fl_Gl_Window.H
@@ -67,7 +67,9 @@ class FL_EXPORT Fl_Gl_Window : public Fl_Window {
   int mode(int, const int *);
   static int gl_plugin_linkage();
 protected:
+  void draw_begin();
   virtual void draw();
+  void draw_end();
 
 public:
   void show();
diff --git documentation/src/opengl.dox documentation/src/opengl.dox
index 793b983..668e26e 100644
--- documentation/src/opengl.dox
+++ documentation/src/opengl.dox
@@ -257,6 +257,75 @@ adhere to for maximum portability:
 Do \e not call \p gl_start() or
 \p gl_finish() when drawing into an Fl_Gl_Window !
 
+
+\section opengl_with_fltk_widgets Using FLTK widgets in OpenGL Windows
+
+FLTK widgets can be added to `Fl_Gl_Window`s just as they would be added to
+`Fl_Window`s. They are rendered as an overlay over the user defined
+OpenGL graphics using 'fl_..' graphics calls that are implemented in GL.
+
+`Fl_Gl_Window` does not add subsequent widgets as children by default as
+`Fl_Window` does. Call `myGlWindow->begin()` after creating the GL window to
+automatically add following widgets. Remember to call `myGlWindow->end()`.
+
+\code
+class My_Gl_Window : public Fl_Gl_Window {
+...
+  void draw();
+...
+};
+
+...
+myGlWindow = new My_Gl_Window(0, 0, 500, 500);
+myGlWindow->begin();
+myButton = new Fl_Button(10, 10, 120, 24, "Hello!");
+myGlWindow->end();
+...
+
+void My_Gl_Window::draw() {
+  // ... user GL drawing code
+  Fl_Gl_Window::draw(); // Draw FLTK child widgets.
+}
+\endcode
+
+Users can draw into the overlay by using GL graphics calls as well as all
+`fl_...` graphics calls from the "Drawing Fast Shapes" section.
+
+\code
+void My_Gl_Window::draw() {
+  // ... user GL drawing code
+  Fl_Gl_Window::draw_begin(); // Set up 1:1 projection
+  Fl_Window::draw();          // Draw FLTK children
+  fl_color(FL_RED);
+  fl_rect(10, 10, 100, 100);
+  Fl_Gl_Window::draw_end();   // Restore GL state
+}
+\endcode
+
+Widgets can be drawn with transparencies by assigning an alpha value to a
+colormap entry and using that color in the widget.
+
+\code
+Fl::set_color(FL_FREE_COLOR, 255, 255, 0, 127); // 50% transparent yellow
+myGlWindow = new My_Gl_Window(0, 0, 500, 500);
+myGlWindow->begin();
+myButton = new Fl_Button(10, 10, 120, 24, "Hello!");
+myButton->box(FL_BORDER_BOX);
+myButton->color(FL_FREE_COLOR);
+myGlWindow->end();
+\endcode
+
+Transparencies can also be set directly when drawing. This can be used to
+create custom box types and RGB overlay drawings with an alpha channel.
+
+\code
+fl_color(0, 255, 0, 127); // 50% transparent green
+fl_rectf(10, 10, 100, 100);
+fl_color(FL_RED); // back to opaque red
+fl_rect(20, 20, 80, 80);
+\endcode
+
+
 \section opengl_drawing OpenGL Drawing Functions
 
 FLTK provides some useful OpenGL drawing functions. They can
diff --git src/Fl_Gl_Window.cxx src/Fl_Gl_Window.cxx
index 06253bf..b87872e 100644
--- src/Fl_Gl_Window.cxx
+++ 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 src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H
index b3c7e9d..274d911 100644
--- src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H
+++ 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 src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx
index f933d10..73b216f 100644
--- src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx
+++ 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 src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx
index 54810ca..30bd40a 100644
--- src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_color.cxx
+++ 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 src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx
index 89dea69..c196335 100644
--- src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_line_style.cxx
+++ 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 src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx
index f47aaab..5b61b3a 100644
--- src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx
+++ 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 src/fl_color.cxx src/fl_color.cxx
index 861f8d7..8d3d045 100644
--- src/fl_color.cxx
+++ 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 src/fl_gtk.cxx src/fl_gtk.cxx
index bceae8e..eb47c6c 100644
--- src/fl_gtk.cxx
+++ 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);
diff --git test/CMakeLists.txt test/CMakeLists.txt
index 9197eba..f52af5c 100644
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -139,9 +139,28 @@ CREATE_EXAMPLE (tile tile.cxx fltk)
 CREATE_EXAMPLE (tiled_image tiled_image.cxx fltk)
 CREATE_EXAMPLE (tree tree.fl fltk)
 CREATE_EXAMPLE (twowin twowin.cxx fltk)
+SET (UNITTEST_SRCS
+  unittests.cxx
+  unittest_about.cxx
+  unittest_points.cxx
+  unittest_complex_shapes.cxx
+  unittest_fast_shapes.cxx
+  unittest_circles.cxx
+  unittest_text.cxx
+  unittest_symbol.cxx
+  unittest_images.cxx
+  unittest_viewport.cxx
+  unittest_scrollbarsize.cxx
+  unittest_schemes.cxx
+  unittest_simple_terminal.cxx
+)
+if (OPENGL_FOUND)
+  CREATE_EXAMPLE (unittests "${UNITTEST_SRCS}" "fltk_gl;fltk;${OPENGL_LIBRARIES}") # opt. Fl_Gl_Window
+else()
+  CREATE_EXAMPLE (unittests "${UNITTEST_SRCS}" fltk) # w/o Fl_Gl_Window
+endif()
 CREATE_EXAMPLE (utf8 utf8.cxx fltk)
 CREATE_EXAMPLE (valuators valuators.fl fltk)
-CREATE_EXAMPLE (unittests unittests.cxx fltk)
 CREATE_EXAMPLE (windowfocus windowfocus.cxx fltk)
 CREATE_EXAMPLE (wizard wizard.cxx fltk)
 
diff --git test/Makefile test/Makefile
index c08446a..49d56e7 100644
--- test/Makefile
+++ test/Makefile
@@ -16,6 +16,36 @@
 
 include ../makeinclude
 
+CPPUNITTEST = \
+	unittests.cxx \
+	unittest_about.cxx \
+	unittest_points.cxx \
+	unittest_complex_shapes.cxx \
+	unittest_fast_shapes.cxx \
+	unittest_circles.cxx \
+	unittest_text.cxx \
+	unittest_symbol.cxx \
+	unittest_images.cxx \
+	unittest_viewport.cxx \
+	unittest_scrollbarsize.cxx \
+	unittest_schemes.cxx \
+	unittest_simple_terminal.cxx
+
+OBJUNITTEST = \
+	unittests.o \
+	unittest_about.o \
+	unittest_points.o \
+	unittest_complex_shapes.o \
+	unittest_fast_shapes.o \
+	unittest_circles.o \
+	unittest_text.o \
+	unittest_symbol.o \
+	unittest_images.o \
+	unittest_viewport.o \
+	unittest_scrollbarsize.o \
+	unittest_schemes.o \
+	unittest_simple_terminal.o
+
 CPPFILES =\
 	adjuster.cxx \
 	animated.cxx \
@@ -103,13 +133,12 @@ CPPFILES =\
 	tiled_image.cxx \
 	tree.cxx \
 	twowin.cxx \
-	unittests.cxx \
 	utf8.cxx \
 	valuators.cxx \
-	windowfocus.cxx
+	windowfocus.cxx \
+	$(CPPUNITTEST)
 
 ALL =	\
-	unittests$(EXEEXT) \
 	animated$(EXEEXT) \
 	adjuster$(EXEEXT) \
 	arc$(EXEEXT) \
@@ -200,7 +229,8 @@ GLALL = \
 	fullscreen$(EXEEXT) \
 	gl_overlay$(EXEEXT) \
 	glpuzzle$(EXEEXT) \
-	shape$(EXEEXT)
+	shape$(EXEEXT) \
+	unittests$(EXEEXT)
 
 all:	$(ALL) $(GLDEMOS)
 
@@ -299,11 +329,7 @@ uninstall-osx:
 $(ALL): $(LIBNAME)
 
 # General demos...
-unittests$(EXEEXT): unittests.o
-
-unittests.o: unittests.cxx unittest_about.cxx unittest_points.cxx unittest_lines.cxx unittest_circles.cxx \
-	unittest_rects.cxx unittest_text.cxx unittest_symbol.cxx unittest_viewport.cxx unittest_images.cxx \
-	unittest_schemes.cxx unittest_scrollbarsize.cxx unittest_simple_terminal.cxx
+unittests$(EXEEXT): $(OBJUNITTEST)
 
 adjuster$(EXEEXT): adjuster.o
 
@@ -626,6 +652,11 @@ gl_overlay$(EXEEXT): gl_overlay.o
 	$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ gl_overlay.o $(LINKFLTKGL) $(LINKFLTK) $(GLDLIBS)
 	$(OSX_ONLY) ../fltk-config --post $@
 
+unittests$(EXEEXT): $(OBJUNITTEST)
+	echo Linking $@...
+	$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJUNITTEST) $(LINKFLTKGL) $(LINKFLTK) $(GLDLIBS)
+	$(OSX_ONLY) ../fltk-config --post $@
+
 shape$(EXEEXT): shape.o
 	echo Linking $@...
 	$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ shape.o $(LINKFLTKGL) $(LINKFLTK) $(GLDLIBS)
diff --git test/cube.cxx test/cube.cxx
index 64e9044..fa96130 100644
--- test/cube.cxx
+++ test/cube.cxx
@@ -18,6 +18,7 @@
 
 #include <config.h>
 #include <FL/Fl.H>
+#include <FL/fl_ask.H>
 #include <FL/Fl_Window.H>
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Button.H>
@@ -184,6 +185,12 @@ void print_cb(Fl_Widget *w, void *data)
 #define MARGIN2   (MARGIN*2)
 #define MARGIN3   (MARGIN*3)
 
+void show_info_cb(Fl_Widget*, void*) {
+  fl_message("This is an example of using FLTK widgets inside OpenGL windows.\n"
+             "Multiple widgets can be added to Fl_Gl_Windows. They will be\n"
+             "rendered as overlays over the scene.");
+}
+
 void makeform(const char *name) {
   // Widget's XYWH's
   int form_w = 800 + 4 * MARGIN;             // main window width
@@ -207,6 +214,14 @@ void makeform(const char *name) {
     lt_grp->begin();
       // left GL window
       lt_cube = new cube_box(lt_cub_x, lt_cub_y, lt_cub_w, lt_cub_h, 0);
+
+      lt_cube->begin();
+      Fl_Widget *w = new Fl_Button(10, 10, 120, 30, "FLTK over GL");
+      w->color(FL_FREE_COLOR);
+      w->box(FL_BORDER_BOX );
+      w->callback(show_info_cb);
+      lt_cube->end();
+
       // center group
       Fl_Group *ct_grp = new Fl_Group(ct_grp_x, ct_grp_y, ct_grp_w, ct_grp_h);
       ct_grp->begin();
@@ -238,6 +253,7 @@ void makeform(const char *name) {
 
 int main(int argc, char **argv) {
   Fl::use_high_res_GL(1);
+  Fl::set_color(FL_FREE_COLOR, 255, 255, 0, 75);
   makeform(argv[0]);
   speed->bounds(4,0);
 #if HAVE_GL
@@ -246,7 +262,7 @@ int main(int argc, char **argv) {
   speed->value(lt_cube->speed = rt_cube->speed = 0.0);
 #endif
   size->bounds(4,0.01);
-  size->value(lt_cube->size = rt_cube->size = 1.0);
+  size->value(lt_cube->size = rt_cube->size = 3.0);
   flat->value(1); lt_cube->wire = 0; rt_cube->wire = 1;
   form->label("cube");
   form->show(argc,argv);
diff --git test/makedepend test/makedepend
index 6fc9d44..e0b2658 100644
--- test/makedepend
+++ test/makedepend
@@ -2535,9 +2535,9 @@ unittests.o: ../FL/platform_types.h
 unittests.o: unittest_about.cxx
 unittests.o: unittest_circles.cxx
 unittests.o: unittest_images.cxx
-unittests.o: unittest_lines.cxx
+unittests.o: unittest_complex_shapes.cxx
 unittests.o: unittest_points.cxx
-unittests.o: unittest_rects.cxx
+unittests.o: unittest_fast_shapes.cxx
 unittests.o: unittest_schemes.cxx
 unittests.o: unittest_scrollbarsize.cxx
 unittests.o: unittest_simple_terminal.cxx
diff --git test/unittest_about.cxx test/unittest_about.cxx
index 966c7cb..3c4084d 100644
--- test/unittest_about.cxx
+++ test/unittest_about.cxx
@@ -14,6 +14,8 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Help_View.H>
 
 //
@@ -51,4 +53,4 @@ public:
   }
 };
 
-UnitTest about("About...", About::create);
+UnitTest about(kTestAbout, "About...", About::create);
diff --git test/unittest_circles.cxx test/unittest_circles.cxx
index 62ef280..0d3fad2 100644
--- test/unittest_circles.cxx
+++ test/unittest_circles.cxx
@@ -14,71 +14,203 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
+#include <config.h>
 #include <FL/Fl_Box.H>
 #include <FL/fl_draw.H>
+#include <FL/math.h>
+#if HAVE_GL
+#include <FL/Fl_Gl_Window.H>
+#endif
+
+//
+// --- test drawing circles and arcs ------
+//
+
+void arc(int xi, int yi, int w, int h, double a1, double a2)
+{
+  if (a2<=a1) return;
+
+  double rx = w/2.0;
+  double ry = h/2.0;
+  double x = xi + rx + 0.5;
+  double y = yi + ry + 0.5;
+  double circ = M_PI*0.5*(rx+ry);
+  int i, segs = circ * (a2-a1) / 100;
+  if (segs<3) segs = 3;
+
+  int px, py;
+  a1 = a1/180*M_PI;
+  a2 = a2/180*M_PI;
+  double step = (a2-a1)/segs;
+
+  int nx = x + cos(a1)*rx;
+  int ny = y - sin(a1)*ry;
+  fl_point(nx, ny);
+  for (i=segs; i>0; i--) {
+    a1+=step;
+    px = nx; py = ny;
+    nx = x + cos(a1)*rx;
+    ny = y - sin(a1)*ry;
+    //fl_line(px, py, nx, ny);
+    fl_point(nx, ny);
+  }
+}
+
+void draw_circles() {
+  int a = 0, b = 0, w=40, h=40;
+  // ---- 1: draw a circle and a filled circle
+  fl_color(FL_RED);
+  arc(a+1, b+1, w-2, h-2, 0.0, 360.0);
+  fl_color(FL_GREEN);
+  arc(a, b, w, h, 0.0, 360.0);
+  arc(a+2, b+2, w-4, h-4, 0.0, 360.0);
+  fl_color(FL_BLACK);
+  fl_arc(a+1, b+1, w-1, h-1, 0.0, 360.0);
+  // ----
+  fl_color(FL_RED);
+  arc(a+1+50, b+1, w-2, h-2, 0.0, 360.0);
+  fl_color(FL_GREEN);
+  arc(a+50, b, w, h, 0.0, 360.0);
+  fl_color(FL_BLACK);
+  fl_pie(a+1+50, b+1, w-1, h-1, 0.0, 360.0);
+  b+=44;
+  // ---- 2: draw arcs and pies
+  fl_color(FL_RED);
+//  arc(a-5, b-5, w+10, h+10, 45.0, 315.0);
+  arc(a+1, b+1, w-2, h-2, 45.0, 315.0);
+//  arc(a+5, b+5, w-10, h-10, 45.0, 315.0);
+//  arc(a+10, b+10, w-20, h-20, 45.0, 315.0);
+  fl_color(FL_GREEN);
+  arc(a, b, w, h, 45.0, 315.0);
+  arc(a+2, b+2, w-4, h-4, 45.0, 315.0);
+  fl_color(FL_BLACK);
+//  fl_arc(a-5, b-5, w+10, h+10, 45.0, 315.0);
+  fl_arc(a+1, b+1, w-1, h-1, 45.0, 315.0);
+//  fl_arc(a+5, b+5, w-10, h-10, 45.0, 315.0);
+//  fl_arc(a+10, b+10, w-20, h-20, 45.0, 315.0);
+  fl_color(FL_RED);
+  // ----
+  arc(a+1+50, b+1, w-2, h-2, 45.0, 315.0);
+  fl_line(a+50+20, b+20, a+50+20+14, b+20-14);
+  fl_line(a+50+20, b+20, a+50+20+14, b+20+14);
+  fl_color(FL_GREEN);
+  arc(a+50, b, w, h, 45.0, 315.0);
+  fl_line(a+50+21, b+20, a+50+21+14, b+20-14);
+  fl_line(a+50+21, b+20, a+50+21+14, b+20+14);
+  fl_color(FL_BLACK);
+  fl_pie(a+1+50, b+1, w-1, h-1, 45.0, 315.0);
+}
+
+#if HAVE_GL
+
+class GLCircleTest : public Fl_Gl_Window {
+public:
+  GLCircleTest(int x, int y, int w, int h)
+  : Fl_Gl_Window(x, y, w, h) {
+    box(FL_FLAT_BOX);
+  }
+  void draw() {
+    draw_begin();
+    Fl_Window::draw();
+    draw_circles();
+    draw_end();
+  }
+};
+
+#endif
+
+class NativeCircleTest : public Fl_Window {
+public:
+  NativeCircleTest(int x, int y, int w, int h)
+  : Fl_Window(x, y, w, h) {
+    box(FL_FLAT_BOX);
+    end();
+  }
+  void draw() {
+    Fl_Window::draw();
+    draw_circles();
+  }
+};
 
 //
 //------- test the circle drawing capabilities of this implementation ----------
 //
-class CircleTest : public Fl_Box {
+class CircleTest : public Fl_Group {
 public:
   static Fl_Widget *create() {
     return new CircleTest(TESTAREA_X, TESTAREA_Y, TESTAREA_W, TESTAREA_H);
   }
-  CircleTest(int x, int y, int w, int h) : Fl_Box(x, y, w, h) {
-    label("testing int drawing of circles and ovals (fl_arc, fl_pie)\n"
+  CircleTest(int x, int y, int w, int h) : Fl_Group(x, y, w, h) {
+    label("Testing fast circle, arc, and pie drawing\n\n"
           "No red lines should be visible. "
-          "If you see bright red pixels, the circle drawing alignment is off. "
-          "If you see dark red pixels, your system supports anti-aliasing "
-          "which should be of no concern. "
-          "The green rectangles should not be overwritten by circle drawings.");
+          "The green outlines should not be overwritten by circle drawings.");
     align(FL_ALIGN_INSIDE|FL_ALIGN_BOTTOM|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
     box(FL_BORDER_BOX);
-  }
-  void draw() {
-    Fl_Box::draw();
-    int a = x()+10, b = y()+10; fl_color(FL_BLACK); fl_rect(a, b, 100, 100);
-    // test fl_arc for full circles
-    fl_color(FL_GREEN); fl_rect(a+ 9, b+ 9, 33, 33);
-    fl_color(FL_RED); fl_xyline(a+24, b+10, a+27); fl_xyline(a+24, b+40, a+27);
-    fl_yxline(a+10, b+24, b+27); fl_yxline(a+40, b+24, b+27);
-    fl_color(FL_BLACK); fl_arc(a+10, b+10, 31, 31, 0.0, 360.0);
-    // test fl_arc segmet 1
-    fl_color(FL_GREEN); fl_rect(a+54, b+ 4, 43, 43);
-    fl_rect(a+54, b+4, 18, 18); fl_rect(a+79, b+29, 18, 18);
-    fl_color(FL_RED); fl_point(a+55, b+30); fl_point(a+70, b+45);
-    fl_point(a+80, b+5); fl_point(a+95, b+20);
-    fl_color(FL_BLACK); fl_arc(a+65, b+ 5, 31, 31, -35.0, 125.0);
-    // test fl_arc segmet 2
-    fl_color(FL_BLACK); fl_arc(a+55, b+15, 31, 31, 145.0, 305.0);
-    // test fl_pie for full circles
-    fl_color(FL_RED); fl_xyline(a+24, b+60, a+27); fl_xyline(a+24, b+90, a+27);
-    fl_yxline(a+10, b+74, b+77); fl_yxline(a+40, b+74, b+77);
-    fl_color(FL_GREEN); fl_rect(a+ 9, b+59, 33, 33);
-    fl_color(FL_BLACK); fl_pie(a+10, b+60, 31, 31, 0.0, 360.0);
-    // test fl_pie segmet 1
-    fl_color(FL_GREEN); fl_rect(a+54, b+54, 43, 43);
-    fl_rect(a+54, b+54, 18, 18); fl_rect(a+79, b+79, 18, 18);
-    fl_point(a+79, b+71); fl_point(a+71, b+79);
-    fl_color(FL_RED); fl_point(a+55, b+80); fl_point(a+70, b+95);
-    fl_point(a+80, b+55); fl_point(a+95, b+70);
-    fl_point(a+81, b+69); fl_point(a+69, b+81);
-    fl_color(FL_BLACK); fl_pie(a+65, b+55, 31, 31, -30.0, 120.0);
-    // test fl_pie segmet 2
-    fl_color(FL_BLACK); fl_pie(a+55, b+65, 31, 31, 150.0, 300.0);
-    //---- oval testing (horizontal squish)
-    a +=120; b += 0; fl_color(FL_BLACK); fl_rect(a, b, 100, 100);
-    fl_color(FL_GREEN);
-    fl_rect(a+19, b+9, 63, 33); fl_rect(a+19, b+59, 63, 33);
-    fl_color(FL_BLACK);
-    fl_arc(a+20, b+10, 61, 31, 0, 360); fl_pie(a+20, b+60, 61, 31, 0, 360);
-    //---- oval testing (horizontal squish)
-    a += 120; b += 0; fl_color(FL_BLACK); fl_rect(a, b, 100, 100);
-    fl_color(FL_GREEN);
-    fl_rect(a+9, b+19, 33, 63); fl_rect(a+59, b+19, 33, 63);
-    fl_color(FL_BLACK);
-    fl_arc(a+10, b+20, 31, 61, 0, 360); fl_pie(a+60, b+20, 31, 61, 0, 360);
+
+    int a = x+16, b = y+34;
+    Fl_Box *t = new Fl_Box(a, b-24, 80, 18, "native");
+    t->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+
+    /* NativeCircleTest *nr = */ new NativeCircleTest(a+23, b-1, 200, 200);
+
+    t = new Fl_Box(a, b, 18, 18, "1");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing circle alignment.\n\n"
+               // Description:
+               "This draws a black circle and a black disc, surrounded by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing, circle drawing must be adjusted (see fl_arc, fl_pie).\n\n"
+               "If red pixels are showing, line width or aligment may be off."
+               );
+    b+=44;
+    t = new Fl_Box(a, b, 18, 18, "2");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing arc and pie drawing.\n\n"
+               // Description:
+               "This draws a black frame, surrounded on the inside and outside by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, rectangular frame drawing schould be adjusted (see fl_rect).\n\n"
+               "If red pixels show in the corners of the frame in hidpi mode, line endings should be adjusted."
+               );
+
+#if HAVE_GL
+
+    a = x+16+250, b = y+34;
+    t = new Fl_Box(a, b-24, 80, 18, "OpenGL");
+    t->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+
+    /* GLCircleTest *glr = */ new GLCircleTest(a+31, b-1, 200, 200);
+
+    t = new Fl_Box(a, b, 26, 18, "1a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing circle alignment.\n\n"
+               // Description:
+               "This draws a black circle and a black disc, surrounded by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing, circle drawing must be adjusted (see fl_arc, fl_pie).\n\n"
+               "If red pixels are showing, line width or aligment may be off."
+               );
+    b+=44;
+    t = new Fl_Box(a, b, 26, 18, "2a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing arc and pie drawing.\n\n"
+               // Description:
+               "This draws a black frame, surrounded on the inside and outside by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, rectangular frame drawing schould be adjusted (see fl_rect).\n\n"
+               "If red pixels show in the corners of the frame in hidpi mode, line endings should be adjusted."
+               );
+#endif
+
+    t = new Fl_Box(x+w-1,y+h-1, 1, 1);
+    resizable(t);
   }
 };
 
-UnitTest circle("circles and arcs", CircleTest::create);
+UnitTest circle(kTestCircles, "Circles and Arcs", CircleTest::create);
diff --git test/unittest_complex_shapes.cxx test/unittest_complex_shapes.cxx
new file mode 100644
index 0000000..399243e
--- /dev/null
+++ test/unittest_complex_shapes.cxx
@@ -0,0 +1,121 @@
+//
+// Unit tests for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+//     https://www.fltk.org/bugs.php
+//
+
+#include "unittests.h"
+
+#include <FL/Fl_Box.H>
+#include <FL/fl_draw.H>
+
+#if 0
+
+// TODO:
+void fl_push_matrix()
+void fl_pop_matrix()
+
+void fl_scale(double x,double y)
+void fl_scale(double x)
+void fl_translate(double x,double y)
+void fl_rotate(double d)
+void fl_mult_matrix(double a,double b,double c,double d,double x,double y)
+
+double fl_transform_x(double x, double y)
+double fl_transform_y(double x, double y)
+double fl_transform_dx(double x, double y)
+double fl_transform_dy(double x, double y)
+void fl_transformed_vertex(double xf, double yf)
+
+void fl_begin_points()
+void fl_end_points()
+
+void fl_begin_line()
+void fl_end_line()
+
+void fl_begin_loop()
+void fl_end_loop()
+
+void fl_begin_polygon()
+void fl_end_polygon()
+
+void fl_begin_complex_polygon()
+void fl_gap()
+void fl_end_complex_polygon()
+
+void fl_vertex(double x,double y)
+
+void fl_curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3)
+
+void fl_arc(double x, double y, double r, double start, double end)
+void fl_circle(double x, double y, double r)
+
+
+#endif
+
+//
+//------- test Complex Shape drawing capabilities of this implementation ----------
+//
+class ComplexShapesTest : public Fl_Box {
+public:
+  static Fl_Widget *create() {
+    return new ComplexShapesTest(TESTAREA_X, TESTAREA_Y, TESTAREA_W, TESTAREA_H);
+  }
+  ComplexShapesTest(int x, int y, int w, int h) : Fl_Box(x, y, w, h) {
+    label("Testing complex shape drawing.\n\n"
+          "Complex Shapes in FLTK are rendered using floating point coordinates "
+          "which can be transformed through a matrix.");
+    align(FL_ALIGN_INSIDE|FL_ALIGN_BOTTOM|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
+    box(FL_BORDER_BOX);
+  }
+  void draw() {
+    Fl_Box::draw();
+
+    int i, a = x()+10, b = y()+10; fl_color(FL_BLACK); fl_rect(a, b, 100, 100);
+    // testing fl_xyline(x, y, x1)
+    fl_color(FL_RED); fl_point(a+10, b+10); fl_point(a+20, b+10);
+    fl_color(FL_BLACK); fl_xyline(a+10, b+10, a+20);
+    // testing fl_xyline(x, y, x1, y2);
+    fl_color(FL_RED); fl_point(a+10, b+20); fl_point(a+20, b+20);
+    fl_point(a+20, b+30);
+    fl_color(FL_BLACK); fl_xyline(a+10, b+20, a+20, b+30);
+    // testing fl_xyline(x, y, x1, y2, x3);
+    fl_color(FL_RED); fl_point(a+10, b+40); fl_point(a+20, b+40);
+    fl_point(a+20, b+50); fl_point(a+30, b+50);
+    fl_color(FL_BLACK); fl_xyline(a+10, b+40, a+20, b+50, a+30);
+    //+++ add testing for the fl_yxline commands!
+    // testing fl_loop(x,y, x,y, x,y, x, y)
+    fl_color(FL_RED); fl_point(a+60, b+60); fl_point(a+90, b+60);
+    fl_point(a+60, b+90); fl_point(a+90, b+90);
+    fl_color(FL_BLACK);
+    fl_loop(a+60, b+60, a+90, b+60, a+90, b+90, a+60, b+90);
+
+    a = x()+120, b = y()+10; fl_color(FL_BLACK); fl_rect(a, b, 203, 203);
+    a += 101; b += 101;
+    fl_color(0xff888800);
+    for (i=-80; i<=80; i+=20) fl_line(a, b, a+i, b-100);
+    fl_color(0xff444400);
+    for (i=-80; i<=80; i+=20) fl_line(a, b, a+i, b+100);
+    fl_color(0x88ff8800);
+    for (i=-80; i<=80; i+=20) fl_line(a, b, a-100, b+i);
+    fl_color(0x44ff4400);
+    for (i=-80; i<=80; i+=20) fl_line(a, b, a+100, b+i);
+    fl_color(0x8888ff00);
+    fl_line(a, b, a-100, b-100);
+    fl_line(a, b, a+100, b-100);
+    fl_line(a, b, a+100, b+100);
+    fl_line(a, b, a-100, b+100);
+  }
+};
+
+//UnitTest lines(kTestComplexShapes, "Complex Shapes", ComplexShapesTest::create);
diff --git test/unittest_fast_shapes.cxx test/unittest_fast_shapes.cxx
new file mode 100644
index 0000000..c486eb1
--- /dev/null
+++ test/unittest_fast_shapes.cxx
@@ -0,0 +1,383 @@
+//
+// Unit tests for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+//     https://www.fltk.org/bugs.php
+//
+
+#include "unittests.h"
+
+#include <config.h>
+#include <FL/Fl_Box.H>
+#include <FL/fl_draw.H>         // fl_text_extents()
+#if HAVE_GL
+#include <FL/Fl_Gl_Window.H>
+#endif
+
+#if 0
+
+// TODO:
+void fl_line(int x, int y, int x1, int y1)
+void fl_line(int x, int y, int x1, int y1, int x2, int y2)
+
+Draw one or two lines between the given points.
+void fl_loop(int x, int y, int x1, int y1, int x2, int y2)
+void fl_loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3)
+
+Outline a 3 or 4-sided polygon with lines.
+void fl_polygon(int x, int y, int x1, int y1, int x2, int y2)
+void fl_polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3)
+
+Draw vertical and horizontal lines. A vertical line is drawn first, then a horizontal, then a vertical.
+
+#endif
+
+//
+// --- test drawing shapes that are not transformed by the drawing matrix ------
+//
+
+void draw_fast_shapes() {
+  int a = 0, b = 0, i;
+  // 1: draw a filled rectangle (fl_rectf)
+  fl_color(FL_GREEN);
+  for (i=0; i<=40; i++) { fl_point(a+i, b); fl_point(a+i, b+20); }
+  for (i=0; i<=20; i++) { fl_point(a, b+i); fl_point(a+40, b+i); }
+  fl_color(FL_RED);
+  for (i=1; i<=39; i++) { fl_point(a+i, b+1); fl_point(a+i, b+19); }
+  for (i=1; i<=19; i++) { fl_point(a+1, b+i); fl_point(a+39, b+i); }
+  fl_color(FL_BLACK);
+  fl_rectf(a+1, b+1, 39, 19);
+  // 2: draw a one units wide frame
+  b+=24;
+  fl_color(FL_GREEN);
+  for (i=0; i<=40; i++) { fl_point(a+i, b); fl_point(a+i, b+20); }
+  for (i=0; i<=20; i++) { fl_point(a, b+i); fl_point(a+40, b+i); }
+  fl_color(FL_GREEN);
+  for (i=2; i<=38; i++) { fl_point(a+i, b+2); fl_point(a+i, b+18); }
+  for (i=2; i<=18; i++) { fl_point(a+2, b+i); fl_point(a+38, b+i); }
+  fl_color(FL_RED);
+  for (i=1; i<=39; i++) { fl_point(a+i, b+1); fl_point(a+i, b+19); }
+  for (i=1; i<=19; i++) { fl_point(a+1, b+i); fl_point(a+39, b+i); }
+  fl_color(FL_BLACK);
+  fl_rect(a+1, b+1, 39, 19);
+  // 3: draw a three units wide frame
+  b+=24;
+  fl_color(FL_GREEN);
+  fl_rect(a, b, 41, 21);
+  fl_rect(a+4, b+4, 33, 13);
+  fl_color(FL_RED);
+  fl_rect(a+1, b+1, 39, 19);
+  fl_rect(a+3, b+3, 35, 15);
+  fl_color(FL_BLACK);
+  fl_line_style(FL_SOLID, 3);
+  fl_rect(a+2, b+2, 37, 17);
+  fl_line_style(FL_SOLID, 1);
+  // 4: draw fl_xyline
+  b+=24;
+  fl_color(FL_GREEN);
+  fl_rect(a, b+8, 41, 3);   // single line
+  fl_rect(a+45, b, 41, 3);  // horizontal, then vertical line
+  fl_rect(a+83, b, 3, 21);
+  fl_rect(a+90, b, 21, 3);  // horizontal, vertical, horizontal line
+  fl_rect(a+109, b, 3, 21);
+  fl_rect(a+109, b+18, 21, 3);
+  fl_color(FL_RED);
+  fl_rectf(a+1, b+9, 39, 1);  // single line
+  fl_rectf(a+46, b+1, 39, 1); // two lines
+  fl_rectf(a+84, b+1, 1, 19);
+  fl_rectf(a+91, b+1, 20, 1); // three lines
+  fl_rectf(a+110, b+1, 1, 19);
+  fl_rectf(a+110, b+19, 19, 1); // three lines
+  fl_color(FL_BLACK);
+  fl_xyline(a+1, b+9, a+39);
+  fl_xyline(a+46, b+1, a+84, b+19);
+  fl_xyline(a+91, b+1, a+110, b+19, a+128);
+  b+=24;
+  fl_color(FL_GREEN);
+  fl_rect(a, b+7, 41, 5);   // single line
+  fl_rect(a+45, b, 41, 5);  // horizontal, then vertical line
+  fl_rect(a+81, b, 5, 21);
+  fl_rect(a+90, b, 22, 5);  // horizontal, vertical, horizontal line
+  fl_rect(a+108, b, 5, 21);
+  fl_rect(a+108, b+16, 22, 5);
+  fl_color(FL_RED);
+  fl_rectf(a+1, b+8, 39, 3);  // single line
+  fl_rectf(a+46, b+1, 39, 3); // two lines
+  fl_rectf(a+82, b+1, 3, 19);
+  fl_rectf(a+91, b+1, 20, 3); // three lines
+  fl_rectf(a+109, b+1, 3, 19);
+  fl_rectf(a+109, b+17, 20, 3); // three lines
+  fl_color(FL_BLACK);
+  fl_line_style(FL_SOLID, 3);
+  fl_xyline(a+1, b+9, a+39);
+  fl_xyline(a+46, b+2, a+83, b+19);
+  fl_xyline(a+91, b+2, a+110, b+18, a+128);
+  fl_line_style(FL_SOLID, 1);
+  // 5: draw fl_xyline
+  b+=24;
+  fl_color(FL_GREEN);
+  fl_rect(a+9, b, 3, 21);   // single line
+  fl_rect(a+45, b, 3, 21);  // horizontal, then vertical line
+  fl_rect(a+45, b+18, 41, 3);
+  fl_rect(a+90, b, 3, 11);  // horizontal, vertical, horizontal line
+  fl_rect(a+90, b+9, 40, 3);
+  fl_rect(a+127, b+9, 3, 12);
+  fl_color(FL_RED);
+  fl_rectf(a+10, b+1, 1, 19);  // single line
+  fl_rectf(a+46, b+1, 1, 19); // two lines
+  fl_rectf(a+46, b+19, 39, 1);
+  fl_rectf(a+91, b+1, 1, 10); // three lines
+  fl_rectf(a+91, b+10, 38, 1);
+  fl_rectf(a+128, b+10, 1, 10); // three lines
+  fl_color(FL_BLACK);
+  fl_yxline(a+10, b+1, b+19);
+  fl_yxline(a+46, b+1, b+19, a+84);
+  fl_yxline(a+91, b+1, b+10, a+128, b+19);
+  b+=24;
+  fl_color(FL_GREEN);
+  fl_rect(a+8, b, 5, 21);   // single line
+  fl_rect(a+45, b, 5, 21);  // horizontal, then vertical line
+  fl_rect(a+45, b+16, 41, 5);
+  fl_rect(a+90, b, 5, 11);  // horizontal, vertical, horizontal line
+  fl_rect(a+90, b+8, 40, 5);
+  fl_rect(a+125, b+8, 5, 13);
+  fl_color(FL_RED);
+  fl_rectf(a+9, b+1, 3, 19);  // single line
+  fl_rectf(a+46, b+1, 3, 19); // two lines
+  fl_rectf(a+46, b+17, 39, 3);
+  fl_rectf(a+91, b+1, 3, 10); // three lines
+  fl_rectf(a+91, b+9, 38, 3);
+  fl_rectf(a+126, b+9, 3, 11); // three lines
+  fl_color(FL_BLACK);
+  fl_line_style(FL_SOLID, 3);
+  fl_yxline(a+10, b+1, b+19);
+  fl_yxline(a+47, b+1, b+18, a+84);
+  fl_yxline(a+92, b+1, b+10, a+127, b+19);
+  fl_line_style(FL_SOLID, 1);
+  // 6: fast diagonal lines
+  b+=24;
+  fl_color(FL_GREEN);
+  fl_point(a, b); fl_point(a+1, b); fl_point(a, b+1);
+  fl_point(a+20, b+20); fl_point(a+19, b+20); fl_point(a+20, b+19);
+  fl_color(FL_RED);
+  fl_point(a+1, b+1); fl_point(a+19, b+19);
+  fl_color(FL_BLACK);
+  fl_line(a+1, b+1, a+19, b+19);
+  fl_color(FL_GREEN);
+  fl_point(a+25+1, b); fl_point(a+25, b+1); fl_point(a+25+4, b); fl_point(a+25, b+4);
+  fl_point(a+25+20, b+19); fl_point(a+25+19, b+20); fl_point(a+25+16, b+20); fl_point(a+25+20, b+16);
+  fl_color(FL_RED);
+  fl_point(a+25+2, b+2); fl_point(a+25+18, b+18);
+  fl_color(FL_BLACK);
+  fl_line_style(FL_SOLID, 5);
+  fl_line(a+25+1, b+1, a+25+19, b+19);
+  fl_line(a+50+1, b+1, a+50+20, b+20, a+50+39, b+1);
+  fl_line_style(FL_SOLID, 1);
+}
+
+#if HAVE_GL
+
+class GLRectTest : public Fl_Gl_Window {
+public:
+  GLRectTest(int x, int y, int w, int h)
+  : Fl_Gl_Window(x, y, w, h) {
+    box(FL_FLAT_BOX);
+  }
+  void draw() {
+    draw_begin();
+    fl_color(color());
+    fl_rectf(0, 0, w(), h());
+    draw_fast_shapes();
+    draw_end();
+  }
+};
+
+#endif
+
+class NativeRectTest : public Fl_Window {
+public:
+  NativeRectTest(int x, int y, int w, int h)
+  : Fl_Window(x, y, w, h) {
+    box(FL_FLAT_BOX);
+    end();
+  }
+  void draw() {
+    Fl_Window::draw();
+    draw_fast_shapes();
+  }
+};
+
+class RectTest : public Fl_Group { // 520 x 365
+public:
+  static Fl_Widget *create() {
+    return new RectTest(TESTAREA_X, TESTAREA_Y, TESTAREA_W, TESTAREA_H);
+  }
+  RectTest(int x, int y, int w, int h) : Fl_Group(x, y, w, h) {
+    label("Testing FLTK fast shape calls.\n"
+          "These calls draw horizontal and vertical lines, frames, and rectangles.\n\n"
+          "No red pixels should be visible. "
+          "If you see bright red lines, or if parts of the green frames are hidden, "
+          "drawing alignment is off.");
+    align(FL_ALIGN_INSIDE|FL_ALIGN_BOTTOM|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
+    box(FL_BORDER_BOX);
+
+    int a = x+16, b = y+34;
+    Fl_Box *t = new Fl_Box(a, b-24, 80, 18, "native");
+    t->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+
+    /* NativeRectTest *nr = */ new NativeRectTest(a+23, b-1, 200, 200);
+
+    t = new Fl_Box(a, b, 18, 18, "1");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing filled rectangle alignment.\n\n"
+               // Description:
+               "This draws a black rectangle, surrounded by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing, filled rectangles draw too big (see fl_rectf).\n\n"
+               "If red pixels are showing, filled rectangles are drawn too small."
+               );
+    b+=24;
+    t = new Fl_Box(a, b, 18, 18, "2");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing rectangle frame alignment.\n\n"
+               // Description:
+               "This draws a black frame, surrounded on the inside and outside by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, rectangular frame drawing schould be adjusted (see fl_rect).\n\n"
+               "If red pixels show in the corners of the frame in hidpi mode, line endings should be adjusted."
+               );
+    b+=24;
+    t = new Fl_Box(a, b, 18, 18, "3");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing scaled frame alignment.\n\n"
+               // Description:
+               "This draws a 3 units wide black frame, surrounded on the inside and outside by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, line width schould be adjusted (see fl_line_style).\n\n"
+               "If red pixels show in the corners of the frame in hidpi mode, line endings should be adjusted."
+               );
+    b+=24;
+    t = new Fl_Box(a, b, 18, 18, "4");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing fl_xyline.\n\n"
+               // Description:
+               "This draws 3 versions of fl_xyline surronded with a green outline.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, fl_xyline must be adjusted."
+               );
+    b+=48;
+    t = new Fl_Box(a, b, 18, 18, "5");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing fl_yxline.\n\n"
+               // Description:
+               "This draws 3 versions of fl_yxline surronded with a green outline.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, fl_yxline must be adjusted."
+               );
+    b+=48;
+    t = new Fl_Box(a, b, 18, 18, "6");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing fl_line(int...).\n\n"
+               // Description:
+               "This draws 2 lines at differnet widths, and one connected line.\n\n"
+               // Things to look out for:
+               "Green and red pixels mark the beginning and end of single lines."
+               "The line caps should be flat, the joints shoould be of type \"miter\"."
+               );
+
+#if HAVE_GL
+
+    a = x+16+250, b = y+34;
+    t = new Fl_Box(a, b-24, 80, 18, "OpenGL");
+    t->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+
+    /*GLRectTest *glr = */ new GLRectTest(a+31, b-1, 200, 200);
+
+    t = new Fl_Box(a, b, 26, 18, "1a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing filled rectangle alignment.\n\n"
+               // Description:
+               "This draws a black rectangle, surrounded by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing, filled rectangles draw too big (see fl_rectf).\n\n"
+               "If red pixels are showing, filled rectangles are drawn too small."
+               );
+    
+    b+=24;
+    t = new Fl_Box(a, b, 26, 18, "2a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing rectangle frame alignment.\n\n"
+               // Description:
+               "This draws a black frame, surrounded on the inside and outside by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, rectangular frame drawing schould be adjusted (see fl_rect).\n\n"
+               "If red pixels show in the corners of the frame in hidpi mode, line endings should be adjusted."
+               );
+
+    b+=24;
+    t = new Fl_Box(a, b, 26, 18, "3a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing scaled frame alignment.\n\n"
+               // Description:
+               "This draws a 3 units wide black frame, surrounded on the inside and outside by a green frame.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, line width schould be adjusted (see fl_line_style).\n\n"
+               "If red pixels show in the corners of the frame in hidpi mode, line endings should be adjusted."
+               );
+    b+=24;
+    t = new Fl_Box(a, b, 26, 18, "4a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing fl_xyline.\n\n"
+               // Description:
+               "This draws 3 versions of fl_xyline surronded with a green outline.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, fl_xyline must be adjusted."
+               );
+    b+=48;
+    t = new Fl_Box(a, b, 26, 18, "5a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing fl_yxline.\n\n"
+               // Description:
+               "This draws 3 versions of fl_yxline surronded with a green outline.\n\n"
+               // Things to look out for:
+               "If green pixels are missing or red pixels are showing, fl_yxline must be adjusted."
+               );
+    b+=48;
+    t = new Fl_Box(a, b, 26, 18, "6a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing fl_line(int...).\n\n"
+               // Description:
+               "This draws 2 lines at differnet widths, and one connected line.\n\n"
+               // Things to look out for:
+               "Green and red pixels mark the beginning and end of single lines."
+               "The line caps should be flat, the joints shoould be of type \"miter\"."
+               );
+#endif
+
+    t = new Fl_Box(x+w-1,y+h-1, 1, 1);
+    resizable(t);
+  }
+};
+
+UnitTest rects(kTestFastShapes, "Fast Shapes", RectTest::create);
diff --git test/unittest_images.cxx test/unittest_images.cxx
index 210af96..dcc720f 100644
--- test/unittest_images.cxx
+++ test/unittest_images.cxx
@@ -14,12 +14,16 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Group.H>
 #include <FL/Fl_Button.H>
 #include <FL/Fl_Radio_Button.H>
 #include <FL/Fl_Check_Button.H>
 #include <FL/fl_draw.H>
 
+#include <stdlib.h>
+
 // Note: currently (March 2010) fl_draw_image() supports transparency with
 //       alpha channel only on Apple (Mac OS X), but Fl_RGB_Image->draw()
 //       supports transparency on all platforms !
@@ -291,4 +295,4 @@ Fl_RGB_Image *ImageTest::i_ga = 0;
 Fl_RGB_Image *ImageTest::i_rgb = 0;
 Fl_RGB_Image *ImageTest::i_rgba = 0;
 
-UnitTest images("drawing images", ImageTest::create);
+UnitTest images(kTestImages, "Drawing Images", ImageTest::create);
diff --git test/unittest_lines.cxx test/unittest_lines.cxx
deleted file mode 100644
index b255159..0000000
--- test/unittest_lines.cxx
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// Unit tests for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2010 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file.  If this
-// file is missing or damaged, see the license at:
-//
-//     https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-//     https://www.fltk.org/bugs.php
-//
-
-#include <FL/Fl_Box.H>
-#include <FL/fl_draw.H>
-
-//
-//------- test the line drawing capabilities of this implementation ----------
-//
-class LineTest : public Fl_Box {
-public:
-  static Fl_Widget *create() {
-    return new LineTest(TESTAREA_X, TESTAREA_Y, TESTAREA_W, TESTAREA_H);
-  }
-  LineTest(int x, int y, int w, int h) : Fl_Box(x, y, w, h) {
-    label("testing the integer based fl_line calls\n"
-          "No red pixels should be visible.\n"
-          "If you see bright red pixels, the line drawing alignment is off,\n"
-          "or the last pixel in a line does not get drawn.\n"
-          "If you see dark red pixels, anti-aliasing must be switched off.");
-    align(FL_ALIGN_INSIDE|FL_ALIGN_BOTTOM|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
-    box(FL_BORDER_BOX);
-  }
-  void draw() {
-    Fl_Box::draw();
-
-    int i, a = x()+10, b = y()+10; fl_color(FL_BLACK); fl_rect(a, b, 100, 100);
-    // testing fl_xyline(x, y, x1)
-    fl_color(FL_RED); fl_point(a+10, b+10); fl_point(a+20, b+10);
-    fl_color(FL_BLACK); fl_xyline(a+10, b+10, a+20);
-    // testing fl_xyline(x, y, x1, y2);
-    fl_color(FL_RED); fl_point(a+10, b+20); fl_point(a+20, b+20);
-    fl_point(a+20, b+30);
-    fl_color(FL_BLACK); fl_xyline(a+10, b+20, a+20, b+30);
-    // testing fl_xyline(x, y, x1, y2, x3);
-    fl_color(FL_RED); fl_point(a+10, b+40); fl_point(a+20, b+40);
-    fl_point(a+20, b+50); fl_point(a+30, b+50);
-    fl_color(FL_BLACK); fl_xyline(a+10, b+40, a+20, b+50, a+30);
-    //+++ add testing for the fl_yxline commands!
-    // testing fl_loop(x,y, x,y, x,y, x, y)
-    fl_color(FL_RED); fl_point(a+60, b+60); fl_point(a+90, b+60);
-    fl_point(a+60, b+90); fl_point(a+90, b+90);
-    fl_color(FL_BLACK);
-    fl_loop(a+60, b+60, a+90, b+60, a+90, b+90, a+60, b+90);
-
-    a = x()+120, b = y()+10; fl_color(FL_BLACK); fl_rect(a, b, 203, 203);
-    a += 101; b += 101;
-    fl_color(0xff888800);
-    for (i=-80; i<=80; i+=20) fl_line(a, b, a+i, b-100);
-    fl_color(0xff444400);
-    for (i=-80; i<=80; i+=20) fl_line(a, b, a+i, b+100);
-    fl_color(0x88ff8800);
-    for (i=-80; i<=80; i+=20) fl_line(a, b, a-100, b+i);
-    fl_color(0x44ff4400);
-    for (i=-80; i<=80; i+=20) fl_line(a, b, a+100, b+i);
-    fl_color(0x8888ff00);
-    fl_line(a, b, a-100, b-100);
-    fl_line(a, b, a+100, b-100);
-    fl_line(a, b, a+100, b+100);
-    fl_line(a, b, a-100, b+100);
-  }
-};
-
-UnitTest lines("drawing lines", LineTest::create);
diff --git test/unittest_points.cxx test/unittest_points.cxx
index f8affc9..22291b2 100644
--- test/unittest_points.cxx
+++ test/unittest_points.cxx
@@ -14,41 +14,293 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
+#include <config.h>
 #include <FL/Fl_Box.H>
 #include <FL/fl_draw.H>
+#if HAVE_GL
+#include <FL/Fl_Gl_Window.H>
+#endif
 
 //
 //------- test the point drawing capabilities of this implementation ----------
 //
-class PointTest : public Fl_Box {
+
+class PointTestWin : public Fl_Window {
+public:
+  PointTestWin(int x, int y, int w, int h) :
+  Fl_Window(x, y, w, h) { end(); }
+  void draw() {
+    int i;
+    fl_color(FL_WHITE);
+    fl_rectf(0, 0, 10, 10);
+    fl_color(FL_BLACK);
+    for (i=0; i<10; i++) {
+      fl_point(i, 0);
+      fl_point(i, 9);
+    }
+    for (i=0; i<10; i++) {
+      fl_point(0, i);
+      fl_point(9, i);
+    }
+  }
+};
+
+#if HAVE_GL
+
+class GLTestWin : public Fl_Gl_Window {
+public:
+  GLTestWin(int x, int y, int w, int h) :
+  Fl_Gl_Window(x, y, w, h) {
+    box(FL_FLAT_BOX);
+    end();
+  }
+  void draw() {
+    Fl_Gl_Window::draw_begin();
+    Fl_Window::draw();
+
+    int a = -24, b = 5-9, i, j;
+    // Test 1a: pixel size
+    fl_color(FL_WHITE); fl_rectf(a+24, b+9-5, 10, 10);
+    fl_color(FL_BLACK);
+    for (i=0; i<8; i++)
+      for (j=0; j<8; j++)
+        if ((i+j)&1)
+          fl_point(a+i+24+1, b+j+9-5+1);
+    // Test 2a: pixel color
+    for (int n=0; n<3; n++) {
+      static Fl_Color lut[3] = { FL_RED, FL_GREEN, FL_BLUE };
+      int yy = b+9-5+24 + 16*n;
+      fl_color(FL_WHITE); fl_rectf(a+24, yy, 10, 10);
+      fl_color(lut[n]);
+      for (i=0; i<8; i++)
+        for (j=0; j<8; j++)
+          fl_point(a+i+24+1, yy+j+1);
+    }
+    // Test 3a: pixel alignment inside windows (drawing happens in PointTestWin)
+    int xx = a+24, yy = b+2*24+2*16+9-5;
+    fl_color(FL_RED);
+    for (i=0; i<10; i++) {
+      fl_point(xx-1, yy+i);
+      fl_point(xx+10, yy+i);
+    }
+    fl_color(FL_BLACK);
+    for (i=0; i<10; i++) {
+      fl_point(xx+i, yy);
+      fl_point(xx+i, yy+9);
+    }
+    for (i=0; i<10; i++) {
+      fl_point(xx, yy+i);
+      fl_point(xx+9, yy+i);
+    }
+    fl_color(FL_WHITE);
+    for (i=0; i<8; i++)
+      for (j=0; j<8; j++)
+        fl_point(xx+i+1, yy+j+1);
+    // Test 4a: check pixel clipping
+    xx = a+24; yy = b+3*24+2*16+9-5;
+    fl_push_clip(xx+1, yy+1, 9, 9);
+    fl_color(FL_RED);
+    for (i=0; i<10; i++) {
+      fl_point(xx+i, yy);
+      fl_point(xx+i, yy+9);
+    }
+    for (i=0; i<10; i++) {
+      fl_point(xx, yy+i);
+      fl_point(xx+9, yy+i);
+    }
+    fl_color(FL_BLACK);
+    for (i=1; i<9; i++) {
+      fl_point(xx+i, yy+1);
+      fl_point(xx+i, yy+8);
+    }
+    for (i=1; i<9; i++) {
+      fl_point(xx+1, yy+i);
+      fl_point(xx+8, yy+i);
+    }
+    fl_color(FL_WHITE);
+    for (i=1; i<7; i++)
+      for (j=1; j<7; j++)
+        fl_point(xx+i+1, yy+j+1);
+    fl_pop_clip();
+
+    Fl_Gl_Window::draw_end();
+  }
+};
+
+#endif
+
+class PointTest : public Fl_Group {
+  PointTestWin *align_test_win;
+#if HAVE_GL
+  GLTestWin *gl_test_win;
+#endif
 public:
   static Fl_Widget *create() {
     return new PointTest(TESTAREA_X, TESTAREA_Y, TESTAREA_W, TESTAREA_H);
+    // 520x365, resizable
   }
-  PointTest(int x, int y, int w, int h) : Fl_Box(x, y, w, h) {
-    label("testing the fl_point call\n"
-          "You should see four pixels each in black, red, green and blue. "
-          "Make sure that pixels are not anti-aliased (blurred across multiple pixels)!");
+  PointTest(int x, int y, int w, int h) : Fl_Group(x, y, w, h) {
+    label("Testing the fl_point call.");
     align(FL_ALIGN_INSIDE|FL_ALIGN_BOTTOM|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
     box(FL_BORDER_BOX);
+    int a = x+16, b = y+34;
+    Fl_Box *t = new Fl_Box(a, b-24, 80, 18, "native");
+    t->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+
+    t = new Fl_Box(a, b, 18, 18, "1");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixel size and antialiasing.\n\n"
+               // Description:
+               "This draws a checker board of black points on a white background.\n\n"
+               // Things to look out for:
+               "Black and white points should be the same size of one unit (1 pixel in regular mode, 2x2 pixels in hidpi mode)."
+               "If black points are smaller than white in hidpi mode, point size must be increased.\n\n"
+               "Points should not be blurry. Antialiasing should be switched of and the point coordinates should be centered on the pixel(s).\n\n"
+               "If parts of the white border are missing, the size of fl_rect should be adjusted."
+               );
+    t = new Fl_Box(a, b+24, 18, 18, "2");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixels color.\n\n"
+               // Description:
+               "This draws three squares in red, green, and blue.\n\n"
+               // Things to look out for:
+               "If the order of colors is different, the byte order when writing into the pixel buffer should be fixed."
+               );
+    t = new Fl_Box(a, b+2*24+2*16, 18, 18, "3");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixels alignment in windows.\n\n"
+               // Description:
+               "This draws a black frame around a white square.\n\n"
+               // Things to look out for:
+               "If parts of the black frame are clipped by the window and not visible, pixel offsets must be adjusted."
+               );
+    align_test_win = new PointTestWin(a+24, b+2*24+2*16+9-5, 10, 10);
+
+    t = new Fl_Box(a, b+3*24+2*16, 18, 18, "4");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixels clipping.\n\n"
+               // Description:
+               "This draws a black frame around a white square.\n\n"
+               // Things to look out for:
+               "If red pixels are visble or black pixels are missing, graphics clipping is misaligned."
+               );
+
+    a+=100;
+#if HAVE_GL
+    t = new Fl_Box(a, b-24, 80, 18, "OpenGL");
+    t->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+
+    t = new Fl_Box(a, b, 26, 18, "1a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixel size and antialiasing.\n\n"
+               // Description:
+               "This draws a checker board of black points on a white background.\n\n"
+               // Things to look out for:
+               "Black and white points should be the same size of one unit (1 pixel in regular mode, 2x2 pixels in hidpi mode)."
+               "If black points are smaller than white in hidpi mode, point size must be increased.\n\n"
+               "Points should not be blurry. Antialiasing should be switched of and the point coordinates should be centered on the pixel(s).\n\n"
+               "If parts of the white border are missing, the size of fl_rect should be adjusted."
+               );
+    t = new Fl_Box(a, b+24, 26, 18, "2a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixels color.\n\n"
+               // Description:
+               "This draws three squares in red, green, and blue.\n\n"
+               // Things to look out for:
+               "If the order of colors is different, the color component order when writing into the pixel buffer should be fixed."
+               );
+    t = new Fl_Box(a, b+2*24+2*16, 26, 18, "3a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixels alignment in windows.\n\n"
+               // Description:
+               "This draws a black frame around a white square, extending to both sides.\n\n"
+               // Things to look out for:
+               "If parts of the black frame are clipped by the window and not visible, pixel offsets must be adjusted horizontally.\n\n"
+               "If the horizontal lines are misaligned, vertical pixel offset should be adjusted."
+               );
+
+    t = new Fl_Box(a, b+3*24+2*16, 26, 18, "4a");
+    t->box(FL_ROUNDED_BOX); t->color(FL_YELLOW);
+    t->tooltip(// Title:
+               "Testing pixels clipping.\n\n"
+               // Description:
+               "This draws a black frame around a white square. The square is slightly smaller.\n\n"
+               // Things to look out for:
+               "If red pixels are visble or black pixels are missing, graphics clipping is misaligned."
+               );
+
+    gl_test_win = new GLTestWin(a+24+8, b+9-5, 10, 4*24+2*16);
+#endif
+
+    t = new Fl_Box(x+w-1,y+h-1, 1, 1);
+    resizable(t);
   }
   void draw() {
-    Fl_Box::draw();
-    int a = x()+10, b = y()+10;
-    fl_color(FL_WHITE); fl_rectf(a, b, 90, 90);
-    fl_color(FL_BLACK); fl_rect(a, b, 90, 90);
-    fl_point(a+10, b+10); fl_point(a+20, b+20);
-    fl_point(a+10, b+20); fl_point(a+20, b+10);
-    fl_color(FL_RED); a = x()+70;
-    fl_point(a+10, b+10); fl_point(a+20, b+20);
-    fl_point(a+10, b+20); fl_point(a+20, b+10);
-    fl_color(FL_GREEN); a = x()+10; b = y()+70;
-    fl_point(a+10, b+10); fl_point(a+20, b+20);
-    fl_point(a+10, b+20); fl_point(a+20, b+10);
-    fl_color(FL_BLUE); a = x()+70;
-    fl_point(a+10, b+10); fl_point(a+20, b+20);
-    fl_point(a+10, b+20); fl_point(a+20, b+10);
+    Fl_Group::draw();
+    int a = x()+16, b = y()+34, i, j;
+    // Test 1: pixel size
+    fl_color(FL_WHITE); fl_rectf(a+24, b+9-5, 10, 10);
+    fl_color(FL_BLACK);
+    for (i=0; i<8; i++)
+      for (j=0; j<8; j++)
+        if ((i+j)&1)
+          fl_point(a+i+24+1, b+j+9-5+1);
+    // Test 2: pixel color
+    for (int n=0; n<3; n++) {
+      static Fl_Color lut[3] = { FL_RED, FL_GREEN, FL_BLUE };
+      int yy = b+9-5+24 + 16*n;
+      fl_color(FL_WHITE); fl_rectf(a+24, yy, 10, 10);
+      fl_color(lut[n]);
+      for (i=0; i<8; i++)
+        for (j=0; j<8; j++)
+          fl_point(a+i+24+1, yy+j+1);
+    }
+    // Test 3: pixel alignment inside windows (drawing happens in PointTestWin)
+    // Test 4: check pixel clipping
+    int xx = a+24, yy = b+3*24+2*16+9-5;
+    fl_push_clip(xx, yy, 10, 10);
+    fl_color(FL_RED);
+    for (i=-1; i<11; i++) {
+      fl_point(xx+i, yy-1);
+      fl_point(xx+i, yy+10);
+    }
+    for (i=-1; i<11; i++) {
+      fl_point(xx-1, yy+i);
+      fl_point(xx+10, yy+i);
+    }
+    fl_color(FL_BLACK);
+    for (i=0; i<10; i++) {
+      fl_point(xx+i, yy);
+      fl_point(xx+i, yy+9);
+    }
+    for (i=0; i<10; i++) {
+      fl_point(xx, yy+i);
+      fl_point(xx+9, yy+i);
+    }
+    fl_color(FL_WHITE);
+    for (i=0; i<8; i++)
+      for (j=0; j<8; j++)
+        fl_point(xx+i+1, yy+j+1);
+    fl_pop_clip();
+    // Test 3a: pixel alignment inside the OpenGL window
+#if HAVE_GL
+    xx = a+24+108; yy = b+2*24+2*16+9-5;
+    fl_color(FL_BLACK);
+    for (i=-4; i<14; i++) {
+      fl_point(xx+i, yy);
+      fl_point(xx+i, yy+9);
+    }
+#endif
   }
 };
 
-UnitTest points("drawing points", PointTest::create);
+UnitTest points(kTestPoints, "Drawing Points", PointTest::create);
diff --git test/unittest_rects.cxx test/unittest_rects.cxx
deleted file mode 100644
index 69d2ae1..0000000
--- test/unittest_rects.cxx
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Unit tests for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2010 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file.  If this
-// file is missing or damaged, see the license at:
-//
-//     https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-//     https://www.fltk.org/bugs.php
-//
-
-#include <FL/Fl_Box.H>
-#include <FL/fl_draw.H>         // fl_text_extents()
-
-//
-//------- test the rectangle drawing capabilities of this implementation ----------
-//
-class RectTest : public Fl_Box {
-public:
-  static Fl_Widget *create() {
-    return new RectTest(TESTAREA_X, TESTAREA_Y, TESTAREA_W, TESTAREA_H);
-  }
-  RectTest(int x, int y, int w, int h) : Fl_Box(x, y, w, h) {
-    label("testing the fl_rect call\n"
-          "No red pixels should be visible. "
-          "If you see bright red lines, or if parts of the green frames are hidden, "
-          "the rect drawing alignment is off.");
-    align(FL_ALIGN_INSIDE|FL_ALIGN_BOTTOM|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
-    box(FL_BORDER_BOX);
-  }
-  void draw() {
-    Fl_Box::draw();
-    int a = x()+10, b = y()+10; fl_color(FL_BLACK); fl_rect(a, b, 100, 100);
-    // testing fl_rect() with positive size
-    fl_color(FL_RED);   fl_loop(a+10, b+10, a+40, b+10, a+40, b+40, a+10, b+40);
-    fl_color(FL_GREEN); fl_loop(a+ 9, b+ 9, a+41, b+ 9, a+41, b+41, a+ 9, b+41);
-    fl_color(FL_GREEN); fl_loop(a+11, b+11, a+39, b+11, a+39, b+39, a+11, b+39);
-    fl_color(FL_BLACK); fl_rect(a+10, b+10, 31, 31);
-    // testing fl_rect() with positive size
-    fl_color(FL_RED);   fl_loop(a+60, b+60, a+90, b+60, a+90, b+90, a+60, b+90);
-    fl_color(FL_GREEN); fl_loop(a+59, b+59, a+91, b+59, a+91, b+91, a+59, b+91);
-    fl_color(FL_BLACK); fl_rectf(a+60, b+60, 31, 31);
-  }
-};
-
-UnitTest rects("rectangles", RectTest::create);
diff --git test/unittest_schemes.cxx test/unittest_schemes.cxx
index 9f5123c..767a18b 100644
--- test/unittest_schemes.cxx
+++ test/unittest_schemes.cxx
@@ -16,6 +16,8 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Choice.H>
 
 // needed by Edmanuel's test layout
@@ -324,4 +326,4 @@ public:
   }
 };
 
-UnitTest schemestest("schemes test", SchemesTest::create);
+UnitTest schemestest(kTestSchemes, "Schemes Test", SchemesTest::create);
diff --git test/unittest_scrollbarsize.cxx test/unittest_scrollbarsize.cxx
index f0aacd1..10b5668 100644
--- test/unittest_scrollbarsize.cxx
+++ test/unittest_scrollbarsize.cxx
@@ -14,7 +14,10 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Group.H>
+#include <FL/Fl_Box.H>
 #include <FL/Fl_Browser.H>
 #include <FL/Fl_Tree.H>
 #include <FL/Fl_Table.H>
@@ -216,4 +219,4 @@ public:
     }
 };
 
-UnitTest scrollbarsize("scrollbar size", ScrollBarSizeTest::create);
+UnitTest scrollbarsize(kTestScrollbarsize, "Scrollbar Size", ScrollBarSizeTest::create);
diff --git test/unittest_simple_terminal.cxx test/unittest_simple_terminal.cxx
index 645f996..7783190 100644
--- test/unittest_simple_terminal.cxx
+++ test/unittest_simple_terminal.cxx
@@ -14,6 +14,8 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <time.h>
 #include <FL/Fl_Group.H>
 #include <FL/Fl_Simple_Terminal.H>
@@ -115,4 +117,4 @@ public:
   }
 };
 
-UnitTest simple_terminal("simple terminal", SimpleTerminal::create);
+UnitTest simple_terminal(kTestSimpleTerminal, "Simple Terminal", SimpleTerminal::create);
diff --git test/unittest_symbol.cxx test/unittest_symbol.cxx
index ee95d15..9e92239 100644
--- test/unittest_symbol.cxx
+++ test/unittest_symbol.cxx
@@ -14,6 +14,8 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Box.H>
 #include <FL/fl_draw.H>
 
@@ -86,4 +88,4 @@ public:
   }
 };
 
-UnitTest symbolExtents("symbol text", SymbolTest::create);
+UnitTest symbolExtents(kTestSymbol, "Symbol Text", SymbolTest::create);
diff --git test/unittest_text.cxx test/unittest_text.cxx
index 80cce72..9613d54 100644
--- test/unittest_text.cxx
+++ test/unittest_text.cxx
@@ -14,6 +14,8 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Box.H>
 #include <FL/fl_draw.H>
 
@@ -79,4 +81,4 @@ public:
   }
 };
 
-UnitTest textExtents("rendering text", TextExtentsTest::create);
+UnitTest textExtents(kTestText, "Rendering text", TextExtentsTest::create);
diff --git test/unittest_viewport.cxx test/unittest_viewport.cxx
index 5202625..0ae98fa 100644
--- test/unittest_viewport.cxx
+++ test/unittest_viewport.cxx
@@ -14,6 +14,8 @@
 //     https://www.fltk.org/bugs.php
 //
 
+#include "unittests.h"
+
 #include <FL/Fl_Box.H>
 #include <FL/fl_draw.H>
 
@@ -46,4 +48,4 @@ public:
   }
 };
 
-UnitTest viewport("viewport test", ViewportTest::create);
+UnitTest viewport(kTestViewport, "Viewport Test", ViewportTest::create);
diff --git test/unittests.cxx test/unittests.cxx
index b81a007..4726124 100644
--- test/unittests.cxx
+++ test/unittests.cxx
@@ -21,6 +21,8 @@
 // v1.0 - Submit for svn
 // v1.1 - Matthias seperated all tests into multiple source files for hopefully easier handling
 
+#include "unittests.h"
+
 #include <FL/Fl.H>
 #include <FL/Fl_Double_Window.H>
 #include <FL/Fl_Hold_Browser.H>
@@ -31,129 +33,90 @@
 #include <FL/fl_string_functions.h>   // fl_strdup()
 #include <stdlib.h>         // malloc, free
 
-// WINDOW/WIDGET SIZES
-#define MAINWIN_W       700                             // main window w()
-#define MAINWIN_H       400                             // main window h()
-#define BROWSER_X       10                              // browser x()
-#define BROWSER_Y       25                              // browser y()
-#define BROWSER_W       150                             // browser w()
-#define BROWSER_H       MAINWIN_H-35                    // browser h()
-#define TESTAREA_X      (BROWSER_W + 20)                // test area x()
-#define TESTAREA_Y      25                              // test area y()
-#define TESTAREA_W      (MAINWIN_W - BROWSER_W - 30)    // test area w()
-#define TESTAREA_H      BROWSER_H                       // test area h()
+class MainWindow *mainwin = 0;
+class Fl_Hold_Browser *browser = 0;
+
+UnitTest::UnitTest(int index, const char *label, Fl_Widget* (*create)()) :
+  fWidget(0L)
+{
+  fLabel = fl_strdup(label);
+  fCreate = create;
+  add(index, this);
+}
 
-typedef void (*UnitTestCallback)(const char*,Fl_Group*);
+UnitTest::~UnitTest() {
+  delete fWidget;
+  free(fLabel);
+}
 
-class MainWindow *mainwin = 0;
-Fl_Hold_Browser *browser = 0;
-
-// This class helps to automagically register a new test with the unittest app.
-// Please see the examples on how this is used.
-class UnitTest {
-public:
-  UnitTest(const char *label, Fl_Widget* (*create)()) :
-    fWidget(0L)
-  {
-    fLabel = fl_strdup(label);
-    fCreate = create;
-    add(this);
-  }
-  ~UnitTest() {
-    delete fWidget;
-    free(fLabel);
-  }
-  const char *label() {
-    return fLabel;
-  }
-  void create() {
-    fWidget = fCreate();
-    if (fWidget) fWidget->hide();
-  }
-  void show() {
-    if (fWidget) fWidget->show();
-  }
-  void hide() {
-    if (fWidget) fWidget->hide();
-  }
-  static int numTest() { return nTest; }
-  static UnitTest *test(int i) { return fTest[i]; }
-private:
-  char *fLabel;
-  Fl_Widget *(*fCreate)();
-  Fl_Widget *fWidget;
-
-  static void add(UnitTest *t) {
-    fTest[nTest] = t;
-    nTest++;
-  }
-  static int nTest;
-  static UnitTest *fTest[];
-};
+const char *UnitTest::label() {
+  return fLabel;
+}
+
+void UnitTest::create() {
+  fWidget = fCreate();
+  if (fWidget) fWidget->hide();
+}
+
+void UnitTest::show() {
+  if (fWidget) fWidget->show();
+}
+
+void UnitTest::hide() {
+  if (fWidget) fWidget->hide();
+}
+
+void UnitTest::add(int index, UnitTest *t) {
+  fTest[index] = t;
+  if (index>=nTest)
+    nTest = index+1;
+}
 
 int UnitTest::nTest = 0;
-UnitTest *UnitTest::fTest[200];
-
-
-// The main window needs an additional drawing feature in order to support
-// the viewport alignment test.
-class MainWindow : public Fl_Double_Window {
-public:
-  MainWindow(int w, int h, const char *l=0L) :
-    Fl_Double_Window(w, h, l),
-    fTestAlignment(0)
-  { }
-  // this code is used by the viewport alignment test
-  void drawAlignmentIndicators() {
-    const int sze = 16;
-    // top left corner
-    fl_color(FL_GREEN); fl_yxline(0, sze, 0, sze);
-    fl_color(FL_RED);   fl_yxline(-1, sze, -1, sze);
-    fl_color(FL_WHITE); fl_rectf(3, 3, sze-2, sze-2);
-    fl_color(FL_BLACK); fl_rect(3, 3, sze-2, sze-2);
-    // bottom left corner
-    fl_color(FL_GREEN); fl_yxline(0, h()-sze-1, h()-1, sze);
-    fl_color(FL_RED);   fl_yxline(-1, h()-sze-1, h(), sze);
-    fl_color(FL_WHITE); fl_rectf(3, h()-sze-1, sze-2, sze-2);
-    fl_color(FL_BLACK); fl_rect(3, h()-sze-1, sze-2, sze-2);
-    // bottom right corner
-    fl_color(FL_GREEN); fl_yxline(w()-1, h()-sze-1, h()-1, w()-sze-1);
-    fl_color(FL_RED);   fl_yxline(w(), h()-sze-1, h(), w()-sze-1);
-    fl_color(FL_WHITE); fl_rectf(w()-sze-1, h()-sze-1, sze-2, sze-2);
-    fl_color(FL_BLACK); fl_rect(w()-sze-1, h()-sze-1, sze-2, sze-2);
-    // top right corner
-    fl_color(FL_GREEN); fl_yxline(w()-1, sze, 0, w()-sze-1);
-    fl_color(FL_RED);   fl_yxline(w(), sze, -1, w()-sze-1);
-    fl_color(FL_WHITE); fl_rectf(w()-sze-1, 3, sze-2, sze-2);
-    fl_color(FL_BLACK); fl_rect(w()-sze-1, 3, sze-2, sze-2);
-  }
-  void draw() {
-    Fl_Double_Window::draw();
-    if (fTestAlignment) {
-      drawAlignmentIndicators();
-    }
-  }
-  void testAlignment(int v) {
-    fTestAlignment = v;
-    redraw();
+UnitTest *UnitTest::fTest[200] = { 0 };
+
+MainWindow::MainWindow(int w, int h, const char *l) :
+Fl_Double_Window(w, h, l),
+fTestAlignment(0)
+{ }
+
+void MainWindow::drawAlignmentIndicators() {
+  const int sze = 16;
+  // top left corner
+  fl_color(FL_GREEN); fl_yxline(0, sze, 0, sze);
+  fl_color(FL_RED);   fl_yxline(-1, sze, -1, sze);
+  fl_color(FL_WHITE); fl_rectf(3, 3, sze-2, sze-2);
+  fl_color(FL_BLACK); fl_rect(3, 3, sze-2, sze-2);
+  // bottom left corner
+  fl_color(FL_GREEN); fl_yxline(0, h()-sze-1, h()-1, sze);
+  fl_color(FL_RED);   fl_yxline(-1, h()-sze-1, h(), sze);
+  fl_color(FL_WHITE); fl_rectf(3, h()-sze-1, sze-2, sze-2);
+  fl_color(FL_BLACK); fl_rect(3, h()-sze-1, sze-2, sze-2);
+  // bottom right corner
+  fl_color(FL_GREEN); fl_yxline(w()-1, h()-sze-1, h()-1, w()-sze-1);
+  fl_color(FL_RED);   fl_yxline(w(), h()-sze-1, h(), w()-sze-1);
+  fl_color(FL_WHITE); fl_rectf(w()-sze-1, h()-sze-1, sze-2, sze-2);
+  fl_color(FL_BLACK); fl_rect(w()-sze-1, h()-sze-1, sze-2, sze-2);
+  // top right corner
+  fl_color(FL_GREEN); fl_yxline(w()-1, sze, 0, w()-sze-1);
+  fl_color(FL_RED);   fl_yxline(w(), sze, -1, w()-sze-1);
+  fl_color(FL_WHITE); fl_rectf(w()-sze-1, 3, sze-2, sze-2);
+  fl_color(FL_BLACK); fl_rect(w()-sze-1, 3, sze-2, sze-2);
+}
+
+void MainWindow::draw() {
+  Fl_Double_Window::draw();
+  if (fTestAlignment) {
+    drawAlignmentIndicators();
   }
-  int fTestAlignment;
-};
+}
 
-//------- include the various unit tests as inline code -------
+void MainWindow::testAlignment(int v) {
+  fTestAlignment = v;
+  redraw();
+}
 
-#include "unittest_about.cxx"
-#include "unittest_points.cxx"
-#include "unittest_lines.cxx"
-#include "unittest_rects.cxx"
-#include "unittest_circles.cxx"
-#include "unittest_text.cxx"
-#include "unittest_symbol.cxx"
-#include "unittest_images.cxx"
-#include "unittest_viewport.cxx"
-#include "unittest_scrollbarsize.cxx"
-#include "unittest_schemes.cxx"
-#include "unittest_simple_terminal.cxx"
+//------- include the various unit tests as inline code -------
 
 // callback whenever the browser value changes
 void Browser_CB(Fl_Widget*, void*) {
@@ -175,6 +138,7 @@ int main(int argc, char **argv) {
   Fl::get_system_colors();
   Fl::scheme(Fl::scheme()); // init scheme before instantiating tests
   Fl::visual(FL_RGB);
+  Fl::use_high_res_GL(1);
   mainwin = new MainWindow(MAINWIN_W, MAINWIN_H, "FLTK Unit Tests");
   browser = new Fl_Hold_Browser(BROWSER_X, BROWSER_Y, BROWSER_W, BROWSER_H, "Unit Tests");
   browser->align(FL_ALIGN_TOP|FL_ALIGN_LEFT);
@@ -184,16 +148,18 @@ int main(int argc, char **argv) {
   int i, n = UnitTest::numTest();
   for (i=0; i<n; i++) {
     UnitTest *t = UnitTest::test(i);
-    mainwin->begin();
-    t->create();
-    mainwin->end();
-    browser->add(t->label(), (void*)t);
+    if (t) {
+      mainwin->begin();
+      t->create();
+      mainwin->end();
+      browser->add(t->label(), (void*)t);
+    }
   }
 
   mainwin->resizable(mainwin);
   mainwin->show(argc,argv);
   // Select first test in browser, and show that test.
-  browser->select(1);
+  browser->select(kTestAbout+1);
   Browser_CB(browser,0);
   return(Fl::run());
 }
diff --git test/unittests.h test/unittests.h
new file mode 100644
index 0000000..3b9cddd
--- /dev/null
+++ test/unittests.h
@@ -0,0 +1,87 @@
+//
+// Unit tests for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2022 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+//     https://www.fltk.org/bugs.php
+//
+
+#ifndef UNITTESTS_H
+#define UNITTESTS_H 1
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+
+// WINDOW/WIDGET SIZES
+#define MAINWIN_W       700                             // main window w()
+#define MAINWIN_H       400                             // main window h()
+#define BROWSER_X       10                              // browser x()
+#define BROWSER_Y       25                              // browser y()
+#define BROWSER_W       150                             // browser w()
+#define BROWSER_H       MAINWIN_H-35                    // browser h()
+#define TESTAREA_X      (BROWSER_W + 20)                // test area x()
+#define TESTAREA_Y      25                              // test area y()
+#define TESTAREA_W      (MAINWIN_W - BROWSER_W - 30)    // test area w()
+#define TESTAREA_H      BROWSER_H                       // test area h()
+
+typedef void (*UnitTestCallback)(const char*, class Fl_Group*);
+
+extern class MainWindow *mainwin;
+extern class Fl_Hold_Browser *browser;
+
+enum {
+  kTestAbout = 0,
+  kTestPoints,
+  kTestFastShapes,
+  kTestCircles,
+//  kTestComplexShapes,
+  kTestText,
+  kTestSymbol,
+  kTestImages,
+  kTestViewport,
+  kTestScrollbarsize,
+  kTestSchemes,
+  kTestSimpleTerminal
+};
+
+// This class helps to automatically register a new test with the unittest app.
+// Please see the examples on how this is used.
+class UnitTest {
+public:
+  UnitTest(int index, const char *label, Fl_Widget* (*create)());
+  ~UnitTest();
+  const char *label();
+  void create();
+  void show();
+  void hide();
+  static int numTest() { return nTest; }
+  static UnitTest *test(int i) { return fTest[i]; }
+private:
+  char *fLabel;
+  Fl_Widget *(*fCreate)();
+  Fl_Widget *fWidget;
+  static void add(int index, UnitTest *t);
+  static int nTest;
+  static UnitTest *fTest[];
+};
+
+// The main window needs an additional drawing feature in order to support
+// the viewport alignment test.
+class MainWindow : public Fl_Double_Window {
+public:
+  MainWindow(int w, int h, const char *l=0L);
+  void drawAlignmentIndicators();
+  void draw();
+  void testAlignment(int v);
+  int fTestAlignment;
+};
+
+#endif
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.