summaryrefslogtreecommitdiff
path: root/documentation/opengl.html
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/opengl.html')
-rw-r--r--documentation/opengl.html486
1 files changed, 486 insertions, 0 deletions
diff --git a/documentation/opengl.html b/documentation/opengl.html
new file mode 100644
index 000000000..e26895a2c
--- /dev/null
+++ b/documentation/opengl.html
@@ -0,0 +1,486 @@
+<HTML>
+<BODY>
+
+<H1 ALIGN=RIGHT><A NAME="opengl">7 - Using OpenGL</A></H1>
+
+This chapter discusses using FLTK for your OpenGL applications.
+
+<H2>The OpenGL Widget</H2>
+
+<H2>Making a Simple OpenGL Wrapper Widget</H2>
+
+<H2>A Simple Flight Simulator</H2>
+
+<H2>Using FLTK with OpenGL Optimizer</H2>
+
+<H2>Using OpenGL Optimizer for the Flight Simulator</H2>
+
+</BODY>
+</HTML>
+<title>Using OpenGL in Fltk</title>
+
+<h2>Using OpenGL in Fltk<br>#include &lt;FL/gl.h></h2>
+
+The easiest way to make an OpenGL display is to subclass Fl_Gl_Window.
+Your subclass should implement a draw() method which uses OpenGL calls
+to draw the display. Your main program should call w->redraw() when
+the display needs to change, and (somewhat later) fltk will call
+draw().
+
+<p>With a bit of care you can also use OpenGL to draw into normal fltk
+windows. This is mostly useful because you can access Gourand shading
+for drawing your widgets. To do this you use the <a
+href=#gl_start>gl_start() and gl_finish()</a> functions around your
+OpenGL code.
+
+<p>You must include fltk's &lt;FL/gl.h> header file. It will include
+the file &lt;GL/gl.h>, plus it defines some extra drawing functions
+provided by fltk, and also gets around a horrid screwup by our friends
+in Seattle.
+
+<h2>Sample code for subclassing Fl_Gl_Window</h2>
+
+<p><pre>
+ 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) {}
+ };
+
+ 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 ...
+ }
+
+ 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_KEYBOARD:
+ ... keypress, key is in Fl::event_key(), ascii in Fl::event_text()
+ return 1;
+ default:
+ // tell fltk that I don't understand other events
+ return 0;
+ }
+ }
+</pre>
+
+<p>When handle() is called, the glx context is not set up! If your
+display changes, you should call redraw() and let draw() do the work.
+Don't call any gl functions from inside handle()!
+
+<p>This may mean you cannot call some OpenGl stuff like hit detection.
+You can fix this by doing:
+
+<p><pre>
+ case FL_PUSH:
+ make_current(); // make glx 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 ...
+</pre>
+
+<p>Your main program can now create one of your windows by doing "new
+MyWindow(...)". You can also use <a href=fluid.html>fluid</a>:
+
+<ol>
+<li>Put your class definition in a MyWindow.H file.
+<li>In fluid create a box object, resize & place where you want.
+<li>In the control panel, fill in the "class" field with MyWindow.H.
+This will make fluid produce constructors for your new class.
+<li>In the "extra code" put "#include "MyWindow.H"", so that the fluid
+output file will compile.
+</ol>
+
+<p>You must put glwindow->show() in your main code after calling
+show() on the window containing the gl window.
+
+<p><hr>
+<h2>class Fl_Gl_Window : public <a href=Fl_Window.html>Fl_Window</a></h2>
+
+<p>An Fl_Gl_Window sets things up so OpenGL works, and also keeps an
+OpenGL "context" for that window, so that changes to the lighting and
+projection may be reused between redraws. Fl_Gl_Window also flushes
+the OpenGL streams and swaps buffers after draw() returns.
+
+<p>Fl_Gl_Window::draw() is a pure virtual method. You must subclass
+Fl_Gl_Window and provide an implementation for draw(). You may also
+provide an implementation of draw_overlay() if you want to draw into
+the overlay planes. You can avoid reinitializing the viewport and
+lights and other things by checking valid() at the start of draw() and
+only doing the initialization if it is false.
+
+<p>The draw() method can <i>only</i> use OpenGL calls. Do not attempt to
+call X, any of the functions in &lt;FL/fl_draw.H>, or glX directly. Do
+not call gl_start() or gl_finish().
+
+<h2>Methods:</h2>
+
+<h4><code>Fl_Gl_Window::Fl_Gl_Window(int W, int H, const char *l=0);
+<br>Fl_Gl_Window::Fl_Gl_Window(int X, int Y, int W, int H, const char
+*l=0)</code></h4><ul>
+
+The constructors. Fl_Gl_Window::mode() defaults to
+<code>FL_RGB|FL_DOUBLE|FL_DEPTH</code>.
+
+<a name=mode>
+</ul><h4><code>const int Fl_Gl_Window::mode() const;
+<br>int Fl_Gl_Window::mode(int);</code></h4><ul>
+
+Set or change the OpenGL capabilites of the window. The value can be
+any of the following or'd together:
+
+<p><ul>
+<li><code>FL_RGB</code> - Color (not indexed)
+<li><code>FL_RGB8</code> - Color with at least 8 bits of each color
+<li><code>FL_INDEX</code> - Indexed mode
+<li><code>FL_SINGLE</code> - not double buffered
+<li><code>FL_DOUBLE</code> - double buffered
+<li><code>FL_ACCUM</code> - accumulation buffer
+<li><code>FL_ALPHA</code> - alpha channel in color
+<li><code>FL_DEPTH</code> - depth buffer
+<li><code>FL_STENCIL</code> - stencil buffer
+<li><code>FL_MULTISAMPLE</code> - multisample antialiasing
+</ul>
+
+<p><code>FL_RGB</code> and <code>FL_SINGLE</code> have a
+value of zero, they are "on" <i>unless</i> you give
+<code>FL_INDEX</code> or <code>FL_DOUBLE</code>.
+
+<p>If the desired combination cannot be done, fltk will try turning off
+the <code>FL_MULTISAMPLE</code>. If this also fails show() will call
+Fl::error() and not show the window.
+
+<p>You can change the mode while the window is displayed. This
+is most useful for turning double-buffering on and off. <i>Under
+X this will cause the old X window to be destroyed and a new one
+created. If this is a top-level window this will unfortunately also
+cause the window to blink, raise to the top, and be de-iconized, and
+the xid() will change, possibly breaking other code. It is best to
+make the GL window a child of another window if you wish to do this!</i>
+
+</ul><h4><code>int Fl_Gl_Window::mode(const int *);</code></h4><ul>
+
+<p><i>This call only works on systems using glX.</i> This value is
+passed unchanged to glXChooseVisual(), superceeding the value
+calculated from mode(int). See "man glXChooseVisual" if you wish to
+construct your own mode. Fltk assummes that the pointer is to static
+const data, and caches the pointer with the found visual.
+glXChooseVisual is not called until show() or can_do()
+is called. To restore the use of mode(int), call
+<code>mode((int*)0)</code>.
+
+</ul><h4><code>static int Fl_Gl_Window::can_do(int);
+<br>static int Fl_Gl_Window::can_do(const int *mode);
+<br>int Fl_Gl_Window::can_do() const;</code></h4><ul>
+
+Returns non-zero if show() will not call Fl::error() if called with
+the given or current mode.
+
+</ul><h4><code>char Fl_Gl_Window::valid() const;
+<br>void Fl_Gl_Window::invalidate();
+<br>void Fl_Gl_Window::valid(char i);</code></h4><ul>
+
+<code>Fl_Gl_Window::valid()</code> is turned off when fltk creates a
+new context for this window and by the window resizing, and is turned
+on <i>after</i> draw() is called. You can use this inside your draw()
+method to avoid unneccessarily initializing the OpenGL context. Just
+do this:
+
+<ul><pre><code>void mywindow::draw() {
+ if (!valid()) {
+ glViewport(0,0,w(),h());
+ glFrustum(...);
+ glLight(...);
+ ...other initilization...
+ }
+ ... draw your geometry here ...
+}
+</code></pre></ul>
+
+<p>You can also turn valid() off yourself (for instance if you know
+the current projection has changed). To do this call
+<code>invalidate()</code>.
+
+<p>You can turn valid() on by calling valid(1). You should only do
+this after fixing the transformation inside a draw() or after
+make_current(). This is done automatically after draw() returns.
+
+</ul><h4><code>void Fl_Gl_Window::ortho();</code></h4><ul>
+
+Set the projection so 0,0 is in the lower left of the window and each
+pixel is 1 unit wide/tall. If you are drawing 2D images, your draw()
+method may want to call this if valid() is false.
+
+</ul><h4><code>void Fl_Gl_Window::make_current();
+<br>void Fl_Gl_Window::make_overlay_current();
+<br>void Fl_Gl_Window::swap_buffers();</code></h4><ul>
+
+These functions can be used to set the current GL context to a window
+and draw into it incrementally, rather than using the draw() method.
+You will also need to call make_current() to do OpenGL feedback or hit
+detection in response to events. After calling make_current(), be
+sure to test valid(), and if false, initialize the transformation and
+call valid(1).
+
+</ul><h4><code>void Fl_Gl_Window::hide();
+<br>Fl_Gl_Window::~Fl_Gl_Window();</code></h4><ul>
+
+Hiding the window or destroying it also destroys the OpenGL context it
+uses.
+
+</ul><h2>Fl_Gl_Window overlay</h2>
+
+GL hardware typically provides some overlay bit planes, which are very
+useful for drawing UI controls atop your 3D graphics. If the overlay
+hardware is not provided, fltk tries to simulate the overlay, this works
+pretty well if your graphics are double buffered, but not very well
+for single-buffered.
+
+</ul><h4><code>int Fl_Gl_Window::can_do_overlay();</code></h4><ul>
+
+Returns true if the hardware overlay is possible. If this is false,
+fltk will try to simulate the overlay, with significant loss of update
+speed. Calling this will cause fltk to open the display.
+
+</ul><h4><code>void Fl_Gl_Window::redraw_overlay();</code></h4><ul>
+
+Call this if what is drawn in the overlay needs to change, this will
+cause draw_overlay to be called at a later time. Initially the
+overlay is clear, if you want the window to display something in the
+overlay when it first appears, you must call this immediately after
+you show() your window.
+
+</ul><h4><code>virtual void Fl_Gl_Window::draw_overlay();</code></h4><ul>
+
+You must implement this virtual function if you want to draw into the
+overlay. The overlay is cleared before this is called. You should
+draw anything that is not clear, using OpenGl. You must use
+gl_color(i) to choose colors (it allocates them from the colormap
+using system-specific calls), and remember that you are in an indexed
+OpenGL mode and drawing anything other than flat-shaded will probably
+not work.
+
+<p>Both this function and Fl_Gl_Window::draw() must check
+Fl_Gl_Window::valid(), and set the same transformation. If you don't
+your code may not work on other systems. Depending on the OS, and on
+whether overlays are real or simulated, the OpenGL context may be the
+same or different between the overlay and main window.
+
+</ul><p><hr>
+<a name=gl_start>
+<h2>Using OpenGL in normal Fltk windows</h2>
+
+<p>You can put OpenGL code into an <a
+href=subclass.html#draw>Fl_Widget::draw()</a> method or into the code
+for a <a href=Boxtypes.html>boxtype</a> or other places, with some care.
+
+<p>Most important, before you show <i>any</i> windows (including those
+that don't have OpenGL drawing) you must initialize fltk/X so that it
+knows it is going to use OpenGL. You may use any of the symbols
+described for <a href=#mode>Fl_Gl_Window::mode()</a> to describe how
+you intend to use OpenGL:
+
+<ul><p><code> Fl::gl_visual(FL_RGB);</code></ul>
+
+<p>You can then put OpenGL drawing code anywhere you can draw normally
+by surrounding it with:
+
+<ul><p><code>gl_start();</code><br>
+<i>... put your OpenGL code here ...</i><br>
+<code>gl_finish();</code></ul>
+
+<p>gl_start() and gl_finish() set up a GL 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
+scissor commands. These also synchronize the OpenGL graphics stream
+with the drawing done by other X or fltk functions.
+
+<p>The same context is reused each time. If your code changes the
+projection transformation or anything else you should use glPush/glPop
+to put the state back before calling gl_finish().
+
+<p>You may want to use <code>Fl_Window::current()->h()</code> to get
+the drawable height so you can flip the coordinate system.
+
+<p>Unfortunately there are a bunch of limitations you must adhere to for
+maximum portability:<ul>
+
+<li>You must choose a default visual with <a
+href=Fl.html#gl_visual>Fl::gl_visual()</a>.
+
+<li>You cannot pass FL_DOUBLE to Fl::gl_visual().
+
+<li>You cannot use Fl_Double_Window (or Fl_Overlay_Window).
+
+</ul>
+
+<p>Do <i>not</i> call gl_start()/gl_finish() when drawing an
+Fl_Gl_Window!
+
+</ul><p><hr>
+<a name=drawing>
+<h2>OpenGL drawing functions
+<br>#include &lt;FL/gl_draw.H></h2>
+
+Fltk provides some useful gl drawing functions. They can be freely
+mixed with any OpenGL calls, and are defined by including &lt;FL/gl.H>
+(which you should include instead of the OpenGL header &lt;GL/gl.h>).
+
+</ul><h4><code>void gl_color(Fl_Color);</code></h4><ul>
+
+Set the current color to a fltk color index. <i>For color-index modes
+it will use fl_xpixel(c), which is only right if this window uses the
+default X colormap</i>.
+
+</ul><h4><code>void gl_rect(int x,int y,int w,int h);
+<br>void gl_rectf(int x,int y,int w,int h);</code></h4><ul>
+
+Outline or fill a rectangle with the current color. If ortho() has
+been called, then the rectangle will exactly fill the pixel rectangle
+passed.
+
+</ul><h4><code>void gl_font(Fl_Font fontid, int size);</code></h4><ul>
+
+Set the "current GL font" to the same font you get by calling
+<a href=Draw.html#fl_font>fl_font()</a>.
+
+</ul><h4><code>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);</code></h4><ul>
+
+Return information about the current GL font.
+
+</ul><h4><code>void gl_draw(const char *);
+<br>void gl_draw(const char *, int n);</code></h4><ul>
+
+Draw a null-terminated string or an array of <i>n</i> characters in
+the current GL font at the current glRasterPos.
+
+</ul><h4><code>void gl_draw(const char *, int x, int y);
+<br>void gl_draw(const char *, int n, int x, int y);</code></h4><ul>
+
+Draw a null-terminated string or an array of <i>n</i> characters in
+the current GL font at the given position.
+
+</ul><h4><code>void gl_draw(const char *, int x, int y, int w, int h, Fl_Align);</code></h4><ul>
+
+Draw 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=Draw.html#fl_draw>fl_draw()</a>.
+
+</ul>
+<p><a href = index.html>(back to contents)</a>
+<title>Fltk example: shape.C</title>
+<h2>shape.C</h2>
+
+<p>Of course GL is no fun unless you can draw your own graphics. This
+is done with a subclass that you create:
+
+<p><img src = shape.C.gif align=top>
+
+<pre>
+#include &lt;FL/Fl.H>
+#include &lt;FL/Fl_Window.H>
+#include &lt;FL/Fl_Hor_Slider.H>
+#include &lt;FL/math.h>
+#include &lt;FL/gl.h>
+#include &lt;FL/Fl_Gl_Window.H>
+
+class shape_window : public Fl_Gl_Window {
+ void draw();
+public:
+ int sides;
+ shape_window(int x,int y,int w,int h,const char *l=0);
+};
+
+shape_window::shape_window(int x,int y,int w,int h,const char *l) :
+Fl_Gl_Window(x,y,w,h,l) {
+ sides = 3;
+}
+
+void shape_window::draw() {
+ // the valid() property may be used to avoid reinitializing your
+ // GL transformation for each redraw:
+ if (!valid()) {
+ valid(1);
+ glLoadIdentity();
+ glViewport(0,0,w(),h());
+ }
+ // draw an amazing graphic:
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor3f(.5,.6,.7);
+ glBegin(GL_POLYGON);
+ for (int i=0; i&lt;sides; i++) {
+ double ang = i*2*M_PI/sides;
+ glVertex3f(cos(ang),sin(ang),0);
+ }
+ glEnd();
+}
+
+// when you change the data, as in this callback, you must call redraw():
+void sides_cb(Fl_Widget *o, void *p) {
+ shape_window *sw = (shape_window *)p;
+ sw->sides = int(((Fl_Slider *)o)->value());
+ sw->redraw();
+}
+
+int main(int argc, char **argv) {
+
+ Fl_Window window(300, 330);
+
+ shape_window sw(10, 10, 280, 280);
+ window.resizable(&sw);
+
+ Fl_Hor_Slider slider(50, 295, window.w()-60, 30, "Sides:");
+ slider.align(FL_ALIGN_LEFT);
+ slider.callback(sides_cb,&sw);
+ slider.value(sw.sides);
+ slider.step(1);
+ slider.bounds(3,40);
+
+ window.show(argc,argv);
+
+ return Fl::run();
+}
+</pre>
+
+<p>To do your own drawing, you must subclass <a
+href=Fl_Gl_Window.html>Fl_Gl_Window</a>. The virtual method <a
+href=subclass.html#draw>draw()</a> is called when the window should
+update. You can only draw into the window inside a draw() method.
+You call the method <a href=Fl_Widget.html#redraw>redraw()</a> on the
+window to indicate that draw() needs to be called. It won't actually
+be called until <a href=Fl.html#wait>Fl::wait()</a> is called.
+
+<P>The window may be made a child of another window, as it is here.
+This is done by add()ing it to a parent before you show() it. <i>If
+you don't want to make a child window, be sure to end() the previous
+window!</i> The Fl_Gl_Window constructor automatically does end() so
+you don't accidentally add children to it.
+
+<p>The files &lt;FL/math.h> and &lt;FL/gl.h> are wrappers for the
+normal header files. You should use them to port to MSWindows because
+the MicroSoft header files have errors or ommisions in them.
+
+<p><a href = index.html>[back to contents]</a>