From 241b2c746ec34a11e05a8036f216f13131abb025 Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Tue, 13 Apr 2010 14:26:12 +0000 Subject: [PATCH] gl_draw.cxx (Mac-specific): implemented a fifo pile of pre-computed textures for faster GL text rendering. Also added new function gl_texture_pile_height(int) that sets the height of this pile. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7491 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- FL/gl.h | 4 + src/gl_draw.cxx | 243 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 184 insertions(+), 63 deletions(-) diff --git a/FL/gl.h b/FL/gl.h index d1d76a239..1f60f63fa 100644 --- a/FL/gl.h +++ b/FL/gl.h @@ -98,6 +98,10 @@ FL_EXPORT void gl_draw(const char*, int n, int x, int y); FL_EXPORT void gl_draw(const char*, int n, float x, float y); FL_EXPORT void gl_draw(const char*, int x, int y, int w, int h, Fl_Align); FL_EXPORT void gl_measure(const char*, int& x, int& y); +#ifdef __APPLE__ +extern FL_EXPORT void gl_texture_pile_height(int max); +extern FL_EXPORT int gl_texture_pile_height(); +#endif FL_EXPORT void gl_draw_image(const uchar *, int x,int y,int w,int h, int d=3, int ld=0); diff --git a/src/gl_draw.cxx b/src/gl_draw.cxx index f0323d4ed..8593f40f6 100644 --- a/src/gl_draw.cxx +++ b/src/gl_draw.cxx @@ -29,7 +29,7 @@ // See also Fl_Gl_Window and gl_start.cxx #include "flstring.h" -#if HAVE_GL +#if HAVE_GL || defined(FL_DOXYGEN) #include #include @@ -129,7 +129,6 @@ void gl_font(int fontid, int size) { } #ifndef __APPLE__ -// The OSX build does not use this at present... It probbaly should, though... static void get_list(int r) { gl_fontsize->glok[r] = 1; #if defined(USE_X11) @@ -151,7 +150,7 @@ static void get_list(int r) { wglUseFontBitmapsW(fl_gc, ii, ii + 0x03ff, gl_fontsize->listbase+ii); SelectObject(fl_gc, oldFid); #elif defined(__APPLE_QUARTZ__) -// FIXME: +// handled by textures #else # error unsupported platform #endif @@ -197,14 +196,15 @@ void gl_remove_displaylist_fonts() #endif } -/** - Draws an array of n characters of the string in the current font - at the current position. - */ #ifdef __APPLE__ static void gl_draw_cocoa(const char* str, int n); #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) + */ void gl_draw(const char* str, int n) { #ifdef __APPLE__ gl_draw_cocoa(str, n); @@ -237,6 +237,7 @@ void gl_draw(const char* str, int n) { /** 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) */ void gl_draw(const char* str, int n, int x, int y) { glRasterPos2i(x, y); @@ -245,6 +246,7 @@ 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) */ void gl_draw(const char* str, int n, float x, float y) { glRasterPos2f(x, y); @@ -253,6 +255,7 @@ 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) */ void gl_draw(const char* str) { gl_draw(str, strlen(str)); @@ -260,6 +263,7 @@ void gl_draw(const char* 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) */ void gl_draw(const char* str, int x, int y) { gl_draw(str, strlen(str), x, y); @@ -267,6 +271,7 @@ void gl_draw(const char* str, int x, int 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) */ void gl_draw(const char* str, float x, float y) { gl_draw(str, strlen(str), x, y); @@ -289,6 +294,7 @@ void gl_draw( fl_draw(str, x, -y-h, w, h, align, gl_draw_invert); } +/** Measure how wide and tall the string will be when drawn by the gl_draw() function */ void gl_measure(const char* str, int& x, int& y) {fl_measure(str,x,y);} /** @@ -351,13 +357,56 @@ void gl_draw_image(const uchar* b, int x, int y, int w, int h, int d, int ld) { glDrawPixels(w,h,d<4?GL_RGB:GL_RGBA,GL_UNSIGNED_BYTE,(const ulong*)b); } -#ifdef __APPLE__ +#if defined( __APPLE__) || defined(FL_DOXYGEN) #include -static void gl_draw_cocoa(const char* str, int n) +// manages a fifo pile of pre-computed string textures +class gl_texture_fifo { + friend void gl_draw_cocoa(const char *, int); +private: + typedef struct { // information for a pre-computed texture + GLuint texName; // its name + char *utf8; //its text + Fl_Font_Descriptor *fdesc; // its font + int width; // its width + int height; // its height + } data; + data *fifo; // array of pile elements + int size_; // pile height + int current; // the oldest texture to have entered the pile + int last; // pile top + int textures_generated; // true iff glGenTextures has been called + void display_texture(int rank); + int compute_texture(const char* str, int n); + int already_known(const char *str, int n); +public: + gl_texture_fifo(int max = 100); // 100 = default height of texture pile + inline int size(void) {return size_; }; + ~gl_texture_fifo(void); +}; + +gl_texture_fifo::gl_texture_fifo(int max) { -//setup matrices + size_ = max; + last = current = -1; + textures_generated = 0; + fifo = (data*)calloc(size_, sizeof(data)); +} + +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); +} + +// displays a pre-computed texture on the GL scene +void gl_texture_fifo::display_texture(int rank) +{ + //setup matrices GLint matrixMode; glGetIntegerv (GL_MATRIX_MODE, &matrixMode); glMatrixMode (GL_PROJECTION); @@ -370,64 +419,41 @@ static void gl_draw_cocoa(const char* str, int n) float winh = Fl_Window::current()->h(); glScalef (2.0f / winw, 2.0f / winh, 1.0f); glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f); -//write str to a bitmap just big enough - int w = 0, h = 0; - fl_measure(str, w, h, 0); - CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); - void *base = calloc(4*w, h); - if(base == NULL) return; - fl_gc = CGBitmapContextCreate(base, w, h, 8, w*4, lut, kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(lut); - fl_fontsize = gl_fontsize; - fl_draw(str, 0, h - fl_descent()); -//put this bitmap in a texture - static GLuint texName = 0; - glPushAttrib(GL_TEXTURE_BIT); - if (0 == texName) glGenTextures (1, &texName); - glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texName); - glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, base); - glPopAttrib(); - CGContextRelease(fl_gc); - fl_gc = NULL; - free(base); + //write the texture on screen GLfloat pos[4]; glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - if (texName) {//write the texture on screen - CGRect bounds = CGRectMake (pos[0], pos[1] - fl_descent(), w, h); - glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable - - 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 - glEnable (GL_TEXTURE_RECTANGLE_EXT); - - glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texName); - glBegin (GL_QUADS); - glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates - glVertex2f (bounds.origin.x, bounds.origin.y); - - glTexCoord2f (0.0f, h); // draw upper left in world coordinates - glVertex2f (bounds.origin.x, bounds.origin.y + bounds.size.height); - - glTexCoord2f (w, h); // draw upper right in world coordinates - glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height); - - glTexCoord2f (w, 0.0f); // draw lower right in world coordinates - glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y); - glEnd (); - - glPopAttrib(); - glDeleteTextures(1, &texName); - } + CGRect bounds = CGRectMake (pos[0], pos[1] - fl_descent(), fifo[rank].width, fifo[rank].height); + glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable + + 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 + glEnable (GL_TEXTURE_RECTANGLE_EXT); + + glBindTexture (GL_TEXTURE_RECTANGLE_EXT, fifo[rank].texName); + glBegin (GL_QUADS); + glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates + glVertex2f (bounds.origin.x, bounds.origin.y); + + glTexCoord2f (0.0f, fifo[rank].height); // draw upper left in world coordinates + glVertex2f (bounds.origin.x, bounds.origin.y + bounds.size.height); + + glTexCoord2f (fifo[rank].width, fifo[rank].height); // draw upper right in world coordinates + glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height); + + glTexCoord2f (fifo[rank].width, 0.0f); // draw lower right in world coordinates + glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y); + glEnd (); + + glPopAttrib(); // reset original matrices glPopMatrix(); // GL_MODELVIEW glMatrixMode (GL_PROJECTION); glPopMatrix(); glMatrixMode (matrixMode); -//set the raster position to end of string - pos[0] += w; + + //set the raster position to end of string + pos[0] += fifo[rank].width; GLdouble modelmat[16]; glGetDoublev (GL_MODELVIEW_MATRIX, modelmat); GLdouble projmat[16]; @@ -438,9 +464,100 @@ static void gl_draw_cocoa(const char* str, int n) gluUnProject(pos[0], pos[1], pos[2], modelmat, projmat, viewport, &objX, &objY, &objZ); glRasterPos2d(objX, objY); } -#endif -#endif +// pre-computes a string texture +int gl_texture_fifo::compute_texture(const char* str, int n) +{ + current = (current + 1) % size_; + if (current > last) last = current; + //write str to a bitmap just big enough + fifo[current].width = 0, fifo[current].height = 0; + fl_measure(str, fifo[current].width, fifo[current].height, 0); + CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); + void *base = calloc(4*fifo[current].width, fifo[current].height); + if (base == NULL) return -1; + fl_gc = CGBitmapContextCreate(base, fifo[current].width, fifo[current].height, 8, fifo[current].width*4, lut, kCGImageAlphaPremultipliedLast); + CGColorSpaceRelease(lut); + fl_fontsize = gl_fontsize; + fl_draw(str, 0, fifo[current].height - fl_descent()); + //put this bitmap in a texture + glPushAttrib(GL_TEXTURE_BIT); + glBindTexture (GL_TEXTURE_RECTANGLE_EXT, fifo[current].texName); + glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, fifo[current].width, fifo[current].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, base); + glPopAttrib(); + CGContextRelease(fl_gc); + fl_gc = NULL; + free(base); + if ( fifo[current].utf8 ) free(fifo[current].utf8); + fifo[current].utf8 = (char *)malloc(n + 1); + memcpy(fifo[current].utf8, str, n); + fifo[current].utf8[n] = 0; + fifo[current].fdesc = gl_fontsize; + 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) +{ + 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) return rank; + } + return -1; +} + +static gl_texture_fifo *gl_fifo = NULL; // points to the texture pile class instance + +// draws a utf8 string using pre-computed texture if available +static void gl_draw_cocoa(const char* str, int n) +{ + if (! gl_fifo) gl_fifo = new gl_texture_fifo(); + if (!gl_fifo->textures_generated) { + 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); + } + gl_fifo->display_texture(rank); +} + +/** \addtogroup group_macosx + @{ */ + +/** + \brief Returns the current height of the pile of pre-computed string textures + * + The default value is 100 + */ +int gl_texture_pile_height(void) +{ + if (! gl_fifo) gl_fifo = new gl_texture_fifo(); + return gl_fifo->size(); +} + +/** + \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 + */ +void gl_texture_pile_height(int max) +{ + if (gl_fifo) delete gl_fifo; + gl_fifo = new gl_texture_fifo(max); +} + +/** @} */ + +#endif // __APPLE__ + +#endif // HAVE_GL // // End of "$Id$".