From 501690edce2cecc356334fc42e7f429907cdfa1e Mon Sep 17 00:00:00 2001 From: Fabien Costantini Date: Fri, 17 Oct 2008 11:08:15 +0000 Subject: Last test does keep history, lets add all related files and patch them afterwards... git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6447 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- documentation/src_doc/opengl.dox | 459 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 documentation/src_doc/opengl.dox (limited to 'documentation/src_doc/opengl.dox') diff --git a/documentation/src_doc/opengl.dox b/documentation/src_doc/opengl.dox new file mode 100644 index 000000000..bed6b5d5c --- /dev/null +++ b/documentation/src_doc/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 +Fl_Gl_Window. +Your subclass must implement a draw() method which uses +OpenGL calls to draw the display. Your main program should call +redraw() when the display needs to change, and +(somewhat later) FLTK will call draw(). + +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 +gl_start() +and +gl_finish() +functions around your OpenGL code. + +You must include FLTK's header +file. It will include the file , define +some extra drawing functions provided by FLTK, and include the + 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 draw() method. + +\li A handle() 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 FL_DAMAGE_ALL bit is set +in the value returned by damage(). 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 + +
+ + + + +
Note: + +

If you are using the Mesa graphics library, the call + to glDrawBuffer() is not required and will slow + down drawing considerably. The preprocessor instructions + shown above will optimize your code based upon the + graphics library used. + +

+ +\subsection opengl_defining Defining the Subclass + +To define the subclass you just subclass the Fl_Gl_Window 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 draw() and handle() 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 draw() 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 handle() 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 handle() is called, the OpenGL context is not +set up! If your display changes, you should call +redraw() and let draw() do the work. Don't +call any OpenGL drawing functions from inside handle()! + +You can call some 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 +new MyWindow(...). You can also use +FLUID +by: + +-# Putting your class definition in a MyWindow.H file. +
+-# Creating a Fl_Box widget in FLUID. +
+-# In the widget panel fill in the "class" field with MyWindow. + This will make FLUID produce constructors for your new class. +
+-# In the "Extra Code" field put \#include "MyWindow.H", + so that the FLUID output file will compile. + +You must put glwindow->show() in your main code +after calling show() on the window containing the +OpenGL window. + +\section opengl_normal Using OpenGL in Normal FLTK Windows + +You can put OpenGL code into an +Fl_Widget::draw() +method or into the code for a +boxtype +or other places with some care. + +Most importantly, before you show any windows, +including those that don't have OpenGL drawing, you must +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 + +gl_start() +and +gl_finish() +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 glScissor() +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 +glPushMatrix() and glPopMatrix() functions to +put the state back before calling gl_finish(). + +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 FL_DOUBLE to Fl::gl_visual(). + +\li You cannot use Fl_Double_Window or Fl_Overlay_Window. + +Do not call gl_start() or +gl_finish() 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 which you should include +instead of the OpenGL header . + +void gl_color(Fl_Color) + +\par +Sets the current OpenGL color to a FLTK color. For +color-index modes it will use fl_xpixel(c), which is +only right if this window uses the default colormap! + +void gl_rect(int x, int y, int w, int h)
+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 +fl_font(). + +int gl_height()
+int gl_descent()
+float gl_width(const char *)
+float gl_width(const char *, int n)
+float gl_width(uchar) + +\par +Returns information about the current OpenGL font. + +void gl_draw(const char *)
+void gl_draw(const char *, int n) + +\par +Draws a nul-terminated string or an array of n +characters in the current OpenGL font at the current raster +position. + +void gl_draw(const char *, int x, int y)
+void gl_draw(const char *, int n, int x, int y)
+void gl_draw(const char *, float x, float y)
+void gl_draw(const char *, int n, float x, float y) + +\par +Draws a nul-terminated string or an array of n +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 +fl_draw(). + +\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 GL_SWAP_TYPE environment +variable. This variable declares what is in the backbuffer after +you do a swapbuffers. + +\li setenv GL_SWAP_TYPE COPY
+
+ 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.

+ +\li setenv GL_SWAP_TYPE NODAMAGE
+
+ 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.

+ +\li All other values for GL_SWAP_TYPE, 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 gl_overlay 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 + +OpenGL Optimizer +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 Fl_Gl_Widget 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 camera() 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 draw() 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 scene() method sets the scene to be drawn. The scene is +a collection of 3D objects in a csGroup. The scene is redrawn +after this call. + +\htmlonly +


+[Index]    +[Previous]  7 - Adding and Extending Widgets  +[Next]  9 - Programming with FLUID  +\endhtmlonly +*/ -- cgit v1.2.3