/usr/share/doc/python-fltk-doc/CH8_Opengl.html is in python-fltk-doc 1.3.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | <HTML>
<BODY>
<H1 ALIGN=RIGHT><A NAME=opengl>8 - Using OpenGL</A></H1>
<P>This chapter discusses using pyFltk for your OpenGL applications.
<H2>Using OpenGL in pyFltk</H2>
<P>The easiest way to make an OpenGL display is to subclass <A
href="fltk.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) pyFltk will call <TT>draw()</TT>.
<P>With a bit of care you can also use OpenGL to draw into
normal pyFltk 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.</P>
<P>You must make sure that pyFltk has been compiled with OpenGL support!</P>
<H2>Making a Subclass of Fl_Gl_Window</H2>
<P>To make a subclass of Fl_Gl_Window, you must provide:
<UL>
<LI>A class definition.</LI>
<LI>A <TT>draw()</TT> method.</LI>
<LI>A <TT>handle()</TT> method if you need to receive
input from the user.</LI>
</UL>
<P>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:
<UL><PRE>
glDrawBuffer(GL_FRONT_AND_BACK)
... draw stuff here ...
glDrawBuffer(GL_BACK)
</PRE></UL>
<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>
<H3>Defining the Subclass</H3>
<P>To define the subclass you just subclass the
<TT>Fl_Gl_Window</TT> class:
<UL><PRE>
class MyWindow(Fl_Gl_Window):
def __init__(self, xpos, ypos, width, height, label):
Fl_Gl_Window.__init__(self, xpos, ypos, width, height, label)
</PRE></UL>
<P>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>
<P>The <TT>draw()</TT> method is where you actually do your
OpenGL drawing:
<UL><PRE>
def draw(self):
if not self.valid():
... set up projection, viewport, etc ...
... window size is in w() and h().
... valid() is turned on by pyFltk after draw() returns
... draw ...
</PRE></UL>
<H3>The handle() Method</H3>
<P>The <TT>handle()</TT> method handles mouse and keyboard
events for the window:
<UL><PRE>
def handle(self, event):
if event == FL_PUSH:
... mouse down event ...
... position in Fl.event_x() and Fl.event_y()
return 1
elif event == FL_DRAG:
... mouse moved while down event ...
return 1
elif event == FL_RELEASE:
... mouse up event ...
return 1
elif event == FL_FOCUS or event == FL_UNFOCUS:
... Return 1 if you want keyboard events, 0 otherwise
return 1
elif event == 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
elif event == 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
else:
// pass other events to the base class...
return Fl_Gl_Window.handle(self, event)
</PRE></UL>
<P>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 <I>some</I> OpenGL stuff like hit detection and texture
loading functions by doing: </P>
<UL><PRE>
if event == FL_PUSH:
self.make_current() # make OpenGL context current
if not self.valid():
... set up projection exactly the same as draw ...
self.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>
<P>Your main program can now create one of your windows by calling
<TT>MyWindow(...)</TT>.
<P>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 pyFltk Windows</H2>
<P>You can put OpenGL code into an <A
href="CH7_Subclassing.html#draw"><TT>Fl_Widget.draw()</TT></A>
method or into the code for a <A
href="CH3_Common.html#boxtypes">boxtype</A> or other places with some
care.
<P>Most importantly, before you show <I>any</I> windows,
including those that don't have OpenGL drawing, you <B>must</B>
initialize pyFltk so that it knows it is going to use OpenGL. You
may use any of the symbols described for <A
href="fltk.html#Fl_Gl_Window-mode"><TT>Fl_Gl_Window.mode()</TT></A>
to describe how you intend to use OpenGL:</P>
<UL><PRE>
Fl.gl_visual(FL_RGB)
</PRE></UL>
<P>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>
<P><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 pyFltk 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>
<P>You may want to use <TT>Fl_Window.current()->h()</TT> to
get the drawable height so that you can flip the Y
coordinates.</P>
<P>Unfortunately, there are a bunch of limitations you must
adhere to for maximum portability: </P>
<UL>
<LI>You must choose a default visual with <A
href="fltk.html#Fl-gl_visual"><TT>Fl.gl_visual()</TT></A>.</LI>
<LI>You cannot pass <TT>FL_DOUBLE</TT> to
<TT>Fl.gl_visual()</TT>.</LI>
<LI>You cannot use <TT>Fl_Double_Window</TT> or
<TT>Fl_Overlay_Window</TT>.</LI>
</UL>
<P>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>
<P>pyFltk provides some useful OpenGL drawing functions, which can
be freely mixed with any OpenGL calls.
<H4>gl_color(color)</H4>
<P>Sets the current OpenGL color to a pyFltk 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>
<H4>gl_rect(xpos, ypos, width, height)
<BR>gl_rectf(xpos, ypos, width, height)</H4>
<P>Outlines or fills a rectangle with the current color. If <A
HREF="fltk.html#Fl_Gl_Window-ortho"><TT>Fl_Gl_Window.ortho()</TT></A>
has been called, then the rectangle will exactly fill the pixel
rectangle passed.
<H4>gl_font(fontid, size)</H4>
<P>Sets the current OpenGL font to the same font you get by
calling <A href="CH5_Drawing.html#fl_font"><TT>fl_font()</TT></A>.
<H4>height = gl_height()
<BR>descent = gl_descent()
<BR>width = gl_width(text)
<BR>width = t gl_width(text, n)
<BR>width = gl_width(character)</H4>
<P>Returns information about the current OpenGL font.
<H4>gl_draw(text)
<BR>gl_draw(text, n)</H4>
<P>Draws a nul-terminated string or an array of <TT>n</TT>
characters in the current OpenGL font at the current raster
position.
<H4>gl_draw(text, xpos, ypos)
<BR>gl_draw(text, n, xpos, ypos)
<BR>gl_draw(text, float_xpos, float_ypos)
<BR>gl_draw(text, n, float_xpos, float_ypos)</H4>
<P>Draws a nul-terminated string or an array of <TT>n</TT>
characters in the current OpenGL font at the given position.
<H4>gl_draw(text, xpos, ypos, width, height, alignment)</H4>
<P>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="CH5_Drawing.html#text"><TT>fl_draw()</TT></A>.
<h2>Speeding up OpenGL</h2>
<P>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.
<ul>
<li><tt>setenv GL_SWAP_TYPE COPY</tt>
<p>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>
<p>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 pyFltk to assume that the
back buffer must be completely redrawn after a swap.
</ul>
<p>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.
<H2>Using OpenGL Optimizer with pyFltk</H2>
<P><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.
<H4>OptimizerWindow Class Definition</H4>
<P>To use OpenGL Optimizer with pyFltk you'll need to create a
subclass of <TT>Fl_Gl_Widget</TT> that includes several state
variables:
<UL><PRE>
class OptimizerWindow(Fl_Gl_Window):
def OptimizerWindow.__init__(self, X, Y, W, H, L):
Fl_Gl_Window.__init__(self, X, Y, W, H, L)
self.context_ = None
self.draw_action_ = None
self.scene_ = None
self.camera_ = None
def scene(self, csGroup):
self.scene_ = csGroup
self.redraw()
def camera(self, csCamera):
self-camera_ = csCamera
if self.context_ != None:
self.draw_action_.setCamera(self.camera_)
self.camera_.draw(self.draw_action_)
self.redraw()
</PRE></UL>
<H4>The camera() Method</H4>
<P>The <TT>camera()</TT> method sets the camera (projection and
viewpoint) to use when drawing the scene. The scene is redrawn after
this call.
<H4>The draw() Method</H4>
<P>The <TT>draw()</TT> method performs the needed initialization and does
the actual drawing:
<UL><PRE>
def draw(self):
if self.context_ != None:
# This is the first time we've been asked to draw; create the
# Optimizer context for the scene...
if sys.platform == 'win32':
self.context_ = csContext(fl_getHDC())
self.context_.ref()
self.context_.makeCurrent(fl_getHDC())
else:
self.context_ = csContext(fl_display, fl_visual)
self.context_.ref()
self.context_.makeCurrent(fl_display, fl_window)
... perform other context setup as desired ...
# Then create the draw action to handle drawing things...
self.draw_action_ = csDrawAction()
if self.camera_ != None:
self.draw_action_.setCamera(self.camera_)
self.camera_.draw(self.draw_action_)
else:
if sys.platform == 'win32':
self.context_.makeCurrent(fl_getHDC())
else:
self.context_.makeCurrent(fl_display, fl_window)
if not valid():
# Update the viewport for this context...
self.context_.setViewport(0, 0, self.w(), self.h())
}
# Clear the window...
self.context_.clear(csContext.COLOR_CLEAR | csContext.DEPTH_CLEAR,
0.0, # Red
0.0, # Green
0.0, # Blue
1.0) # Alpha
# Then draw the scene (if any)...
if self.scene_ != None
self.draw_action_.apply(self.scene_)
</PRE></UL>
<H4>The scene() Method</H4>
<P>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>
|