2 // "$Id: gl_draw.cxx 8573 2011-04-10 09:10:40Z manolo $"
4 // OpenGL drawing support routines for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2011 by Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 // Functions from <FL/gl.h>
29 // See also Fl_Gl_Window and gl_start.cxx
32 #if HAVE_GL || defined(FL_DOXYGEN)
37 #include <FL/fl_draw.H>
38 #include <FL/Fl_Device.H>
39 #include "Fl_Gl_Choice.H"
41 #include <FL/fl_utf8.h>
43 #if !defined(WIN32) && !defined(__APPLE__)
48 //extern XFontStruct* fl_xxfont();
51 /** Returns the current font's height */
52 int gl_height() {return fl_height();}
53 /** Returns the current font's descent */
54 int gl_descent() {return fl_descent();}
55 /** Returns the width of the string in the current fnt */
56 double gl_width(const char* s
) {return fl_width(s
);}
57 /** Returns the width of n characters of the string in the current font */
58 double gl_width(const char* s
, int n
) {return fl_width(s
,n
);}
59 /** Returns the width of the character in the current font */
60 double gl_width(uchar c
) {return fl_width(c
);}
62 static Fl_Font_Descriptor
*gl_fontsize
;
64 #define GL_DRAW_USES_TEXTURES (defined(__APPLE__) && !__ppc__) // 1 only for non-PPC OSX
66 # define USE_OksiD_style_GL_font_selection 1 // Most hosts except OSX
68 # undef USE_OksiD_style_GL_font_selection // OSX
72 # undef USE_OksiD_style_GL_font_selection // turn this off for XFT also
76 Sets the current OpenGL font to the same font as calling fl_font()
78 void gl_font(int fontid
, int size
) {
79 fl_font(fontid
, size
);
80 Fl_Font_Descriptor
*fl_fontsize
= fl_graphics_driver
->font_descriptor();
81 #if !GL_DRAW_USES_TEXTURES
82 if (!fl_fontsize
->listbase
) {
84 #ifdef USE_OksiD_style_GL_font_selection
85 fl_fontsize
->listbase
= glGenLists(0x10000);
86 #else // Fltk-1.1.8 style GL font selection
88 #if defined (USE_X11) // X-windows options follow, either XFT or "plain" X
89 // FIXME: warning Ideally, for XFT, we really need a glXUseXftFont implementation here...
90 // FIXME: warning GL font selection is basically wrong here
91 /* OksiD had a fairly sophisticated scheme for storing multiple X fonts in a XUtf8FontStruct,
92 * then sorting through them at draw time (for normal X rendering) to find which one can
93 * render the current glyph... But for now, just use the first font in the list for GL...
95 XFontStruct
*font
= fl_xfont
;
96 int base
= font
->min_char_or_byte2
;
97 int count
= font
->max_char_or_byte2
-base
+1;
98 fl_fontsize
->listbase
= glGenLists(256);
99 glXUseXFont(font
->fid
, base
, count
, fl_fontsize
->listbase
+base
);
100 # elif defined(WIN32)
101 // this is unused because USE_OksiD_style_GL_font_selection == 1
102 int base
= fl_fontsize
->metr
.tmFirstChar
;
103 int count
= fl_fontsize
->metr
.tmLastChar
-base
+1;
104 HFONT oldFid
= (HFONT
)SelectObject(fl_gc
, fl_fontsize
->fid
);
105 fl_fontsize
->listbase
= glGenLists(256);
106 wglUseFontBitmaps(fl_gc
, base
, count
, fl_fontsize
->listbase
+base
);
107 SelectObject(fl_gc
, oldFid
);
108 # elif defined(__APPLE_QUARTZ__)
109 //AGL is not supported for use in 64-bit applications:
110 //http://developer.apple.com/mac/library/documentation/Carbon/Conceptual/Carbon64BitGuide/OtherAPIChanges/OtherAPIChanges.html
111 short font
, face
, size
;
113 fn
[0]=strlen(fl_fontsize
->q_name
);
114 strcpy((char*)(fn
+1), fl_fontsize
->q_name
);
117 size
= fl_fontsize
->size
;
118 fl_fontsize
->listbase
= glGenLists(256);
119 aglUseFont(aglGetCurrentContext(), font
, face
,
120 size
, 0, 256, fl_fontsize
->listbase
);
122 # error unsupported platform
125 #endif // USE_OksiD_style_GL_font_selection
127 glListBase(fl_fontsize
->listbase
);
128 #endif // !GL_DRAW_USES_TEXTURES
129 gl_fontsize
= fl_fontsize
;
133 static void get_list(int r
) {
134 gl_fontsize
->glok
[r
] = 1;
139 unsigned int ii
= r
* 0x400;
140 for (int i
= 0; i
< 0x400; i
++) {
141 XFontStruct
*font
= NULL
;
143 XGetUtf8FontAndGlyph(gl_fontsize
->font
, ii
, &font
, &id
);
144 if (font
) glXUseXFont(font
->fid
, id
, 1, gl_fontsize
->listbase
+ii
);
149 unsigned int ii
= r
* 0x400;
150 HFONT oldFid
= (HFONT
)SelectObject(fl_gc
, gl_fontsize
->fid
);
151 wglUseFontBitmapsW(fl_gc
, ii
, ii
+ 0x03ff, gl_fontsize
->listbase
+ii
);
152 SelectObject(fl_gc
, oldFid
);
153 #elif defined(__APPLE_QUARTZ__)
154 // handled by textures
156 # error unsupported platform
161 void gl_remove_displaylist_fonts()
165 // clear variables used mostly in fl_font
166 fl_graphics_driver
->font(0, 0);
168 for (int j
= 0 ; j
< FL_FREE_FONT
; ++j
)
170 Fl_Font_Descriptor
* past
= 0;
171 Fl_Fontdesc
* s
= fl_fonts
+ j
;
172 Fl_Font_Descriptor
* f
= s
->first
;
179 past
->next
= f
->next
;
182 // It would be nice if this next line was in a desctructor somewhere
183 glDeleteLists(f
->listbase
, 256);
185 Fl_Font_Descriptor
* tmp
= f
;
199 #if GL_DRAW_USES_TEXTURES
200 static void gl_draw_textures(const char* str
, int n
);
204 Draws an array of n characters of the string in the current font
205 at the current position.
206 \see On the Mac OS X platform, see gl_texture_pile_height(int)
208 void gl_draw(const char* str
, int n
) {
211 #if GL_DRAW_USES_TEXTURES
212 gl_draw_textures(str
, n
);
214 glCallLists(n
, GL_UNSIGNED_BYTE
, str
);
218 static xchar
*buf
= NULL
;
220 int wn
= fl_utf8toUtf16(str
, n
, (unsigned short*)buf
, l
);
222 buf
= (xchar
*) realloc(buf
, sizeof(xchar
) * (wn
+ 1));
224 wn
= fl_utf8toUtf16(str
, n
, (unsigned short*)buf
, l
);
229 for (i
= 0; i
< n
; i
++) {
231 r
= (str
[i
] & 0xFC00) >> 10;
232 if (!gl_fontsize
->glok
[r
]) get_list(r
);
234 glCallLists(n
, GL_UNSIGNED_SHORT
, buf
);
239 Draws n characters of the string in the current font at the given position
240 \see On the Mac OS X platform, see gl_texture_pile_height(int)
242 void gl_draw(const char* str
, int n
, int x
, int y
) {
248 Draws n characters of the string in the current font at the given position
249 \see On the Mac OS X platform, see gl_texture_pile_height(int)
251 void gl_draw(const char* str
, int n
, float x
, float y
) {
257 Draws a nul-terminated string in the current font at the current position
258 \see On the Mac OS X platform, see gl_texture_pile_height(int)
260 void gl_draw(const char* str
) {
261 gl_draw(str
, strlen(str
));
265 Draws a nul-terminated string in the current font at the given position
266 \see On the Mac OS X platform, see gl_texture_pile_height(int)
268 void gl_draw(const char* str
, int x
, int y
) {
269 gl_draw(str
, strlen(str
), x
, y
);
273 Draws a nul-terminated string in the current font at the given position
274 \see On the Mac OS X platform, see gl_texture_pile_height(int)
276 void gl_draw(const char* str
, float x
, float y
) {
277 gl_draw(str
, strlen(str
), x
, y
);
280 static void gl_draw_invert(const char* str
, int n
, int x
, int y
) {
281 glRasterPos2i(x
, -y
);
286 Draws a string formatted into a box, with newlines and tabs expanded,
287 other control characters changed to ^X. and aligned with the edges or
288 center. Exactly the same output as fl_draw().
291 const char* str
, // the (multi-line) string
292 int x
, int y
, int w
, int h
, // bounding box
294 fl_draw(str
, x
, -y
-h
, w
, h
, align
, gl_draw_invert
);
297 /** Measure how wide and tall the string will be when drawn by the gl_draw() function */
298 void gl_measure(const char* str
, int& x
, int& y
) {fl_measure(str
,x
,y
);}
301 Outlines the given rectangle with the current color.
302 If Fl_Gl_Window::ortho() has been called, then the rectangle will
303 exactly fill the given pixel rectangle.
305 void gl_rect(int x
, int y
, int w
, int h
) {
306 if (w
< 0) {w
= -w
; x
= x
-w
;}
307 if (h
< 0) {h
= -h
; y
= y
-h
;}
308 glBegin(GL_LINE_STRIP
);
309 glVertex2i(x
+w
-1, y
+h
-1);
310 glVertex2i(x
+w
-1, y
);
312 glVertex2i(x
, y
+h
-1);
313 glVertex2i(x
+w
, y
+h
-1);
318 extern uchar fl_overlay
;
319 extern int fl_overlay_depth
;
323 Sets the curent OpenGL color to an FLTK color.
325 For color-index modes it will use fl_xpixel(c), which is only
326 right if the window uses the default colormap!
328 void gl_color(Fl_Color i
) {
331 if (fl_overlay
&& fl_overlay_depth
) {
332 if (fl_overlay_depth
< 8) {
333 // only black & white produce the expected colors. This could
334 // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx
335 int size
= 1<<fl_overlay_depth
;
336 if (!i
) glIndexi(size
-2);
337 else if (i
>= size
-2) glIndexi(size
-1);
340 glIndexi(i
? i
: FL_GRAY_RAMP
);
345 if (fl_overlay
) {glIndexi(int(fl_xpixel(i
))); return;}
348 uchar red
, green
, blue
;
349 Fl::get_color(i
, red
, green
, blue
);
350 glColor3ub(red
, green
, blue
);
353 void gl_draw_image(const uchar
* b
, int x
, int y
, int w
, int h
, int d
, int ld
) {
355 glPixelStorei(GL_UNPACK_ROW_LENGTH
, ld
/d
);
357 glDrawPixels(w
,h
,d
<4?GL_RGB
:GL_RGBA
,GL_UNSIGNED_BYTE
,(const ulong
*)b
);
360 #if GL_DRAW_USES_TEXTURES || defined(FL_DOXYGEN)
364 // manages a fifo pile of pre-computed string textures
365 class gl_texture_fifo
{
366 friend void gl_draw_textures(const char *, int);
368 typedef struct { // information for a pre-computed texture
369 GLuint texName
; // its name
370 char *utf8
; //its text
371 Fl_Font_Descriptor
*fdesc
; // its font
372 int width
; // its width
373 int height
; // its height
375 data
*fifo
; // array of pile elements
376 int size_
; // pile height
377 int current
; // the oldest texture to have entered the pile
378 int last
; // pile top
379 int textures_generated
; // true iff glGenTextures has been called
380 void display_texture(int rank
);
381 int compute_texture(const char* str
, int n
);
382 int already_known(const char *str
, int n
);
384 gl_texture_fifo(int max
= 100); // 100 = default height of texture pile
385 inline int size(void) {return size_
; };
386 ~gl_texture_fifo(void);
389 gl_texture_fifo::gl_texture_fifo(int max
)
393 textures_generated
= 0;
394 fifo
= (data
*)calloc(size_
, sizeof(data
));
397 gl_texture_fifo::~gl_texture_fifo()
399 for (int i
= 0; i
< size_
; i
++) {
400 if (fifo
[i
].utf8
) free(fifo
[i
].utf8
);
401 if (textures_generated
) glDeleteTextures(1, &fifo
[i
].texName
);
406 // displays a pre-computed texture on the GL scene
407 void gl_texture_fifo::display_texture(int rank
)
411 glGetIntegerv (GL_MATRIX_MODE
, &matrixMode
);
412 glMatrixMode (GL_PROJECTION
);
415 glMatrixMode (GL_MODELVIEW
);
418 float winw
= Fl_Window::current()->w();
419 float winh
= Fl_Window::current()->h();
420 glScalef (2.0f
/ winw
, 2.0f
/ winh
, 1.0f
);
421 glTranslatef (-winw
/ 2.0f
, -winh
/ 2.0f
, 0.0f
);
422 //write the texture on screen
424 glGetFloatv(GL_CURRENT_RASTER_POSITION
, pos
);
425 CGRect bounds
= CGRectMake (pos
[0], pos
[1] - fl_descent(), fifo
[rank
].width
, fifo
[rank
].height
);
427 // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable
428 glPushAttrib(GL_ENABLE_BIT
| GL_TEXTURE_BIT
| GL_COLOR_BUFFER_BIT
);
429 glDisable (GL_DEPTH_TEST
); // ensure text is not removed by depth buffer test.
430 glEnable (GL_BLEND
); // for text fading
431 glBlendFunc (GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
); // ditto
432 glEnable (GL_TEXTURE_RECTANGLE_EXT
);
433 glDisable(GL_LIGHTING
);
434 glBindTexture (GL_TEXTURE_RECTANGLE_EXT
, fifo
[rank
].texName
);
436 glTexCoord2f (0.0f
, 0.0f
); // draw lower left in world coordinates
437 glVertex2f (bounds
.origin
.x
, bounds
.origin
.y
);
439 glTexCoord2f (0.0f
, fifo
[rank
].height
); // draw upper left in world coordinates
440 glVertex2f (bounds
.origin
.x
, bounds
.origin
.y
+ bounds
.size
.height
);
442 glTexCoord2f (fifo
[rank
].width
, fifo
[rank
].height
); // draw upper right in world coordinates
443 glVertex2f (bounds
.origin
.x
+ bounds
.size
.width
, bounds
.origin
.y
+ bounds
.size
.height
);
445 glTexCoord2f (fifo
[rank
].width
, 0.0f
); // draw lower right in world coordinates
446 glVertex2f (bounds
.origin
.x
+ bounds
.size
.width
, bounds
.origin
.y
);
450 // reset original matrices
451 glPopMatrix(); // GL_MODELVIEW
452 glMatrixMode (GL_PROJECTION
);
454 glMatrixMode (matrixMode
);
456 //set the raster position to end of string
457 pos
[0] += fifo
[rank
].width
;
458 GLdouble modelmat
[16];
459 glGetDoublev (GL_MODELVIEW_MATRIX
, modelmat
);
460 GLdouble projmat
[16];
461 glGetDoublev (GL_PROJECTION_MATRIX
, projmat
);
462 GLdouble objX
, objY
, objZ
;
464 glGetIntegerv (GL_VIEWPORT
, viewport
);
465 gluUnProject(pos
[0], pos
[1], pos
[2], modelmat
, projmat
, viewport
, &objX
, &objY
, &objZ
);
466 glRasterPos2d(objX
, objY
);
469 // pre-computes a string texture
470 int gl_texture_fifo::compute_texture(const char* str
, int n
)
472 current
= (current
+ 1) % size_
;
473 if (current
> last
) last
= current
;
474 //write str to a bitmap just big enough
475 if ( fifo
[current
].utf8
) free(fifo
[current
].utf8
);
476 fifo
[current
].utf8
= (char *)malloc(n
+ 1);
477 memcpy(fifo
[current
].utf8
, str
, n
);
478 fifo
[current
].utf8
[n
] = 0;
479 fifo
[current
].width
= 0, fifo
[current
].height
= 0;
480 fl_measure(fifo
[current
].utf8
, fifo
[current
].width
, fifo
[current
].height
, 0);
481 CGColorSpaceRef lut
= CGColorSpaceCreateDeviceRGB();
482 void *base
= calloc(4*fifo
[current
].width
, fifo
[current
].height
);
483 if (base
== NULL
) return -1;
484 fl_gc
= CGBitmapContextCreate(base
, fifo
[current
].width
, fifo
[current
].height
, 8, fifo
[current
].width
*4, lut
, kCGImageAlphaPremultipliedLast
);
485 CGColorSpaceRelease(lut
);
486 fl_graphics_driver
->font_descriptor(gl_fontsize
);
488 glGetFloatv(GL_CURRENT_COLOR
, colors
);
489 fl_color((uchar
)(colors
[0]*255), (uchar
)(colors
[1]*255), (uchar
)(colors
[2]*255));
490 fl_draw(str
, n
, 0, fifo
[current
].height
- fl_descent());
491 //put this bitmap in a texture
492 glPushAttrib(GL_TEXTURE_BIT
);
493 glBindTexture (GL_TEXTURE_RECTANGLE_EXT
, fifo
[current
].texName
);
494 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
495 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
496 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT
, 0, GL_RGBA
, fifo
[current
].width
, fifo
[current
].height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, base
);
498 CGContextRelease(fl_gc
);
501 fifo
[current
].fdesc
= gl_fontsize
;
505 // returns rank of pre-computed texture for a string if it exists
506 int gl_texture_fifo::already_known(const char *str
, int n
)
509 for ( rank
= 0; rank
<= last
; rank
++) {
510 if ( memcmp(str
, fifo
[rank
].utf8
, n
) == 0 && fifo
[rank
].utf8
[n
] == 0 &&
511 fifo
[rank
].fdesc
== gl_fontsize
) return rank
;
516 static gl_texture_fifo
*gl_fifo
= NULL
; // points to the texture pile class instance
518 // draws a utf8 string using pre-computed texture if available
519 static void gl_draw_textures(const char* str
, int n
)
521 if (! gl_fifo
) gl_fifo
= new gl_texture_fifo();
522 if (!gl_fifo
->textures_generated
) {
523 for (int i
= 0; i
< gl_fifo
->size_
; i
++) glGenTextures (1, &(gl_fifo
->fifo
[i
].texName
));
524 gl_fifo
->textures_generated
= 1;
526 int rank
= gl_fifo
->already_known(str
, n
);
528 rank
= gl_fifo
->compute_texture(str
, n
);
530 gl_fifo
->display_texture(rank
);
533 /** \addtogroup group_macosx
537 \brief Returns the current height of the pile of pre-computed string textures
539 The default value is 100
541 int gl_texture_pile_height(void)
543 if (! gl_fifo
) gl_fifo
= new gl_texture_fifo();
544 return gl_fifo
->size();
548 \brief Changes the height of the pile of pre-computed string textures
550 Strings that are often re-displayed can be processed much faster if
551 this pile is set high enough to hold all of them.
552 \param max Height of the texture pile
554 void gl_texture_pile_height(int max
)
556 if (gl_fifo
) delete gl_fifo
;
557 gl_fifo
= new gl_texture_fifo(max
);
562 #elif defined(__APPLE__)
563 // used only if __ppc__
564 int gl_texture_pile_height(void) {return 0;}
565 void gl_texture_pile_height(int max
) {}
566 #endif // GL_DRAW_USES_TEXTURES
567 #if defined(__APPLE__)
568 void gl_texture_reset()
570 #if GL_DRAW_USES_TEXTURES
571 if (gl_fifo
) gl_texture_pile_height(gl_texture_pile_height());
572 #endif // GL_DRAW_USES_TEXTURES
579 // End of "$Id: gl_draw.cxx 8573 2011-04-10 09:10:40Z manolo $".