367f908d8e
git-svn-id: file:///fltk/svn/fltk/trunk@187 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
361 lines
11 KiB
HTML
361 lines
11 KiB
HTML
<HTML>
|
|
<BODY>
|
|
|
|
<H1 ALIGN=RIGHT><A NAME="opengl">9 - Using OpenGL</A></H1>
|
|
|
|
This chapter discusses using FLTK for your OpenGL applications.
|
|
|
|
<h2>Using OpenGL in FLTK</h2>
|
|
|
|
The easiest way to make an OpenGL display is to subclass <a
|
|
href="#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>.
|
|
|
|
<p>With a bit of care you can also use OpenGL to draw into normal FLTK
|
|
windows. This is mostly useful because you can use Gourand 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.
|
|
|
|
<p>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.
|
|
|
|
<h2>Making a Subclass of Fl_Gl_Window</h2>
|
|
|
|
To make a subclass of Fl_Gl_Window, you must provide:
|
|
|
|
<ul>
|
|
|
|
<li>A class definition.
|
|
<li>A <tt>draw()</tt> method.
|
|
<li>A <tt>handle()</tt> method (if you need to recieve input from
|
|
the user).
|
|
</ul>
|
|
|
|
<h3>Defining the Subclass</h3>
|
|
|
|
To define the subclass you just subclass <tt>Fl_Gl_Window</tt> class:
|
|
|
|
<ul><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) {}
|
|
};
|
|
</pre></ul>
|
|
|
|
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.)
|
|
|
|
<h3>The draw() Method</H3>
|
|
|
|
The <tt>draw()</tt> method is where you actually do your OpenGL drawing:
|
|
|
|
<ul><pre>
|
|
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 ...
|
|
}
|
|
</pre></ul>
|
|
|
|
<h3>The handle() Method</h3>
|
|
|
|
The <tt>handle()</tt> method handles mouse and keyboard events for the
|
|
window:
|
|
|
|
<ul><pre>
|
|
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;
|
|
default:
|
|
// tell FLTK that I don't understand other events
|
|
return 0;
|
|
}
|
|
}
|
|
</pre></ul>
|
|
|
|
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>!
|
|
|
|
<p>You can call some OpenGL stuff like hit detection and texture loading
|
|
functions by doing:
|
|
|
|
<ul><pre>
|
|
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...
|
|
</pre></ul>
|
|
|
|
Your main program can now create one of your windows by doing <tt>new
|
|
MyWindow(...)</tt>. You can also use <a href="#fluid">fluid</a> by:
|
|
|
|
<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 <tt>#include "MyWindow.H"</tt>, so
|
|
that the fluid output file will compile.
|
|
|
|
</ol>
|
|
|
|
You must put <tt>glwindow->show()</tt> in your main code after calling
|
|
<tt>show()</tt> on the window containing the OpenGL window.
|
|
|
|
<h2>Using OpenGL in Normal FLTK Windows</h2>
|
|
|
|
You can put OpenGL code into an <a
|
|
href="#draw"><tt>Fl_Widget::draw()</tt></a> method or into the code for
|
|
a <a href="#boxtypes">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 so that it
|
|
knows it is going to use OpenGL. You may use any of the symbols
|
|
described for <a
|
|
href="#Fl_Gl_Window.mode"><tt>Fl_Gl_Window::mode()</tt></a> to describe
|
|
how you intend to use OpenGL:
|
|
|
|
<ul><pre>
|
|
Fl::gl_visual(FL_RGB);
|
|
</pre></ul>
|
|
|
|
You can then put OpenGL drawing code anywhere you can draw normally
|
|
by surrounding it with:
|
|
|
|
<ul><pre>
|
|
gl_start();
|
|
... put your OpenGL code here ...
|
|
gl_finish();
|
|
</pre></ul>
|
|
|
|
<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 also synchronize the
|
|
OpenGL graphics stream with the drawing done by other X, WIN32, or FLTK
|
|
functions.
|
|
|
|
<p>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>.
|
|
|
|
<p>You may want to use <tt>Fl_Window::current()->h()</tt> to get
|
|
the drawable height so you can flip the Y coordinates.
|
|
|
|
<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="#gl_visual"><tt>Fl::gl_visual()</tt></a>.
|
|
|
|
<li>You cannot pass <tt>FL_DOUBLE</tt> to <tt>Fl::gl_visual()</tt>.
|
|
|
|
<li>You cannot use <tt>Fl_Double_Window</tt> or
|
|
<tt>Fl_Overlay_Window</tt>.
|
|
|
|
</ul>
|
|
|
|
Do <i>not</i> call <tt>gl_start()</tt> or <tt>gl_finish()</tt> when drawing
|
|
into an <tt>Fl_Gl_Window</tt>!
|
|
|
|
<h2>OpenGL drawing functions</h2>
|
|
|
|
FLTK provides some useful OpenGL drawing functions. They can be freely
|
|
mixed with any OpenGL calls, and are defined by including
|
|
<tt><FL/gl.H></tt> (which you should include instead of the OpenGL
|
|
header <tt><GL/gl.h></tt>).
|
|
|
|
<h3>void gl_color(Fl_Color)</h3>
|
|
|
|
Set the current color to a FLTK color index. <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>
|
|
|
|
<h3>void gl_rect(int x, int y, int w, int h)<br>
|
|
void gl_rectf(int x, int y, int w, int h)</h3>
|
|
|
|
Outline or fill a rectangle with the current color. If
|
|
<tt>ortho()</tt> has been called, then the rectangle will exactly fill
|
|
the pixel rectangle passed.
|
|
|
|
<h3>void gl_font(Fl_Font fontid, int size)</h3>
|
|
|
|
Set the "current OpenGL font" to the same font you get by calling
|
|
<a href="#fl_font"><tt>fl_font()</tt></a>.
|
|
|
|
<h3>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)</h3>
|
|
|
|
Return information about the current OpenGL font.
|
|
|
|
<h3>void gl_draw(const char *)<br>
|
|
void gl_draw(const char *, int n)</h3>
|
|
|
|
Draw a nul-terminated string or an array of <tt>n</tt> characters in
|
|
the current OpenGL font at the current <tt>glRasterPos</tt>.
|
|
|
|
<h3>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)</h3>
|
|
|
|
Draw a nul-terminated string or an array of <tt>n</tt> characters in
|
|
the current OpenGL font at the given position.
|
|
|
|
<h3>void gl_draw(const char *, int x, int y, int w, int h, Fl_Align)</h3>
|
|
|
|
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="#fl_draw"><tt>fl_draw()</tt></a>.
|
|
|
|
<h2>Using OpenGL Optimizer with FLTK</h2>
|
|
|
|
<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. Versions are in the works for Solaris and
|
|
HP-UX. It allows you to view large scenes without writing a lot of
|
|
OpenGL code.
|
|
|
|
<h3>OptimizerWindow Class Definition</h3>
|
|
|
|
To use OpenGL Optimizer with FLTK you'll need to create a subclass of
|
|
<tt>Fl_Gl_Widget</tt> that includes several state variables:
|
|
|
|
<ul><pre>
|
|
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();
|
|
}
|
|
}
|
|
};
|
|
</ul><pre>
|
|
|
|
<H3>The camera() Method</H3>
|
|
|
|
The <tt>camera()</tt> method sets the camera (projection and viewpoint)
|
|
to use when drawing the scene. The scene is redrawn after this call.
|
|
|
|
<h3>The draw() Method</h3>
|
|
|
|
The <tt>draw()</tt> method performs the needed initialization
|
|
and does the actual drawing:
|
|
|
|
<ul><pre>
|
|
void OptimizerWindow::draw() {
|
|
if (!context_) {
|
|
// This is the first time we've been asked to draw; create the
|
|
// Optimizer context for the scene...
|
|
|
|
context_ = new csContext(fl_display, fl_visual);
|
|
context_->ref();
|
|
context_->makeCurrent(fl_display, fl_window);
|
|
|
|
... 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_);
|
|
}
|
|
}
|
|
|
|
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_);
|
|
}
|
|
</pre></ul>
|
|
|
|
<H3>The scene() Method</H3>
|
|
|
|
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.
|
|
|
|
</BODY>
|
|
</HTML>
|