1/**
2
3 \page	opengl Using OpenGL
4
5This chapter discusses using FLTK for your OpenGL applications.
6
7\section opengl_using Using OpenGL in FLTK
8
9The easiest way to make an OpenGL display is to subclass
10Fl_Gl_Window.
11Your subclass must implement a \p draw() method which uses
12OpenGL calls to draw the display. Your main program should call
13\p redraw() when the display needs to change, and
14(somewhat later) FLTK will call \p draw().
15
16With a bit of care you can also use OpenGL to draw into
17normal FLTK windows. This allows you to use Gouraud shading for
18drawing your widgets.  To do this you use the
19\ref opengl_gl_start "gl_start()" and
20\ref opengl_gl_finish "gl_finish()"
21functions around your OpenGL code.
22
23You must include FLTK's \p <FL/gl.h> header
24file. It will include the file \p <GL/gl.h>, define
25some extra drawing functions provided by FLTK, and include the
26\p <windows.h> header file needed by WIN32
27applications.
28
29Some simple coding rules (see \ref osissues_retina) allow to write cross-platform code that will draw high resolution
30OpenGL graphics if run on 'retina' displays with Mac OS X.
31
32\section opengl_subclass Making a Subclass of Fl_Gl_Window
33
34To make a subclass of Fl_Gl_Window, you must provide:
35
36\li A class definition.
37\li A \p draw() method.
38\li A \p handle() method if you need to receive input from the user.
39
40If your subclass provides static controls in the window, they
41must be redrawn whenever the \p FL_DAMAGE_ALL bit is set
42in the value returned by \p damage(). For double-buffered
43windows you will need to surround the drawing code with the
44following code to make sure that both buffers are redrawn:
45
46\code
47#ifndef MESA
48glDrawBuffer(GL_FRONT_AND_BACK);
49#endif // !MESA
50... draw stuff here ...
51#ifndef MESA
52glDrawBuffer(GL_BACK);
53#endif // !MESA
54\endcode
55
56<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" CELLSPACING="0" BGCOLOR="#cccccc">
57<TR>
58	<TD><B>Note:</B>
59
60	If you are using the Mesa graphics library, the call
61	to \p glDrawBuffer() is not required and will slow
62	down drawing considerably. The preprocessor instructions
63	shown above will optimize your code based upon the
64	graphics library used.
65
66	</TD>
67
68</TR>
69</TABLE></CENTER>
70
71\subsection opengl_defining Defining the Subclass
72
73To define the subclass you just subclass the Fl_Gl_Window class:
74
75\code
76class MyWindow : public Fl_Gl_Window {
77  void draw();
78  int handle(int);
79
80public:
81  MyWindow(int X, int Y, int W, int H, const char *L)
82    : Fl_Gl_Window(X, Y, W, H, L) {}
83};
84\endcode
85
86The \p draw() and \p handle() methods are
87described below. Like any widget, you can include additional
88private and public data in your class (such as scene graph
89information, etc.)
90
91\subsection opengl_draw The draw() Method
92
93The \p draw() method is where you actually do your OpenGL drawing:
94
95\code
96void MyWindow::draw() {
97  if (!valid()) {
98    ... set up projection, viewport, etc ...
99    ... window size is in w() and h().
100    ... valid() is turned on by FLTK after draw() returns
101  }
102  ... draw ...
103}
104\endcode
105
106\subsection opengl_handle The handle() Method
107
108The \p handle() method handles mouse and keyboard
109events for the window:
110
111\code
112int MyWindow::handle(int event) {
113  switch(event) {
114  case FL_PUSH:
115    ... mouse down event ...
116    ... position in Fl::event_x() and Fl::event_y()
117    return 1;
118  case FL_DRAG:
119    ... mouse moved while down event ...
120    return 1;
121  case FL_RELEASE:
122    ... mouse up event ...
123    return 1;
124  case FL_FOCUS :
125  case FL_UNFOCUS :
126    ... Return 1 if you want keyboard events, 0 otherwise
127    return 1;
128  case FL_KEYBOARD:
129    ... keypress, key is in Fl::event_key(), ascii in Fl::event_text()
130    ... Return 1 if you understand/use the keyboard event, 0 otherwise...
131    return 1;
132  case FL_SHORTCUT:
133    ... shortcut, key is in Fl::event_key(), ascii in Fl::event_text()
134    ... Return 1 if you understand/use the shortcut event, 0 otherwise...
135    return 1;
136  default:
137    // pass other events to the base class...
138    return Fl_Gl_Window::handle(event);
139  }
140}
141\endcode
142
143When \p handle() is called, the OpenGL context is not
144set up! If your display changes, you should call
145\p redraw() and let \p draw() do the work. Don't
146call any OpenGL drawing functions from inside \p handle()!
147
148You can call \e some OpenGL stuff like hit detection and texture
149loading functions by doing:
150
151\code
152  case FL_PUSH:
153    make_current();	// make OpenGL context current
154    if (!valid()) {
155
156      ... set up projection exactly the same as draw ...
157
158      valid(1);		// stop it from doing this next time
159    }
160    ... ok to call NON-DRAWING OpenGL code here, such as hit
161    detection, loading textures, etc...
162\endcode
163
164Your main program can now create one of your windows by doing
165<tt>new MyWindow(...)</tt>.
166
167You can also use your new window class in
168\ref fluid "FLUID"
169by:
170
171-# Putting your class definition in a \p MyWindow.H file.
172-# Creating a Fl_Box widget in FLUID.
173-# In the widget panel fill in the "class" field with \p MyWindow.
174   This will make FLUID produce constructors for your new class.
175-# In the "Extra Code" field put <tt>\#include "MyWindow.H"</tt>,
176   so that the FLUID output file will compile.
177
178You must put <tt>glwindow->show()</tt> in your main code
179after calling \p show() on the window containing the
180OpenGL window.
181
182\section opengl_normal Using OpenGL in Normal FLTK Windows
183
184You can put OpenGL code into the \p draw() method, as described in
185\ref subclassing_drawing
186in the previous chapter, or into the code for a
187\ref common_boxtypes "boxtype"
188or other places with some care.
189
190Most importantly, before you show \e any windows,
191including those that don't have OpenGL drawing, you <B>must</B>
192initialize FLTK so that it knows it is going to use OpenGL. You
193may use any of the symbols described for \p Fl_Gl_Window::mode()
194to describe how you intend to use OpenGL:
195
196\code
197Fl::gl_visual(FL_RGB);
198\endcode
199
200\anchor opengl_gl_start
201\anchor opengl_gl_finish
202You can then put OpenGL drawing code anywhere you can draw
203normally by surrounding it with
204gl_start() and gl_finish() to set up, and later release, an OpenGL
205context with an orthographic projection so that 0,0 is the
206lower-left corner of the window and each pixel is one unit. The
207current clipping is reproduced with OpenGL \p glScissor()
208commands. These functions also synchronize the OpenGL graphics stream
209with the drawing done by other X, WIN32, or FLTK functions.
210
211\code
212gl_start();
213... put your OpenGL code here ...
214gl_finish();
215\endcode
216
217The same context is reused each time. If your code changes
218the projection transformation or anything else you should use
219\p glPushMatrix() and \p glPopMatrix() functions to
220put the state back before calling \p gl_finish().
221
222You may want to use <tt>Fl_Window::current()-\>h()</tt> to
223get the drawable height so that you can flip the Y
224coordinates.
225
226Unfortunately, there are a bunch of limitations you must
227adhere to for maximum portability:
228
229\li You must choose a default visual with Fl::gl_visual().
230
231\li You cannot pass \p FL_DOUBLE to Fl::gl_visual().
232
233\li You cannot use Fl_Double_Window or Fl_Overlay_Window.
234
235Do \e not call \p gl_start() or
236\p gl_finish() when drawing into an Fl_Gl_Window !
237
238\section opengl_drawing OpenGL Drawing Functions
239
240FLTK provides some useful OpenGL drawing functions. They can
241be freely mixed with any OpenGL calls, and are defined by
242including \p <FL/gl.h> which you should include
243instead of the OpenGL header \p <GL/gl.h>.
244
245void gl_color(Fl_Color)
246
247\par
248Sets the current OpenGL color to a FLTK color. <I>For
249color-index modes it will use \p fl_xpixel(c), which is
250only right if this window uses the default colormap!</I>
251
252void gl_rect(int x, int y, int w, int h) <br>
253void gl_rectf(int x, int y, int w, int h)
254
255\par
256Outlines or fills a rectangle with the current color. If
257Fl_Gl_Window::ortho() has been called, then the rectangle will exactly
258fill the pixel rectangle passed.
259
260void gl_font(Fl_Font fontid, int size)
261
262\par
263Sets the current OpenGL font to the same font you get by calling
264\ref ssect_Fonts "fl_font()".
265
266int gl_height() <br>
267int gl_descent() <br>
268float gl_width(const char *s) <br>
269float gl_width(const char *s, int n) <br>
270float gl_width(uchar c)
271
272\par
273Returns information about the current OpenGL font.
274
275void gl_draw(const char *s) <br>
276void gl_draw(const char *s, int n)
277
278\par
279Draws a nul-terminated string or an array of \p n
280characters in the current OpenGL font at the current raster
281position.
282
283void gl_draw(const char *s, int x, int y) <br>
284void gl_draw(const char *s, int n, int x, int y) <br>
285void gl_draw(const char *s, float x, float y) <br>
286void gl_draw(const char *s, int n, float x, float y)
287
288\par
289Draws a nul-terminated string or an array of \p n
290characters in the current OpenGL font at the given position.
291
292void gl_draw(const char *s, int x, int y, int w, int h, Fl_Align)
293
294\par
295Draws a string formatted into a box, with newlines and tabs
296expanded, other control characters changed to ^X, and aligned
297with the edges or center. Exactly the same output as
298\ref ssect_Text "fl_draw()".
299
300\section opengl_speed Speeding up OpenGL
301
302Performance of Fl_Gl_Window may be improved on some types of
303OpenGL implementations, in particular MESA and other software
304emulators, by setting the \p GL_SWAP_TYPE environment
305variable. This variable declares what is in the backbuffer after
306you do a swapbuffers.
307
308\li <tt>setenv GL_SWAP_TYPE COPY</tt> <br>
309    <br>
310    This indicates that the back buffer is copied to the
311    front buffer, and still contains its old data. This is
312    true of many hardware implementations.  Setting this
313    will speed up emulation of overlays, and widgets that
314    can do partial update can take advantage of this as
315    \p damage() will not be cleared to -1.
316
317\li <tt>setenv GL_SWAP_TYPE NODAMAGE</tt> <br>
318    <br>
319    This indicates that nothing changes the back buffer
320    except drawing into it.  This is true of MESA and Win32
321    software emulation and perhaps some hardware emulation
322    on systems with lots of memory.
323
324\li All other values for \p GL_SWAP_TYPE, and not
325    setting the variable, cause FLTK to assume that the
326    back buffer must be completely redrawn after a swap.
327
328This is easily tested by running the \ref examples_gl_overlay demo
329program and seeing if the display is correct when you drag
330another window over it or if you drag the window off the screen
331and back on. You have to exit and run the program again for it
332to see any changes to the environment variable.
333
334\section opengl_optimizer Using OpenGL Optimizer with FLTK
335
336<A href="http://www.sgi.com/software/optimizer">OpenGL Optimizer</A>
337is a scene graph toolkit for OpenGL available from
338Silicon Graphics for IRIX and Microsoft Windows. It allows you
339to view large scenes without writing a lot of OpenGL code.
340
341\par OptimizerWindow Class Definition
342
343\par
344To use
345<A href="http://www.sgi.com/software/optimizer">OpenGL Optimizer</A>
346with FLTK you'll need to create a
347subclass of Fl_Gl_Widget that includes several state
348variables:
349
350\code
351class OptimizerWindow : public Fl_Gl_Window {
352  csContext *context_; // Initialized to 0 and set by draw()...
353  csDrawAction *draw_action_; // Draw action...
354  csGroup *scene_; // Scene to draw...
355  csCamara *camera_; // Viewport for scene...
356
357  void draw();
358
359public:
360  OptimizerWindow(int X, int Y, int W, int H, const char *L)
361    : Fl_Gl_Window(X, Y, W, H, L) {
362      context_ = (csContext *)0;
363      draw_action_ = (csDrawAction *)0;
364      scene_ = (csGroup *)0;
365      camera_ = (csCamera *)0;
366    }
367
368  void scene(csGroup *g) { scene_ = g; redraw(); }
369
370  void camera(csCamera *c) {
371    camera_ = c;
372    if (context_) {
373      draw_action_->setCamera(camera_);
374      camera_->draw(draw_action_);
375      redraw();
376    }
377  }
378};
379\endcode
380
381\par The camera() Method
382
383\par
384The \p camera() method sets the camera (projection and
385viewpoint) to use when drawing the scene. The scene is redrawn after
386this call.
387
388\par The draw() Method
389
390\par
391The \p draw() method performs the needed initialization and does
392the actual drawing:
393
394\code
395void OptimizerWindow::draw() {
396  if (!context_) {
397    // This is the first time we've been asked to draw; create the
398    // Optimizer context for the scene...
399
400#ifdef WIN32
401    context_ = new csContext((HDC)fl_getHDC());
402    context_->ref();
403    context_->makeCurrent((HDC)fl_getHDC());
404#else
405    context_ = new csContext(fl_display, fl_visual);
406    context_->ref();
407    context_->makeCurrent(fl_display, fl_window);
408#endif // WIN32
409
410    ... perform other context setup as desired ...
411
412    // Then create the draw action to handle drawing things...
413
414    draw_action_ = new csDrawAction;
415    if (camera_) {
416      draw_action_->setCamera(camera_);
417      camera_->draw(draw_action_);
418    }
419  } else {
420#ifdef WIN32
421    context_->makeCurrent((HDC)fl_getHDC());
422#else
423    context_->makeCurrent(fl_display, fl_window);
424#endif // WIN32
425  }
426
427  if (!valid()) {
428    // Update the viewport for this context...
429    context_->setViewport(0, 0, w(), h());
430  }
431
432  // Clear the window...
433  context_->clear(csContext::COLOR_CLEAR | csContext::DEPTH_CLEAR,
434                  0.0f,		// Red
435		  0.0f,		// Green
436		  0.0f,		// Blue
437		  1.0f);	// Alpha
438
439  // Then draw the scene (if any)...
440  if (scene_)
441    draw_action_->apply(scene_);
442}
443\endcode
444
445\par The scene() Method
446
447\par
448The \p scene() method sets the scene to be drawn.  The scene is
449a collection of 3D objects in a \p csGroup.  The scene is redrawn
450after this call.
451
452\section opengl3 Using OpenGL 3.0 (or higher versions)
453
454The examples subdirectory contains OpenGL3test.cxx, a toy program
455showing how to use OpenGL 3.0 (or higher versions) with FLTK in a cross-platform fashion.
456It contains also OpenGL3-glut-test.cxx which shows how to use FLTK's GLUT compatibility
457and OpenGL 3.
458
459To access OpenGL 3.0 (or higher versions), use the <tt>FL_OPENGL3</tt> flag
460when calling Fl_Gl_Window::mode(int a) or glutInitDisplayMode().
461
462<b>On the Windows and Unix/Linux platforms</b>, FLTK creates contexts
463implementing the highest OpenGL version supported by the hardware.
464Such contexts may also be compatible with lower OpenGL versions.
465Access to functions from OpenGL
466versions above 1.1 requires to load function pointers at runtime on these platforms.
467FLTK recommends to use the GLEW library to perform this. It is therefore
468necessary to install the GLEW library (see below).
469
470<b>On the macOS platform</b>, MacOS 10.7 or above is required;
471GLEW is possible but not necessary. FLTK creates contexts for OpenGL
472versions 1 and 2 without the FL_OPENGL3
473flag and for OpenGL versions 3.2 and above with it.
474
475\par GLEW installation (Unix/Linux and MSWindows platforms)
476GLEW is available as a package for most Linux distributions and in source form at http://glew.sourceforge.net/.
477For the MSWindows platform, a Visual Studio static library (glew32.lib) can be downloaded from the same web site; a MinGW-style static library (libglew32.a) can be built from source with the make command.
478
479\par  Source-level changes for OpenGL 3:
480\li Put this in all OpenGL-using source files (instead of \#include <FL/gl.h>,
481and before \#include <FL/glut.h> if you use GLUT):
482\code
483#if defined(__APPLE__)
484#  include <OpenGL/gl3.h> // defines OpenGL 3.0+ functions
485#else
486#  if defined(WIN32)
487#    define GLEW_STATIC 1
488#  endif
489#  include <GL/glew.h>
490#endif
491\endcode
492\li Add the <tt>FL_OPENGL3</tt> flag when calling Fl_Gl_Window::mode(int a)
493or glutInitDisplayMode().
494\li Put this in the <tt>handle(int event)</tt> member function of the first to be created
495among your Fl_Gl_Window-derived classes:
496\code
497#ifndef __APPLE__
498    static int first = 1;
499    if (first && event == FL_SHOW && shown()) {
500      first = 0;
501      make_current();
502      glewInit(); // defines pters to functions of OpenGL V 1.2 and above
503    }
504#endif
505\endcode
506\li Alternatively, if you use GLUT, put
507\code
508#ifndef __APPLE__
509  glewInit(); // defines pters to functions of OpenGL V 1.2 and above
510#endif
511\endcode
512after the first glutCreateWindow() call.
513
514If GLEW is installed on the Mac OS development platform, it is possible
515to use the same code for all platforms, with one exception: put
516\code
517#ifdef __APPLE__
518glewExperimental = GL_TRUE;
519#endif
520\endcode
521before the glewInit() call.
522
523\par Changes in the build process
524Link with libGLEW.so (on Unix/Linux), libglew32.a (with MinGW) or glew32.lib
525(with MS Visual Studio); no change is needed on the Mac OS platform.
526
527\htmlonly
528<hr>
529<table summary="navigation bar" width="100%" border="0">
530<tr>
531  <td width="45%" align="LEFT">
532    <a class="el" href="subclassing.html">
533    [Prev]
534    Adding and Extending Widgets
535    </a>
536  </td>
537  <td width="10%" align="CENTER">
538    <a class="el" href="index.html">[Index]</a>
539  </td>
540  <td width="45%" align="RIGHT">
541    <a class="el" href="fluid.html">
542    Programming with FLUID
543    [Next]
544    </a>
545  </td>
546</tr>
547</table>
548\endhtmlonly
549
550*/
551