|
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 ] | |