@ -1,7 +1,7 @@
@@ -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 @@
@@ -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 @@
@@ -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);}
@@ -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()
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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()
@@ -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)
@@ -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)
@@ -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)
@@ -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$".