summaryrefslogtreecommitdiff
path: root/src/gl_draw.cxx
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2018-02-07 15:34:44 +0000
committerManolo Gouy <Manolo>2018-02-07 15:34:44 +0000
commitdcc82d8926e447e422f200d01e1aa990233bc16a (patch)
treebc0d120f1381e0e8c0ef5c66262289e93d3b9a08 /src/gl_draw.cxx
parent90630409cbe8740d2c8b66823757a4ea5441aa21 (diff)
STR#3450: Draw text with OpenGL using textures on all platforms.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12650 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/gl_draw.cxx')
-rw-r--r--src/gl_draw.cxx797
1 files changed, 482 insertions, 315 deletions
diff --git a/src/gl_draw.cxx b/src/gl_draw.cxx
index 6ce4c8d57..ebaa1d2e5 100644
--- a/src/gl_draw.cxx
+++ b/src/gl_draw.cxx
@@ -1,7 +1,7 @@
//
// "$Id$"
//
-// OpenGL drawing support routines for the Fast Light Tool Kit (FLTK).
+// OpenGL text drawing support routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2018 by Bill Spitzak and others.
//
@@ -19,12 +19,23 @@
// Functions from <FL/gl.h>
// See also Fl_Gl_Window and gl_start.cxx
+/* Note about implementing GL text support for a new platform
+
+ 1) if the GL_EXT_texture_rectangle (a.k.a. GL_ARB_texture_rectangle) GL extension
+ is available, no platform-specific code is needed, besides support for fl_draw() and Fl_Image_Surface for the platform.
+
+ 2) if the GL_EXT_texture_rectangle GL extension is not available,
+ a rudimentary support through GLUT is obtained without any platform-specific code.
+
+ 3) A more elaborate support can be obtained implementing
+ get_list(), gl_bitmap_font() and draw_string_legacy() for the platform's Fl_XXX_Gl_Window_Driver.
+ */
+
#include "config_lib.h"
#if defined(FL_PORTING)
# pragma message "FL_PORTING: implement OpenGL text rendering here"
-#endif
+#endif // defined(FL_PORTING)
-#include "flstring.h"
#if HAVE_GL || defined(FL_DOXYGEN)
#include <FL/Fl.H>
@@ -32,25 +43,13 @@
#include <FL/gl_draw.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Gl_Window_Driver.H>
+#include <FL/Fl_Image_Surface.H>
+#include <FL/glu.h> // for gluUnProject()
+#include <FL/glut.H> // for glutStrokeString() and glutStrokeLength()
-#if defined(FL_CFG_GFX_QUARTZ)
-#include "drivers/Quartz/Fl_Font.H"
-# define GENLISTSIZE 0
-
-#elif defined(FL_CFG_GFX_GDI)
-#include "drivers/GDI/Fl_Font.H"
-#define GENLISTSIZE 0x10000
-
-#elif defined(FL_CFG_GFX_XLIB)
-#include "drivers/Xlib/Fl_Font.H"
-#if USE_XFT
-# define GENLISTSIZE 256
-#else
-# define GENLISTSIZE 0x10000
-#endif // USE_XFT
-
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+# define GL_TEXTURE_RECTANGLE_ARB 0x84F5
#endif
-#include <FL/fl_utf8.h>
/** Returns the current font's height */
@@ -65,43 +64,55 @@ double gl_width(const char* s, int n) {return fl_width(s,n);}
double gl_width(uchar c) {return fl_width(c);}
static Fl_Font_Descriptor *gl_fontsize;
+static int has_texture_rectangle = 0; // true means GL_EXT_texture_rectangle is available
+extern float gl_start_scale; // in gl_start.cxx
/**
- Sets the current OpenGL font to the same font as calling fl_font()
+ Sets the current OpenGL font to the same font as calling fl_font().
+ \see Fl::draw_GL_text_with_textures(int val)
*/
void gl_font(int fontid, int size) {
+ static bool once = true;
+ if (once) {
+ once = false;
+ if (Fl::draw_GL_text_with_textures()) {
+ // For the font texture pile to work, we need a texture rectangle extension, so check for
+ // one here. First we check for GL_EXT_texture_rectangle and if that fails we try
+ // for GL_ARB_texture_rectangle instead. If that also fails, we fall back to the
+ // legacy methods used by fltk-1.3 and earlier.
+ has_texture_rectangle = (strstr((const char*)glGetString(GL_EXTENSIONS), "GL_EXT_texture_rectangle") != NULL);
+ if (!has_texture_rectangle) has_texture_rectangle =
+ (strstr((const char*)glGetString(GL_EXTENSIONS), "GL_ARB_texture_rectangle") != NULL);
+ Fl::draw_GL_text_with_textures(has_texture_rectangle);
+ }
+ }
fl_font(fontid, size);
Fl_Font_Descriptor *fl_fontsize = fl_graphics_driver->font_descriptor();
- Fl_Gl_Window_Driver::global()->gl_bitmap_font(fl_fontsize);
+ if (!has_texture_rectangle) Fl_Gl_Window_Driver::global()->gl_bitmap_font(fl_fontsize);
gl_fontsize = fl_fontsize;
}
-#if defined(FL_CFG_GFX_QUARTZ) || defined(FL_CFG_GFX_GDI) || defined(FL_CFG_GFX_XLIB)
-
void gl_remove_displaylist_fonts()
{
-# if HAVE_GL
// clear variables used mostly in fl_font
fl_graphics_driver->font(0, 0);
for (int j = 0 ; j < FL_FREE_FONT ; ++j)
{
Fl_Font_Descriptor* past = 0;
- Fl_Fontdesc* s = fl_fonts + j ;
- Fl_Font_Descriptor* f = s->first;
+ Fl_Font_Descriptor** s_first = Fl_Gl_Window_Driver::global()->fontnum_to_fontdescriptor(j);
+ Fl_Font_Descriptor* f = *s_first;
while (f != 0) {
if(f->listbase) {
- if(f == s->first) {
- s->first = f->next;
+ if(f == *s_first) {
+ *s_first = f->next;
}
else {
past->next = f->next;
}
-
// It would be nice if this next line was in a destructor somewhere
- glDeleteLists(f->listbase, GENLISTSIZE);
-
+ glDeleteLists(f->listbase, Fl_Gl_Window_Driver::global()->genlistsize());
Fl_Font_Descriptor* tmp = f;
f = f->next;
delete tmp;
@@ -112,44 +123,22 @@ void gl_remove_displaylist_fonts()
}
}
}
-#endif // HAVE_GL
}
-#endif
/**
- Draws an array of n characters of the string in the current font
- at the current position.
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ Draws an array of n characters of the string in the current font at the current position.
+ \see gl_texture_pile_height(int)
*/
void gl_draw(const char* str, int n) {
- Fl_Gl_Window_Driver::global()->draw_string(str, n);
+ if (has_texture_rectangle) Fl_Gl_Window_Driver::draw_string_with_texture(str, n);
+ else Fl_Gl_Window_Driver::global()->draw_string_legacy(str, n);
}
-void Fl_Gl_Window_Driver::draw_string(const char* str, int n) {
- static unsigned short *buf = NULL;
- static int l = 0;
- int wn = fl_utf8toUtf16(str, n, (unsigned short*)buf, l);
- if(wn >= l) {
- buf = (unsigned short*) realloc(buf, sizeof(unsigned short) * (wn + 1));
- l = wn + 1;
- wn = fl_utf8toUtf16(str, n, (unsigned short*)buf, l);
- }
- n = wn;
-
- int i;
- for (i = 0; i < n; i++) {
- unsigned int r;
- r = (str[i] & 0xFC00) >> 10;
- //if (!gl_fontsize->glok[r]) get_list(r);
- this->get_list(gl_fontsize, r);
- }
- glCallLists(n, GL_UNSIGNED_SHORT, buf);
-}
/**
- Draws n characters of the string in the current font at the given position
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ Draws n characters of the string in the current font at the given position
+ \see gl_texture_pile_height(int)
*/
void gl_draw(const char* str, int n, int x, int y) {
glRasterPos2i(x, y);
@@ -157,8 +146,8 @@ void gl_draw(const char* str, int n, int x, int y) {
}
/**
- Draws n characters of the string in the current font at the given position
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ Draws n characters of the string in the current font at the given position
+ \see gl_texture_pile_height(int)
*/
void gl_draw(const char* str, int n, float x, float y) {
glRasterPos2f(x, y);
@@ -167,23 +156,23 @@ void gl_draw(const char* str, int n, float x, float y) {
/**
Draws a nul-terminated string in the current font at the current position
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ \see gl_texture_pile_height(int)
*/
void gl_draw(const char* str) {
gl_draw(str, strlen(str));
}
/**
- Draws a nul-terminated string in the current font at the given position
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ Draws a nul-terminated string in the current font at the given position
+ \see gl_texture_pile_height(int)
*/
void gl_draw(const char* str, int x, int y) {
gl_draw(str, strlen(str), x, y);
}
/**
- Draws a nul-terminated string in the current font at the given position
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ Draws a nul-terminated string in the current font at the given position
+ \see gl_texture_pile_height(int)
*/
void gl_draw(const char* str, float x, float y) {
gl_draw(str, strlen(str), x, y);
@@ -229,6 +218,13 @@ void gl_rect(int x, int y, int w, int h) {
glEnd();
}
+void gl_draw_image(const uchar* b, int x, int y, int w, int h, int d, int ld) {
+ if (!ld) ld = w*d;
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, ld/d);
+ glRasterPos2i(x,y);
+ glDrawPixels(w,h,d<4?GL_RGB:GL_RGBA,GL_UNSIGNED_BYTE,(const ulong*)b);
+}
+
/**
Sets the curent OpenGL color to an FLTK color.
@@ -244,155 +240,29 @@ void gl_color(Fl_Color i) {
}
-#if defined(FL_CFG_GFX_XLIB)
-#include <FL/platform.H>
-#include <GL/glx.h>
+#if ! defined(FL_DOXYGEN) // do not want too much of the gl_texture_fifo internals in the documentation
+/* Implement the gl_texture_fifo mechanism:
+ Strings to be drawn are memorized in a fifo pile (which max size can
+ be increased calling gl_texture_pile_height(int)).
+ Each pile element contains the string, the font, the GUI scale, and
+ an image of the string in the form of a GL texture.
+ Strings are drawn in 2 steps:
+ 1) compute the texture for that string if it was not computed before;
+ 2) draw the texture using the current GL color.
+*/
-void Fl_X11_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {
- if (!fl_fontsize->listbase) {
-#if !USE_XFT
- fl_fontsize->listbase = glGenLists(GENLISTSIZE);
-#else // Fltk-1.1.8 style GL font selection
- // FIXME: warning Ideally, for XFT, we really need a glXUseXftFont implementation here...
- // FIXME: warning GL font selection is basically wrong here
- /* OksiD had a fairly sophisticated scheme for storing multiple X fonts in a XUtf8FontStruct,
- * then sorting through them at draw time (for normal X rendering) to find which one can
- * render the current glyph... But for now, just use the first font in the list for GL...
- */
- XFontStruct *font = fl_xfont.value();
- int base = font->min_char_or_byte2;
- int count = font->max_char_or_byte2-base+1;
- fl_fontsize->listbase = glGenLists(GENLISTSIZE);
- glXUseXFont(font->fid, base, count, fl_fontsize->listbase+base);
-#endif // !USE_XFT
- }
- glListBase(fl_fontsize->listbase);
-}
-
-
-void Fl_X11_Gl_Window_Driver::get_list(Fl_Font_Descriptor *gl_fd, int r) {
- if (gl_fd->glok[r]) return;
- gl_fd->glok[r] = 1;
-# if USE_XFT
- // FIXME
-# else
- unsigned int ii = r * 0x400;
- for (int i = 0; i < 0x400; i++) {
- XFontStruct *font = NULL;
- unsigned short id;
- fl_XGetUtf8FontAndGlyph(gl_fd->font, ii, &font, &id);
- if (font) glXUseXFont(font->fid, id, 1, gl_fd->listbase+ii);
- ii++;
- }
-# endif
-}
-
-#if HAVE_GL_OVERLAY
-extern uchar fl_overlay;
-int Fl_X11_Gl_Window_Driver::overlay_color(Fl_Color i) {
- if (fl_overlay) {glIndexi(int(fl_xpixel(i))); return 1;}
- return 0;
-}
-#endif // HAVE_GL_OVERLAY
-#endif // FL_CFG_GFX_XLIB
-
-
-#if defined(FL_CFG_GFX_GDI)
-
-void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {
- if (!fl_fontsize->listbase) {
- fl_fontsize->listbase = glGenLists(GENLISTSIZE);
- /* old, unused WIN32 code
- int base = fl_fontsize->metr.tmFirstChar;
- int count = fl_fontsize->metr.tmLastChar-base+1;
- HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), fl_fontsize->fid);
- fl_fontsize->listbase = glGenLists(256);
- wglUseFontBitmaps((HDC)fl_graphics_driver->gc(), base, count, fl_fontsize->listbase+base);
- SelectObject((HDC)fl_graphics_driver->gc(), oldFid);
- */
- }
- glListBase(fl_fontsize->listbase);
-}
-
-
-void Fl_WinAPI_Gl_Window_Driver::get_list(Fl_Font_Descriptor *gl_fd, int r) {
- if (gl_fd->glok[r]) return;
- gl_fd->glok[r] = 1;
- unsigned int ii = r * 0x400;
- HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), gl_fd->fid);
- wglUseFontBitmapsW((HDC)fl_graphics_driver->gc(), ii, ii + 0x03ff, gl_fd->listbase+ii);
- SelectObject((HDC)fl_graphics_driver->gc(), oldFid);
-}
-
-#if HAVE_GL_OVERLAY
-extern uchar fl_overlay;
-extern int fl_overlay_depth;
-int Fl_WinAPI_Gl_Window_Driver::overlay_color(Fl_Color i) {
- 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 1;
- }
- return 0;
-}
-#endif // HAVE_GL_OVERLAY
-#endif // FL_CFG_GFX_GDI
-
-
-void gl_draw_image(const uchar* b, int x, int y, int w, int h, int d, int ld) {
- if (!ld) ld = w*d;
- glPixelStorei(GL_UNPACK_ROW_LENGTH, ld/d);
- glRasterPos2i(x,y);
- glDrawPixels(w,h,d<4?GL_RGB:GL_RGBA,GL_UNSIGNED_BYTE,(const ulong*)b);
-}
-
-
-#if defined(FL_CFG_GFX_QUARTZ) || defined(FL_DOXYGEN)
-
-#if ! defined(FL_DOXYGEN)
-
-#include <FL/platform.H>
-#if !defined(kCGBitmapByteOrder32Host) // doc says available 10.4 but some 10.4 don't have it
-# define kCGBitmapByteOrder32Host 0
-#endif
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
-# include <OpenGL/glext.h>
-# define GL_TEXTURE_RECTANGLE_ARB GL_TEXTURE_RECTANGLE_EXT
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED
-
-/* Text drawing to an OpenGL scene under Mac OS X is implemented using textures, as recommended by Apple.
- This allows to use any font at any size, and any Unicode character.
- Some old Apple hardware doesn't implement the required GL_EXT_texture_rectangle extension.
- For these, glutStrokeString() is used to draw text. In that case, it's possible to vary text size,
- but not text font, and only ASCII characters can be drawn.
- */
-
-static float gl_scale = 1; // set to 2 for high resolution Fl_Gl_Window
-static int has_texture_rectangle = 0; // true means GL_EXT_texture_rectangle is available
-
-#include <FL/glu.h> // for gluUnProject() and gluCheckExtension()
-#include <FL/glut.H> // for glutStrokeString() and glutStrokeLength()
+static float gl_scale = 1; // scaling factor between FLTK and GL drawing units: GL = FLTK * gl_scale
// manages a fifo pile of pre-computed string textures
class gl_texture_fifo {
- friend class Fl_Cocoa_Gl_Window_Driver;
+ friend class Fl_Gl_Window_Driver;
private:
typedef struct { // information for a pre-computed texture
GLuint texName; // its name
char *utf8; //its text
Fl_Font_Descriptor *fdesc; // its font
- float ratio; // used without rectangle texture
- int scale; // 1 or 2 for low/high resolution
+ float scale; // scaling factor of the GUI
} data;
data *fifo; // array of pile elements
int size_; // pile height
@@ -421,10 +291,34 @@ gl_texture_fifo::~gl_texture_fifo()
for (int i = 0; i < size_; i++) {
if (fifo[i].utf8) free(fifo[i].utf8);
if (textures_generated) glDeleteTextures(1, &fifo[i].texName);
- }
+ }
free(fifo);
}
+// returns rank of pre-computed texture for a string if it exists
+int gl_texture_fifo::already_known(const char *str, int n)
+{
+ int rank;
+ for ( rank = 0; rank <= last; rank++) {
+ if ( (memcmp(str, fifo[rank].utf8, n) == 0) && (fifo[rank].utf8[n] == 0) &&
+ (fifo[rank].fdesc == gl_fontsize) && (fifo[rank].scale == gl_scale) ) {
+ return rank;
+ }
+ }
+ return -1; // means no texture exists yet for that string
+}
+
+static gl_texture_fifo *gl_fifo = NULL; // points to the texture pile class instance
+
+void gl_texture_reset()
+{
+ if (gl_fifo) gl_texture_pile_height(gl_texture_pile_height());
+}
+
+
+// Cross-platform implementation of the texture mechanism for text rendering
+// using textures with the alpha channel only.
+
// displays a pre-computed texture on the GL scene
void gl_texture_fifo::display_texture(int rank)
{
@@ -440,46 +334,39 @@ void gl_texture_fifo::display_texture(int rank)
float winw = gl_scale * Fl_Window::current()->w();
float winh = gl_scale * Fl_Window::current()->h();
// GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable
- glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
+ glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
glDisable (GL_DEPTH_TEST); // ensure text is not removed by depth buffer test.
glEnable (GL_BLEND); // for text fading
- glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING);
GLfloat pos[4];
glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
- float R = 2;
- if (!has_texture_rectangle) {
- R *= fifo[rank].ratio;
+ if (gl_start_scale != 1) { // using gl_start() / gl_finish()
+ pos[0] /= gl_start_scale;
+ pos[1] /= gl_start_scale;
}
+
+ float R = 2;
glScalef (R/winw, R/winh, 1.0f);
glTranslatef (-winw/R, -winh/R, 0.0f);
- GLint width;
- if (has_texture_rectangle) {
- glEnable (GL_TEXTURE_RECTANGLE_ARB);
- glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[rank].texName);
- GLint height;
- glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_WIDTH, &width);
- glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_HEIGHT, &height);
- CGRect bounds = CGRectMake (pos[0], pos[1] - gl_scale*fl_descent(), width, height);
- //write the texture on screen
- glBegin (GL_QUADS);
- glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates
- glVertex2f (bounds.origin.x, bounds.origin.y);
-
- glTexCoord2f (0.0f, height); // draw upper left in world coordinates
- glVertex2f (bounds.origin.x, bounds.origin.y + bounds.size.height);
-
- glTexCoord2f (width, height); // draw upper right in world coordinates
- glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
-
- glTexCoord2f (width, 0.0f); // draw lower right in world coordinates
- glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y);
- glEnd ();
- } else {
- glTranslatef(pos[0]*2/R, pos[1]*2/R, 0.0);
- glutStrokeString(GLUT_STROKE_ROMAN, (uchar*)fifo[rank].utf8);
- width = fl_width(fifo[rank].utf8);
- }
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[rank].texName);
+ GLint width, height;
+ glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_WIDTH, &width);
+ glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_HEIGHT, &height);
+ //write the texture on screen
+ glBegin (GL_QUADS);
+ float ox = pos[0];
+ float oy = pos[1] + height - gl_scale * fl_descent();
+ glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates
+ glVertex2f (ox, oy);
+ glTexCoord2f (0.0f, height); // draw upper left in world coordinates
+ glVertex2f (ox, oy - height);
+ glTexCoord2f (width, height); // draw upper right in world coordinates
+ glVertex2f (ox + width, oy - height);
+ glTexCoord2f (width, 0.0f); // draw lower right in world coordinates
+ glVertex2f (ox + width, oy);
+ glEnd ();
glPopAttrib();
// reset original matrices
@@ -498,14 +385,18 @@ void gl_texture_fifo::display_texture(int rank)
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
gluUnProject(pos[0], pos[1], pos[2], modelmat, projmat, viewport, &objX, &objY, &objZ);
+
+ if (gl_start_scale != 1) { // using gl_start() / gl_finish()
+ objX *= gl_start_scale;
+ objY *= gl_start_scale;
+ }
glRasterPos2d(objX, objY);
-}
+} // display_texture
+
// pre-computes a string texture
int gl_texture_fifo::compute_texture(const char* str, int n)
{
- Fl_Graphics_Driver *prev_driver = fl_graphics_driver;
- fl_graphics_driver = Fl_Display_Device::display_device()->driver();
current = (current + 1) % size_;
if (current > last) last = current;
if ( fifo[current].utf8 ) free(fifo[current].utf8);
@@ -515,114 +406,390 @@ int gl_texture_fifo::compute_texture(const char* str, int n)
fl_graphics_driver->font_descriptor(gl_fontsize);
int w, h;
w = fl_width(fifo[current].utf8, n) * gl_scale;
+ // Hack - make w be aligned
+ w = (w + 3) & 0xFFFFFFC;
h = fl_height() * gl_scale;
+
fifo[current].scale = gl_scale;
fifo[current].fdesc = gl_fontsize;
- if (has_texture_rectangle) {
- //write str to a bitmap just big enough
- CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
- void *base = NULL;
- if (fl_mac_os_version < 100600) base = calloc(4*w, h);
- void* save_gc = fl_graphics_driver->gc();
- CGContextRef gc = CGBitmapContextCreate(base, w, h, 8, w*4, lut,
- (CGBitmapInfo)(kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
- fl_graphics_driver->gc(gc);
- CGColorSpaceRelease(lut);
- GLfloat colors[4];
- glGetFloatv(GL_CURRENT_COLOR, colors);
- fl_color((uchar)(colors[0]*255), (uchar)(colors[1]*255), (uchar)(colors[2]*255));
- CGContextTranslateCTM(gc, 0, h - gl_scale*fl_descent());
- CGContextScaleCTM(gc, gl_scale, gl_scale);
- fl_draw(str, n, 0, 0);
- //put this bitmap in a texture
- glPushAttrib(GL_TEXTURE_BIT);
- glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[current].texName);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
- glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, w, h, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, CGBitmapContextGetData(gc));
- glPopAttrib();
- CGContextRelease(gc);
- fl_graphics_driver->gc(save_gc);
- if (base) free(base);
- } else {
- fifo[current].ratio = float(w)/glutStrokeLength(GLUT_STROKE_ROMAN, (uchar*)fifo[current].utf8);
- }
- fl_graphics_driver = prev_driver;
+ char *txt_buf = Fl_Gl_Window_Driver::global()->alpha_mask_for_string(str, n, w, h);
+
+ // put the bitmap in an alpha-component-only texture
+ glPushAttrib(GL_TEXTURE_BIT);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[current].texName);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
+ // GL_ALPHA8 is defined in GL/gl.h of X11 and of MinGW32 and of MinGW64 and of OpenGL.framework for MacOS
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA8, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, txt_buf);
+ /* For the record: texture construction if an alpha-only-texture is not possible
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, w, h, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, rgba_buf);
+ and also, replace GL_SRC_ALPHA by GL_ONE in glBlendFunc() call of display_texture()
+ */
+ delete[] txt_buf; // free the buffer now we have copied it into the Gl texture
+ glPopAttrib();
return current;
}
-// returns rank of pre-computed texture for a string if it exists
-int gl_texture_fifo::already_known(const char *str, int n)
+#endif // ! defined(FL_DOXYGEN)
+
+/**
+ Returns the current maximum height of the pile of pre-computed string textures.
+ The default value is 100
+ \see Fl::draw_GL_text_with_textures(int)
+ */
+int gl_texture_pile_height(void)
{
- int rank;
- for ( rank = 0; rank <= last; rank++) {
- if ( memcmp(str, fifo[rank].utf8, n) == 0 && fifo[rank].utf8[n] == 0 &&
- fifo[rank].fdesc == gl_fontsize && fifo[rank].scale == gl_scale) return rank;
- }
- return -1;
+ if (! gl_fifo) gl_fifo = new gl_texture_fifo();
+ return gl_fifo->size();
}
-static gl_texture_fifo *gl_fifo = NULL; // points to the texture pile class instance
+/**
+ Changes the maximum height of the pile of pre-computed string textures
-// draws a utf8 string using pre-computed texture if available
-void Fl_Cocoa_Gl_Window_Driver::draw_string(const char* str, int n)
+ Strings that are often re-displayed can be processed much faster if
+ this pile is set high enough to hold all of them.
+ \param max Maximum height of the texture pile
+ \see Fl::draw_GL_text_with_textures(int)
+*/
+void gl_texture_pile_height(int max)
+{
+ if (gl_fifo) delete gl_fifo;
+ gl_fifo = new gl_texture_fifo(max);
+}
+
+
+void Fl_Gl_Window_Driver::draw_string_legacy(const char* str, int n)
+{
+ draw_string_legacy_glut(str, n);
+}
+
+
+/** draws a utf8 string using an OpenGL texture */
+void Fl_Gl_Window_Driver::draw_string_with_texture(const char* str, int n)
{
Fl_Gl_Window *gwin = Fl_Window::current()->as_gl_window();
gl_scale = (gwin ? gwin->pixels_per_unit() : 1);
-
- //fprintf(stderr,"gl_scale=%d\n",gl_scale);
- if (! gl_fifo) gl_fifo = new gl_texture_fifo();
+ if (!gl_fifo) gl_fifo = new gl_texture_fifo();
if (!gl_fifo->textures_generated) {
- has_texture_rectangle = gluCheckExtension((GLubyte*)"GL_EXT_texture_rectangle", glGetString(GL_EXTENSIONS));
if (has_texture_rectangle) for (int i = 0; i < gl_fifo->size_; i++) glGenTextures(1, &(gl_fifo->fifo[i].texName));
gl_fifo->textures_generated = 1;
}
- int rank = gl_fifo->already_known(str, n);
- if (rank == -1) {
- rank = gl_fifo->compute_texture(str, n);
+ int index = gl_fifo->already_known(str, n);
+ if (index == -1) {
+ index = gl_fifo->compute_texture(str, n);
}
- gl_fifo->display_texture(rank);
+ gl_fifo->display_texture(index);
}
-void gl_texture_reset()
+
+char *Fl_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h)
{
- if (gl_fifo) gl_texture_pile_height(gl_texture_pile_height());
+ // write str to a bitmap that is just big enough
+ // create an Fl_Image_Surface object
+ Fl_Image_Surface *image_surface = new Fl_Image_Surface(w, h);
+ Fl_Font fnt = fl_font(); // get the current font
+ // direct all further graphics requests to the image
+ Fl_Surface_Device::push_current(image_surface);
+ // fill the background with black, which we will interpret as transparent
+ fl_color(0,0,0);
+ fl_rectf(0, 0, w, h);
+ // set up the text colour as white, which we will interpret as opaque
+ fl_color(255,255,255);
+ // Fix the font scaling
+ fl_font (fnt, gl_fontsize->size); // resize "fltk" font to current GL view scaling
+ int desc = fl_descent();
+ // Render the text to the buffer
+ fl_draw(str, n, 0, h - desc);
+ // get the resulting image
+ Fl_RGB_Image* image = image_surface->image();
+ // direct graphics requests back to previous state
+ Fl_Surface_Device::pop_current();
+ delete image_surface;
+ // This gives us an RGB rendering of the text. We build an alpha channel from that.
+ char *txt_buf = new char [w * h];
+ for (int idx = 0; idx < w * h; ++idx)
+ { // Fake up the alpha component using the green component's value
+ txt_buf[idx] = image->array[idx * 3 + 1];
+ }
+ delete image;
+ return txt_buf;
}
-#endif //! defined(FL_DOXYGEN)
-/** \addtogroup group_macosx
- @{ */
+// platform-independent, no-texture GL text drawing procedure
+// when Fl_XXX_Gl_Window_Driver::get_list() and gl_bitmap_font() are implemented
+void Fl_Gl_Window_Driver::draw_string_legacy_get_list(const char* str, int n) {
+ static unsigned short *buf = NULL;
+ static unsigned l = 0;
+ unsigned wn = fl_utf8toUtf16(str, n, buf, l);
+ if (wn >= l) {
+ buf = (unsigned short*) realloc(buf, sizeof(unsigned short) * (wn + 1));
+ l = wn + 1;
+ wn = fl_utf8toUtf16(str, n, buf, l);
+ }
+ int size = 0;
+ if (gl_start_scale != 1) { // using gl_start() / gl_finish()
+ size = fl_graphics_driver->font_descriptor()->size;
+ gl_font(fl_font(), size * gl_start_scale);
+ }
+ for (unsigned i = 0; i < wn; i++) {
+ unsigned int r;
+ r = (buf[i] & 0xFC00) >> 10;
+ get_list(gl_fontsize, r);
+ }
+ glCallLists(wn, GL_UNSIGNED_SHORT, buf);
+ if (gl_start_scale != 1) { // using gl_start() / gl_finish()
+ gl_font(fl_font(), size);
+ }
+}
-/**
- \brief Returns the current height of the pile of pre-computed string textures
- *
- The default value is 100
+/* Platform-independent, no-texture, GL text drawing procedure when there's no OS support whatsoever:
+ glutStrokeString() is used to draw text. It's possible to vary text size, but not text font,
+ and only ASCII characters can be drawn.
*/
-int gl_texture_pile_height(void)
+void Fl_Gl_Window_Driver::draw_string_legacy_glut(const char* str, int n)
{
- if (! gl_fifo) gl_fifo = new gl_texture_fifo();
- return gl_fifo->size();
+ uchar *str_nul = new uchar[n + 1];
+ int m = 0;
+ for (int i = 0; i < n; i++) {
+ if ((uchar)str[i] < 128) str_nul[m++] = str[i];
+ }
+ str_nul[m] = 0;
+ n = m;
+ Fl_Surface_Device::push_current(Fl_Display_Device::display_device());
+ fl_graphics_driver->font_descriptor(gl_fontsize);
+ Fl_Gl_Window *gwin = Fl_Window::current()->as_gl_window();
+ gl_scale = (gwin ? gwin->pixels_per_unit() : 1);
+ float ratio = fl_width((char*)str_nul, n) * gl_scale/glutStrokeLength(GLUT_STROKE_ROMAN, str_nul);
+ Fl_Surface_Device::pop_current();
+
+ //setup matrices
+ GLint matrixMode;
+ glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity ();
+ float winw = gl_scale * Fl_Window::current()->w();
+ float winh = gl_scale * Fl_Window::current()->h();
+
+ GLfloat pos[4];
+ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
+ if (gl_start_scale != 1) { // using gl_start() / gl_finish()
+ pos[0] /= gl_start_scale;
+ pos[1] /= gl_start_scale;
+ }
+ float R = 2 * ratio;
+ glScalef (R/winw, R/winh, 1.0f);
+ glTranslatef (-winw/R, -winh/R, 0.0f);
+ glTranslatef(pos[0]*2/R, pos[1]*2/R, 0.0);
+ glutStrokeString(GLUT_STROKE_ROMAN, str_nul);
+ float width = fl_width((char*)str_nul);
+ delete[] str_nul;
+ glPopAttrib();
+ // reset original matrices
+ glPopMatrix(); // GL_MODELVIEW
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode (matrixMode);
+ //set the raster position to end of string
+ pos[0] += width;
+ GLdouble modelmat[16];
+ glGetDoublev (GL_MODELVIEW_MATRIX, modelmat);
+ GLdouble projmat[16];
+ glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+ GLdouble objX, objY, objZ;
+ GLint viewport[4];
+ glGetIntegerv (GL_VIEWPORT, viewport);
+ gluUnProject(pos[0], pos[1], pos[2], modelmat, projmat, viewport, &objX, &objY, &objZ);
+ if (gl_start_scale != 1) { // using gl_start() / gl_finish()
+ objX *= gl_start_scale;
+ objY *= gl_start_scale;
+ }
+ glRasterPos2d(objX, objY);
}
-/**
- \brief Changes the height of the pile of pre-computed string textures
- *
- Strings that are often re-displayed can be processed much faster if
- this pile is set high enough to hold all of them.
- \param max Height of the texture pile
+
+#if defined(FL_CFG_GFX_XLIB)
+# include "drivers/Xlib/Fl_Font.H"
+# include <FL/platform.H>
+# include <GL/glx.h>
+
+void Fl_X11_Gl_Window_Driver::draw_string_legacy(const char* str, int n) {
+ draw_string_legacy_get_list(str, n);
+}
+
+int Fl_X11_Gl_Window_Driver::genlistsize() {
+#if USE_XFT
+ return 256;
+#else
+ return 0x10000;
+#endif
+}
+
+void Fl_X11_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {
+ /* This method should ONLY be triggered if our GL font texture pile mechanism
+ * is not working on this platform. This code might not reliably render glyphs
+ * from higher codepoints. */
+ if (!fl_fontsize->listbase) {
+#if USE_XFT
+ /* Ideally, for XFT, we need a glXUseXftFont implementation here... But we
+ * do not have such a thing. Instead, we try to find a legacy Xlib font that
+ * matches the current XFT font and use that.
+ * Ideally, we never come here - we hope the texture pile implementation
+ * will work correctly so that XFT can render the face directly without the
+ * need for this workaround. */
+ XFontStruct *font = fl_xfont.value();
+ int base = font->min_char_or_byte2;
+ int count = font->max_char_or_byte2 - base + 1;
+ fl_fontsize->listbase = glGenLists(genlistsize());
+ glXUseXFont(font->fid, base, count, fl_fontsize->listbase+base);
+#else
+ /* Not using XFT to render text - the legacy Xlib fonts can usually be rendered
+ * directly by using glXUseXFont mechanisms. */
+ fl_fontsize->listbase = glGenLists(genlistsize());
+#endif // !USE_XFT
+ }
+ glListBase(fl_fontsize->listbase);
+}
+
+
+void Fl_X11_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) {
+ Fl_Xlib_Font_Descriptor *gl_fd = (Fl_Xlib_Font_Descriptor*)fd;
+ if (gl_fd->glok[r]) return;
+ gl_fd->glok[r] = 1;
+# if USE_XFT
+ /* We hope not to come here: We hope that any system using XFT will also
+ * have sufficient GL capability to support our font texture pile mechansim,
+ * allowing XFT to render the face directly. */
+ // Face already set by gl_bitmap_font in this case.
+# else
+ unsigned int ii = r * 0x400;
+ for (int i = 0; i < 0x400; i++) {
+ XFontStruct *font = NULL;
+ unsigned short id;
+ fl_XGetUtf8FontAndGlyph(gl_fd->font, ii, &font, &id);
+ if (font) glXUseXFont(font->fid, id, 1, gl_fd->listbase+ii);
+ ii++;
+ }
+# endif
+}
+
+#if !USE_XFT
+Fl_Font_Descriptor** Fl_X11_Gl_Window_Driver::fontnum_to_fontdescriptor(int fnum) {
+ Fl_Xlib_Fontdesc *s = ((Fl_Xlib_Fontdesc*)fl_fonts) + fnum;
+ return &(s->first);
+}
+#endif
+
+#if HAVE_GL_OVERLAY
+extern uchar fl_overlay;
+int Fl_X11_Gl_Window_Driver::overlay_color(Fl_Color i) {
+ if (fl_overlay) {glIndexi(int(fl_xpixel(i))); return 1;}
+ return 0;
+}
+#endif // HAVE_GL_OVERLAY
+
+#endif // FL_CFG_GFX_XLIB
+
+
+#if defined(FL_CFG_GFX_GDI)
+# include "drivers/GDI/Fl_Font.H"
+
+void Fl_WinAPI_Gl_Window_Driver::draw_string_legacy(const char* str, int n) {
+ draw_string_legacy_get_list(str, n);
+}
+
+int Fl_WinAPI_Gl_Window_Driver::genlistsize() {
+ return 0x10000;
+}
+
+void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {
+ if (!fl_fontsize->listbase) {
+ fl_fontsize->listbase = glGenLists(genlistsize());
+ }
+ glListBase(fl_fontsize->listbase);
+}
+
+void Fl_WinAPI_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) {
+ Fl_GDI_Font_Descriptor* gl_fd = (Fl_GDI_Font_Descriptor*)fd;
+ if (gl_fd->glok[r]) return;
+ gl_fd->glok[r] = 1;
+ unsigned int ii = r * 0x400;
+ HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), gl_fd->fid);
+ wglUseFontBitmapsW((HDC)fl_graphics_driver->gc(), ii, 0x400, gl_fd->listbase+ii);
+ SelectObject((HDC)fl_graphics_driver->gc(), oldFid);
+}
+
+#if HAVE_GL_OVERLAY
+extern uchar fl_overlay;
+extern int fl_overlay_depth;
+int Fl_WinAPI_Gl_Window_Driver::overlay_color(Fl_Color i) {
+ 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 1;
+ }
+ return 0;
+}
+#endif // HAVE_GL_OVERLAY
+#endif // FL_CFG_GFX_GDI
+
+
+#if defined(FL_CFG_GFX_QUARTZ)
+# include "drivers/Quartz/Fl_Font.H"
+
+# if !defined(kCGBitmapByteOrder32Host) // doc says available 10.4 but some 10.4 don't have it
+# define kCGBitmapByteOrder32Host 0
+# endif // !defined(kCGBitmapByteOrder32Host)
+
+/* Some old Apple hardware doesn't implement the GL_EXT_texture_rectangle extension.
+ For it, draw_string_legacy_glut() is used to draw text.
*/
-void gl_texture_pile_height(int max)
+
+char *Fl_Cocoa_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h)
{
- if (gl_fifo) delete gl_fifo;
- gl_fifo = new gl_texture_fifo(max);
+ // write str to a bitmap just big enough
+ CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
+ void *base = NULL;
+ if (fl_mac_os_version < 100600) base = calloc(4*w, h);
+ void* save_gc = fl_graphics_driver->gc();
+ CGContextRef gc = CGBitmapContextCreate(base, w, h, 8, w*4, lut,
+ (CGBitmapInfo)(kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ CGColorSpaceRelease(lut);
+ fl_graphics_driver->gc(gc);
+ fl_color(FL_WHITE);
+ CGContextScaleCTM(gc, gl_scale, -gl_scale);
+ CGContextTranslateCTM(gc, 0, -fl_descent());
+ fl_draw(str, n, 0, 0);
+ // get the alpha channel only of the bitmap
+ char *txt_buf = new char[w*h], *r = txt_buf, *q;
+ q = (char*)CGBitmapContextGetData(gc);
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ *r++ = *(q+3);
+ q += 4;
+ }
+ }
+ CGContextRelease(gc);
+ fl_graphics_driver->gc(save_gc);
+ if (base) free(base);
+ return txt_buf;
}
-/** @} */
-
#endif // FL_CFG_GFX_QUARTZ
-#endif // HAVE_GL
+#endif // HAVE_GL || defined(FL_DOXYGEN)
//
// End of "$Id$".