You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
13KB

  1. /**
  2. \page opengl Using OpenGL
  3. This chapter discusses using FLTK for your OpenGL applications.
  4. \section opengl_using Using OpenGL in FLTK
  5. The easiest way to make an OpenGL display is to subclass
  6. Fl_Gl_Window.
  7. Your subclass must implement a \p draw() method which uses
  8. OpenGL calls to draw the display. Your main program should call
  9. \p redraw() when the display needs to change, and
  10. (somewhat later) FLTK will call \p draw().
  11. With a bit of care you can also use OpenGL to draw into
  12. normal FLTK windows. This allows you to use Gouraud shading for
  13. drawing your widgets. To do this you use the
  14. \ref opengl_gl_start "gl_start()" and
  15. \ref opengl_gl_finish "gl_finish()"
  16. functions around your OpenGL code.
  17. You must include FLTK's \p <FL/gl.h> header
  18. file. It will include the file \p <GL/gl.h>, define
  19. some extra drawing functions provided by FLTK, and include the
  20. \p <windows.h> header file needed by WIN32
  21. applications.
  22. \section opengl_subclass Making a Subclass of Fl_Gl_Window
  23. To make a subclass of Fl_Gl_Window, you must provide:
  24. \li A class definition.
  25. \li A \p draw() method.
  26. \li A \p handle() method if you need to receive input from the user.
  27. If your subclass provides static controls in the window, they
  28. must be redrawn whenever the \p FL_DAMAGE_ALL bit is set
  29. in the value returned by \p damage(). For double-buffered
  30. windows you will need to surround the drawing code with the
  31. following code to make sure that both buffers are redrawn:
  32. \code
  33. #ifndef MESA
  34. glDrawBuffer(GL_FRONT_AND_BACK);
  35. #endif // !MESA
  36. ... draw stuff here ...
  37. #ifndef MESA
  38. glDrawBuffer(GL_BACK);
  39. #endif // !MESA
  40. \endcode
  41. <CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" CELLSPACING="0" BGCOLOR="#cccccc">
  42. <TR>
  43. <TD><B>Note:</B>
  44. If you are using the Mesa graphics library, the call
  45. to \p glDrawBuffer() is not required and will slow
  46. down drawing considerably. The preprocessor instructions
  47. shown above will optimize your code based upon the
  48. graphics library used.
  49. </TD>
  50. </TR>
  51. </TABLE></CENTER>
  52. \subsection opengl_defining Defining the Subclass
  53. To define the subclass you just subclass the Fl_Gl_Window class:
  54. \code
  55. class MyWindow : public Fl_Gl_Window {
  56. void draw();
  57. int handle(int);
  58. public:
  59. MyWindow(int X, int Y, int W, int H, const char *L)
  60. : Fl_Gl_Window(X, Y, W, H, L) {}
  61. };
  62. \endcode
  63. The \p draw() and \p handle() methods are
  64. described below. Like any widget, you can include additional
  65. private and public data in your class (such as scene graph
  66. information, etc.)
  67. \subsection opengl_draw The draw() Method
  68. The \p draw() method is where you actually do your OpenGL drawing:
  69. \code
  70. void MyWindow::draw() {
  71. if (!valid()) {
  72. ... set up projection, viewport, etc ...
  73. ... window size is in w() and h().
  74. ... valid() is turned on by FLTK after draw() returns
  75. }
  76. ... draw ...
  77. }
  78. \endcode
  79. \subsection opengl_handle The handle() Method
  80. The \p handle() method handles mouse and keyboard
  81. events for the window:
  82. \code
  83. int MyWindow::handle(int event) {
  84. switch(event) {
  85. case FL_PUSH:
  86. ... mouse down event ...
  87. ... position in Fl::event_x() and Fl::event_y()
  88. return 1;
  89. case FL_DRAG:
  90. ... mouse moved while down event ...
  91. return 1;
  92. case FL_RELEASE:
  93. ... mouse up event ...
  94. return 1;
  95. case FL_FOCUS :
  96. case FL_UNFOCUS :
  97. ... Return 1 if you want keyboard events, 0 otherwise
  98. return 1;
  99. case FL_KEYBOARD:
  100. ... keypress, key is in Fl::event_key(), ascii in Fl::event_text()
  101. ... Return 1 if you understand/use the keyboard event, 0 otherwise...
  102. return 1;
  103. case FL_SHORTCUT:
  104. ... shortcut, key is in Fl::event_key(), ascii in Fl::event_text()
  105. ... Return 1 if you understand/use the shortcut event, 0 otherwise...
  106. return 1;
  107. default:
  108. // pass other events to the base class...
  109. return Fl_Gl_Window::handle(event);
  110. }
  111. }
  112. \endcode
  113. When \p handle() is called, the OpenGL context is not
  114. set up! If your display changes, you should call
  115. \p redraw() and let \p draw() do the work. Don't
  116. call any OpenGL drawing functions from inside \p handle()!
  117. You can call \e some OpenGL stuff like hit detection and texture
  118. loading functions by doing:
  119. \code
  120. case FL_PUSH:
  121. make_current(); // make OpenGL context current
  122. if (!valid()) {
  123. ... set up projection exactly the same as draw ...
  124. valid(1); // stop it from doing this next time
  125. }
  126. ... ok to call NON-DRAWING OpenGL code here, such as hit
  127. detection, loading textures, etc...
  128. \endcode
  129. Your main program can now create one of your windows by doing
  130. <tt>new MyWindow(...)</tt>.
  131. You can also use your new window class in
  132. \ref fluid "FLUID"
  133. by:
  134. -# Putting your class definition in a \p MyWindow.H file.
  135. -# Creating a Fl_Box widget in FLUID.
  136. -# In the widget panel fill in the "class" field with \p MyWindow.
  137. This will make FLUID produce constructors for your new class.
  138. -# In the "Extra Code" field put <tt>\#include "MyWindow.H"</tt>,
  139. so that the FLUID output file will compile.
  140. You must put <tt>glwindow->show()</tt> in your main code
  141. after calling \p show() on the window containing the
  142. OpenGL window.
  143. \section opengl_normal Using OpenGL in Normal FLTK Windows
  144. You can put OpenGL code into the \p draw() method, as described in
  145. \ref subclassing_drawing
  146. in the previous chapter, or into the code for a
  147. \ref common_boxtypes "boxtype"
  148. or other places with some care.
  149. Most importantly, before you show \e any windows,
  150. including those that don't have OpenGL drawing, you <B>must</B>
  151. initialize FLTK so that it knows it is going to use OpenGL. You
  152. may use any of the symbols described for \p Fl_Gl_Window::mode()
  153. to describe how you intend to use OpenGL:
  154. \code
  155. Fl::gl_visual(FL_RGB);
  156. \endcode
  157. \anchor opengl_gl_start
  158. \anchor opengl_gl_finish
  159. You can then put OpenGL drawing code anywhere you can draw
  160. normally by surrounding it with
  161. gl_start() and gl_finish() to set up, and later release, an OpenGL
  162. context with an orthographic projection so that 0,0 is the
  163. lower-left corner of the window and each pixel is one unit. The
  164. current clipping is reproduced with OpenGL \p glScissor()
  165. commands. These functions also synchronize the OpenGL graphics stream
  166. with the drawing done by other X, WIN32, or FLTK functions.
  167. \code
  168. gl_start();
  169. ... put your OpenGL code here ...
  170. gl_finish();
  171. \endcode
  172. The same context is reused each time. If your code changes
  173. the projection transformation or anything else you should use
  174. \p glPushMatrix() and \p glPopMatrix() functions to
  175. put the state back before calling \p gl_finish().
  176. You may want to use <tt>Fl_Window::current()-\>h()</tt> to
  177. get the drawable height so that you can flip the Y
  178. coordinates.
  179. Unfortunately, there are a bunch of limitations you must
  180. adhere to for maximum portability:
  181. \li You must choose a default visual with Fl::gl_visual().
  182. \li You cannot pass \p FL_DOUBLE to Fl::gl_visual().
  183. \li You cannot use Fl_Double_Window or Fl_Overlay_Window.
  184. Do \e not call \p gl_start() or
  185. \p gl_finish() when drawing into an Fl_Gl_Window !
  186. \section opengl_drawing OpenGL Drawing Functions
  187. FLTK provides some useful OpenGL drawing functions. They can
  188. be freely mixed with any OpenGL calls, and are defined by
  189. including \p <FL/gl.h> which you should include
  190. instead of the OpenGL header \p <GL/gl.h>.
  191. void gl_color(Fl_Color)
  192. \par
  193. Sets the current OpenGL color to a FLTK color. <I>For
  194. color-index modes it will use \p fl_xpixel(c), which is
  195. only right if this window uses the default colormap!</I>
  196. void gl_rect(int x, int y, int w, int h) <br>
  197. void gl_rectf(int x, int y, int w, int h)
  198. \par
  199. Outlines or fills a rectangle with the current color. If
  200. Fl_Gl_Window::ortho() has been called, then the rectangle will exactly
  201. fill the pixel rectangle passed.
  202. void gl_font(Fl_Font fontid, int size)
  203. \par
  204. Sets the current OpenGL font to the same font you get by calling
  205. \ref ssect_Fonts "fl_font()".
  206. int gl_height() <br>
  207. int gl_descent() <br>
  208. float gl_width(const char *s) <br>
  209. float gl_width(const char *s, int n) <br>
  210. float gl_width(uchar c)
  211. \par
  212. Returns information about the current OpenGL font.
  213. void gl_draw(const char *s) <br>
  214. void gl_draw(const char *s, int n)
  215. \par
  216. Draws a nul-terminated string or an array of \p n
  217. characters in the current OpenGL font at the current raster
  218. position.
  219. void gl_draw(const char *s, int x, int y) <br>
  220. void gl_draw(const char *s, int n, int x, int y) <br>
  221. void gl_draw(const char *s, float x, float y) <br>
  222. void gl_draw(const char *s, int n, float x, float y)
  223. \par
  224. Draws a nul-terminated string or an array of \p n
  225. characters in the current OpenGL font at the given position.
  226. void gl_draw(const char *s, int x, int y, int w, int h, Fl_Align)
  227. \par
  228. Draws a string formatted into a box, with newlines and tabs
  229. expanded, other control characters changed to ^X, and aligned
  230. with the edges or center. Exactly the same output as
  231. \ref ssect_Text "fl_draw()".
  232. \section opengl_speed Speeding up OpenGL
  233. Performance of Fl_Gl_Window may be improved on some types of
  234. OpenGL implementations, in particular MESA and other software
  235. emulators, by setting the \p GL_SWAP_TYPE environment
  236. variable. This variable declares what is in the backbuffer after
  237. you do a swapbuffers.
  238. \li <tt>setenv GL_SWAP_TYPE COPY</tt> <br>
  239. <br>
  240. This indicates that the back buffer is copied to the
  241. front buffer, and still contains its old data. This is
  242. true of many hardware implementations. Setting this
  243. will speed up emulation of overlays, and widgets that
  244. can do partial update can take advantage of this as
  245. \p damage() will not be cleared to -1.
  246. \li <tt>setenv GL_SWAP_TYPE NODAMAGE</tt> <br>
  247. <br>
  248. This indicates that nothing changes the back buffer
  249. except drawing into it. This is true of MESA and Win32
  250. software emulation and perhaps some hardware emulation
  251. on systems with lots of memory.
  252. \li All other values for \p GL_SWAP_TYPE, and not
  253. setting the variable, cause FLTK to assume that the
  254. back buffer must be completely redrawn after a swap.
  255. This is easily tested by running the \ref examples_gl_overlay demo
  256. program and seeing if the display is correct when you drag
  257. another window over it or if you drag the window off the screen
  258. and back on. You have to exit and run the program again for it
  259. to see any changes to the environment variable.
  260. \section opengl_optimizer Using OpenGL Optimizer with FLTK
  261. <A href="http://www.sgi.com/software/optimizer">OpenGL Optimizer</A>
  262. is a scene graph toolkit for OpenGL available from
  263. Silicon Graphics for IRIX and Microsoft Windows. It allows you
  264. to view large scenes without writing a lot of OpenGL code.
  265. \par OptimizerWindow Class Definition
  266. \par
  267. To use
  268. <A href="http://www.sgi.com/software/optimizer">OpenGL Optimizer</A>
  269. with FLTK you'll need to create a
  270. subclass of Fl_Gl_Widget that includes several state
  271. variables:
  272. \code
  273. class OptimizerWindow : public Fl_Gl_Window {
  274. csContext *context_; // Initialized to 0 and set by draw()...
  275. csDrawAction *draw_action_; // Draw action...
  276. csGroup *scene_; // Scene to draw...
  277. csCamara *camera_; // Viewport for scene...
  278. void draw();
  279. public:
  280. OptimizerWindow(int X, int Y, int W, int H, const char *L)
  281. : Fl_Gl_Window(X, Y, W, H, L) {
  282. context_ = (csContext *)0;
  283. draw_action_ = (csDrawAction *)0;
  284. scene_ = (csGroup *)0;
  285. camera_ = (csCamera *)0;
  286. }
  287. void scene(csGroup *g) { scene_ = g; redraw(); }
  288. void camera(csCamera *c) {
  289. camera_ = c;
  290. if (context_) {
  291. draw_action_->setCamera(camera_);
  292. camera_->draw(draw_action_);
  293. redraw();
  294. }
  295. }
  296. };
  297. \endcode
  298. \par The camera() Method
  299. \par
  300. The \p camera() method sets the camera (projection and
  301. viewpoint) to use when drawing the scene. The scene is redrawn after
  302. this call.
  303. \par The draw() Method
  304. \par
  305. The \p draw() method performs the needed initialization and does
  306. the actual drawing:
  307. \code
  308. void OptimizerWindow::draw() {
  309. if (!context_) {
  310. // This is the first time we've been asked to draw; create the
  311. // Optimizer context for the scene...
  312. #ifdef WIN32
  313. context_ = new csContext((HDC)fl_getHDC());
  314. context_->ref();
  315. context_->makeCurrent((HDC)fl_getHDC());
  316. #else
  317. context_ = new csContext(fl_display, fl_visual);
  318. context_->ref();
  319. context_->makeCurrent(fl_display, fl_window);
  320. #endif // WIN32
  321. ... perform other context setup as desired ...
  322. // Then create the draw action to handle drawing things...
  323. draw_action_ = new csDrawAction;
  324. if (camera_) {
  325. draw_action_->setCamera(camera_);
  326. camera_->draw(draw_action_);
  327. }
  328. } else {
  329. #ifdef WIN32
  330. context_->makeCurrent((HDC)fl_getHDC());
  331. #else
  332. context_->makeCurrent(fl_display, fl_window);
  333. #endif // WIN32
  334. }
  335. if (!valid()) {
  336. // Update the viewport for this context...
  337. context_->setViewport(0, 0, w(), h());
  338. }
  339. // Clear the window...
  340. context_->clear(csContext::COLOR_CLEAR | csContext::DEPTH_CLEAR,
  341. 0.0f, // Red
  342. 0.0f, // Green
  343. 0.0f, // Blue
  344. 1.0f); // Alpha
  345. // Then draw the scene (if any)...
  346. if (scene_)
  347. draw_action_->apply(scene_);
  348. }
  349. \endcode
  350. \par The scene() Method
  351. \par
  352. The \p scene() method sets the scene to be drawn. The scene is
  353. a collection of 3D objects in a \p csGroup. The scene is redrawn
  354. after this call.
  355. \htmlonly
  356. <hr>
  357. <table summary="navigation bar" width="100%" border="0">
  358. <tr>
  359. <td width="45%" align="LEFT">
  360. <a class="el" href="subclassing.html">
  361. [Prev]
  362. Adding and Extending Widgets
  363. </a>
  364. </td>
  365. <td width="10%" align="CENTER">
  366. <a class="el" href="index.html">[Index]</a>
  367. </td>
  368. <td width="45%" align="RIGHT">
  369. <a class="el" href="fluid.html">
  370. Programming with FLUID
  371. [Next]
  372. </a>
  373. </td>
  374. </tr>
  375. </table>
  376. \endhtmlonly
  377. */