diff options
| author | Fabien Costantini <fabien@onepost.net> | 2008-10-14 22:12:25 +0000 |
|---|---|---|
| committer | Fabien Costantini <fabien@onepost.net> | 2008-10-14 22:12:25 +0000 |
| commit | 497afccb07164373e0de6639e754d7d691f1926f (patch) | |
| tree | 449d0b92ceb05f39617fe8fc2876d16eecde7460 /documentation/src/opengl.dox | |
| parent | e08fffdfe08bbc9320e39a15d162b6501abd4925 (diff) | |
Doxygen pdf man: First version added in documentation/fltk.pdf, old doc removed, images, dox files moved to a new src directory.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6431 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'documentation/src/opengl.dox')
| -rw-r--r-- | documentation/src/opengl.dox | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/documentation/src/opengl.dox b/documentation/src/opengl.dox new file mode 100644 index 000000000..bed6b5d5c --- /dev/null +++ b/documentation/src/opengl.dox @@ -0,0 +1,459 @@ +/** + + \page opengl 8 - Using OpenGL + +This chapter discusses using FLTK for your OpenGL applications. + +\section opengl_using Using OpenGL in FLTK + +The easiest way to make an OpenGL display is to subclass +<A href="Fl_Gl_Window.html#Fl_Gl_Window"><tt>Fl_Gl_Window</tt></A>. +Your subclass must implement a <tt>draw()</tt> method which uses +OpenGL calls to draw the display. Your main program should call +<tt>redraw()</tt> when the display needs to change, and +(somewhat later) FLTK will call <tt>draw()</tt>. + +With a bit of care you can also use OpenGL to draw into +normal FLTK windows. This allows you to use Gouraud shading for +drawing your widgets. To do this you use the +<A href="#gl_start"><tt>gl_start()</tt></A> +and +<A href=#gl_finish><tt>gl_finish()</tt></A> +functions around your OpenGL code. + +You must include FLTK's <tt><FL/gl.h></tt> header +file. It will include the file <tt><GL/gl.h></tt>, define +some extra drawing functions provided by FLTK, and include the +<tt><windows.h></tt> header file needed by WIN32 +applications. + +\section opengl_subclass Making a Subclass of Fl_Gl_Window + +To make a subclass of Fl_Gl_Window, you must provide: + +\li A class definition. + +\li A <tt>draw()</tt> method. + +\li A <tt>handle()</tt> method if you need to receive input from the user. + +If your subclass provides static controls in the window, they +must be redrawn whenever the <tt>FL_DAMAGE_ALL</tt> bit is set +in the value returned by <tt>damage()</tt>. For double-buffered +windows you will need to surround the drawing code with the +following code to make sure that both buffers are redrawn: + +\code +#ifndef MESA +glDrawBuffer(GL_FRONT_AND_BACK); +#endif // !MESA +... draw stuff here ... +#ifndef MESA +glDrawBuffer(GL_BACK); +#endif // !MESA +\endcode + +<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" CELLSPACING="0" BGCOLOR="#cccccc"> +<TR> + <TD><B>Note:</B> + + <P>If you are using the Mesa graphics library, the call + to <tt>glDrawBuffer()</tt> is not required and will slow + down drawing considerably. The preprocessor instructions + shown above will optimize your code based upon the + graphics library used. + + </TD> + +</TR> +</TABLE></CENTER> + +\subsection opengl_defining Defining the Subclass + +To define the subclass you just subclass the <tt>Fl_Gl_Window</tt> class: + +\code +class MyWindow : public Fl_Gl_Window { + void draw(); + int handle(int); + +public: + MyWindow(int X, int Y, int W, int H, const char *L) + : Fl_Gl_Window(X, Y, W, H, L) {} +}; +\endcode + +The <tt>draw()</tt> and <tt>handle()</tt> methods are +described below. Like any widget, you can include additional +private and public data in your class (such as scene graph +information, etc.) + +\subsection opengl_draw The draw() Method + +The <tt>draw()</tt> method is where you actually do your OpenGL drawing: + +\code +void MyWindow::draw() { + if (!valid()) { + ... set up projection, viewport, etc ... + ... window size is in w() and h(). + ... valid() is turned on by FLTK after draw() returns + } + ... draw ... +} +\endcode + +\subsection opengl_handle The handle() Method + +The <tt>handle()</tt> method handles mouse and keyboard +events for the window: + +\code +int MyWindow::handle(int event) { + switch(event) { + case FL_PUSH: + ... mouse down event ... + ... position in Fl::event_x() and Fl::event_y() + return 1; + case FL_DRAG: + ... mouse moved while down event ... + return 1; + case FL_RELEASE: + ... mouse up event ... + return 1; + case FL_FOCUS : + case FL_UNFOCUS : + ... Return 1 if you want keyboard events, 0 otherwise + return 1; + case FL_KEYBOARD: + ... keypress, key is in Fl::event_key(), ascii in Fl::event_text() + ... Return 1 if you understand/use the keyboard event, 0 otherwise... + return 1; + case FL_SHORTCUT: + ... shortcut, key is in Fl::event_key(), ascii in Fl::event_text() + ... Return 1 if you understand/use the shortcut event, 0 otherwise... + return 1; + default: + // pass other events to the base class... + return Fl_Gl_Window::handle(event); + } +} +\endcode + +When <tt>handle()</tt> is called, the OpenGL context is not +set up! If your display changes, you should call +<tt>redraw()</tt> and let <tt>draw()</tt> do the work. Don't +call any OpenGL drawing functions from inside <tt>handle()</tt>! + +You can call <I>some</I> OpenGL stuff like hit detection and texture +loading functions by doing: + +\code + case FL_PUSH: + make_current(); // make OpenGL context current + if (!valid()) { + + ... set up projection exactly the same as draw ... + + valid(1); // stop it from doing this next time + } + ... ok to call NON-DRAWING OpenGL code here, such as hit + detection, loading textures, etc... +\endcode + +Your main program can now create one of your windows by doing +<tt>new MyWindow(...)</tt>. You can also use +<A href="fluid.html#FLUID">FLUID</A> +by: + +-# Putting your class definition in a <tt>MyWindow.H</tt> file. + <br> +-# Creating a <tt>Fl_Box</tt> widget in FLUID. + <br> +-# In the widget panel fill in the "class" field with <tt>MyWindow</tt>. + This will make FLUID produce constructors for your new class. + <br> +-# In the "Extra Code" field put <tt>\#include "MyWindow.H"</tt>, + so that the FLUID output file will compile. + +You must put <tt>glwindow->show()</tt> in your main code +after calling <tt>show()</tt> on the window containing the +OpenGL window. + +\section opengl_normal Using OpenGL in Normal FLTK Windows + +You can put OpenGL code into an +<A href="subclassing.html#draw"><tt>Fl_Widget::draw()</tt></A> +method or into the code for a +<A href="common.html#boxtypes">boxtype</A> +or other places with some care. + +Most importantly, before you show <I>any</I> windows, +including those that don't have OpenGL drawing, you <B>must</B> +initialize FLTK so that it knows it is going to use OpenGL. You +may use any of the symbols described for Fl_Gl_Window::mode() +to describe how you intend to use OpenGL: + +\code +Fl::gl_visual(FL_RGB); +\endcode + +You can then put OpenGL drawing code anywhere you can draw +normally by surrounding it with: + +\code +gl_start(); +... put your OpenGL code here ... +gl_finish(); +\endcode + +<A name="gl_start"><tt>gl_start()</tt></A> +and +<A name="gl_finish"><tt>gl_finish()</tt></A> +set up an OpenGL +context with an orthographic projection so that 0,0 is the +lower-left corner of the window and each pixel is one unit. The +current clipping is reproduced with OpenGL <tt>glScissor()</tt> +commands. These functions also synchronize the OpenGL graphics stream +with the drawing done by other X, WIN32, or FLTK functions. + +The same context is reused each time. If your code changes +the projection transformation or anything else you should use +<tt>glPushMatrix()</tt> and <tt>glPopMatrix()</tt> functions to +put the state back before calling <tt>gl_finish()</tt>. + +You may want to use Fl_Window::current()->h() to +get the drawable height so that you can flip the Y +coordinates. + +Unfortunately, there are a bunch of limitations you must +adhere to for maximum portability: + +\li You must choose a default visual with Fl::gl_visual(). + +\li You cannot pass <tt>FL_DOUBLE</tt> to Fl::gl_visual(). + +\li You cannot use Fl_Double_Window or Fl_Overlay_Window. + +Do <I>not</I> call <tt>gl_start()</tt> or +<tt>gl_finish()</tt> when drawing into an Fl_Gl_Window ! + +\section opengl_drawing OpenGL Drawing Functions + +FLTK provides some useful OpenGL drawing functions. They can +be freely mixed with any OpenGL calls, and are defined by +including <FL/gl.H> which you should include +instead of the OpenGL header <tt><GL/gl.h></tt>. + +void gl_color(Fl_Color) + +\par +Sets the current OpenGL color to a FLTK color. <I>For +color-index modes it will use <tt>fl_xpixel(c)</tt>, which is +only right if this window uses the default colormap!</I> + +void gl_rect(int x, int y, int w, int h) <br> +void gl_rectf(int x, int y, int w, int h) + +\par +Outlines or fills a rectangle with the current color. If +Fl_Gl_Window::ortho() has been called, then the rectangle will exactly +fill the pixel rectangle passed. + +void gl_font(Fl_Font fontid, int size) + +\par +Sets the current OpenGL font to the same font you get by calling +<A href="drawing.html#fl_font"><tt>fl_font()</tt></A>. + +int gl_height() <br> +int gl_descent() <br> +float gl_width(const char *) <br> +float gl_width(const char *, int n) <br> +float gl_width(uchar) + +\par +Returns information about the current OpenGL font. + +void gl_draw(const char *) <br> +void gl_draw(const char *, int n) + +\par +Draws a nul-terminated string or an array of <tt>n</tt> +characters in the current OpenGL font at the current raster +position. + +void gl_draw(const char *, int x, int y) <br> +void gl_draw(const char *, int n, int x, int y) <br> +void gl_draw(const char *, float x, float y) <br> +void gl_draw(const char *, int n, float x, float y) + +\par +Draws a nul-terminated string or an array of <tt>n</tt> +characters in the current OpenGL font at the given position. + +void gl_draw(const char *, int x, int y, int w, int h, Fl_Align) + +\par +Draws a string formatted into a box, with newlines and tabs +expanded, other control characters changed to ^X, and aligned +with the edges or center. Exactly the same output as +<A href="drawing.html#text"><tt>fl_draw()</tt></A>. + +\section opengl_speed Speeding up OpenGL + +Performance of Fl_Gl_Window may be improved on some types of +OpenGL implementations, in particular MESA and other software +emulators, by setting the <tt>GL_SWAP_TYPE</tt> environment +variable. This variable declares what is in the backbuffer after +you do a swapbuffers. + +\li <tt>setenv GL_SWAP_TYPE COPY</tt> <br> + <br> + This indicates that the back buffer is copied to the + front buffer, and still contains it's old data. This is + true of many hardware implementations. Setting this + will speed up emulation of overlays, and widgets that + can do partial update can take advantage of this as + damage() will not be cleared to -1. <p> + +\li <tt>setenv GL_SWAP_TYPE NODAMAGE</tt> <br> + <br> + This indicates that nothing changes the back buffer + except drawing into it. This is true of MESA and Win32 + software emulation and perhaps some hardware emulation + on systems with lots of memory. <p> + +\li All other values for <tt>GL_SWAP_TYPE</tt>, and not + setting the variable, cause FLTK to assume that the + back buffer must be completely redrawn after a swap. + +This is easily tested by running the <tt>gl_overlay</tt> demo +program and seeing if the display is correct when you drag +another window over it or if you drag the window off the screen +and back on. You have to exit and run the program again for it +to see any changes to the environment variable. + +\section opengl_optimizer Using OpenGL Optimizer with FLTK + +<A href="http://www.sgi.com/software/optimizer">OpenGL Optimizer</A> +is a scene graph toolkit for OpenGL available from +Silicon Graphics for IRIX and Microsoft Windows. It allows you +to view large scenes without writing a lot of OpenGL code. + +\par OptimizerWindow Class Definition + +\par +To use OpenGL Optimizer with FLTK you'll need to create a +subclass of <tt>Fl_Gl_Widget</tt> that includes several state +variables: + +\code +class OptimizerWindow : public Fl_Gl_Window { + csContext *context_; // Initialized to 0 and set by draw()... + csDrawAction *draw_action_; // Draw action... + csGroup *scene_; // Scene to draw... + csCamara *camera_; // Viewport for scene... + + void draw(); + +public: + OptimizerWindow(int X, int Y, int W, int H, const char *L) + : Fl_Gl_Window(X, Y, W, H, L) { + context_ = (csContext *)0; + draw_action_ = (csDrawAction *)0; + scene_ = (csGroup *)0; + camera_ = (csCamera *)0; + } + + void scene(csGroup *g) { scene_ = g; redraw(); } + + void camera(csCamera *c) { + camera_ = c; + if (context_) { + draw_action_->setCamera(camera_); + camera_->draw(draw_action_); + redraw(); + } + } +}; +\endcode + +\par The camera() Method + +\par +The <tt>camera()</tt> method sets the camera (projection and +viewpoint) to use when drawing the scene. The scene is redrawn after +this call. + +\par The draw() Method + +\par +The <tt>draw()</tt> method performs the needed initialization and does +the actual drawing: + +\code +void OptimizerWindow::draw() { + if (!context_) { + // This is the first time we've been asked to draw; create the + // Optimizer context for the scene... + +#ifdef WIN32 + context_ = new csContext((HDC)fl_getHDC()); + context_->ref(); + context_->makeCurrent((HDC)fl_getHDC()); +#else + context_ = new csContext(fl_display, fl_visual); + context_->ref(); + context_->makeCurrent(fl_display, fl_window); +#endif // WIN32 + + ... perform other context setup as desired ... + + // Then create the draw action to handle drawing things... + + draw_action_ = new csDrawAction; + if (camera_) { + draw_action_->setCamera(camera_); + camera_->draw(draw_action_); + } + } else { +#ifdef WIN32 + context_->makeCurrent((HDC)fl_getHDC()); +#else + context_->makeCurrent(fl_display, fl_window); +#endif // WIN32 + } + + if (!valid()) { + // Update the viewport for this context... + context_->setViewport(0, 0, w(), h()); + } + + // Clear the window... + context_->clear(csContext::COLOR_CLEAR | csContext::DEPTH_CLEAR, + 0.0f, // Red + 0.0f, // Green + 0.0f, // Blue + 1.0f); // Alpha + + // Then draw the scene (if any)... + if (scene_) + draw_action_->apply(scene_); +} +\endcode + +\par The scene() Method + +\par +The <tt>scene()</tt> method sets the scene to be drawn. The scene is +a collection of 3D objects in a <tt>csGroup</tt>. The scene is redrawn +after this call. + +\htmlonly +<hr> +<a class="el" href="index.html">[Index]</a> +<a class="el" href="subclassing.html">[Previous] 7 - Adding and Extending Widgets</a> +<a class="el" href="fluid.html">[Next] 9 - Programming with FLUID</a> +\endhtmlonly +*/ |
