Contents
Previous
Next
This >chapter >discusses >using >FLTK >for >your >OpenGL >
applications. >
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 ><FL/gl.h>> header >
file. > It >will > include >the >file ><GL/gl.h>>
, >define >some >extra >drawing > functions >provided >by >
FLTK, >and >include >the ><windows.h>> header >
file >needed >by >WIN32 >applications. >
To >make >a >subclass >of >Fl_Gl_Window, >you >must >
provide: >
- A >class >definition. >
- A >draw()> method. >
- A >handle()> method >(if >you >need >to >
recieve >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: >
>#ifndef MESA
>glDrawBuffer(GL_FRONT_AND_BACK);
>#endif // !MESA
>... draw stuff here ...
>#ifndef MESA
>glDrawBuffer(GL_BACK);
>#endif // !MESA
>
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. >
Defining >the >Subclass>
To >define >the >subclass >you >just >subclass >the >
Fl_Gl_Window> class: >
>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) {}
>};
>
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.) >
The >draw() >Method>
The >draw()> method >is >where >you >actually >
do >your >OpenGL > drawing: >
>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 ...
>}
>
The >handle() >Method>
The >handle()> method >handles >mouse >and >
keyboard >events >for >the > window: >
>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);
> }
>}
>
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: >
> 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...
>
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. >
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: >
>Fl::gl_visual(FL_RGB);
>
You >can >then >put >OpenGL >drawing >code >anywhere >
you >can >draw >normally >by > surrounding >it >with: >
>gl_start();
>... put your OpenGL code here ...
>gl_finish();
>
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 >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: >
- You >must >choose >a >default >visual >with >
Fl::gl_visual()>. >
- You >cannot >pass >FL_DOUBLE> to >
Fl::gl_visual()>.>
- 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>
! >
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 > <GL/gl.h>>). >
void >gl_color(Fl_Color)>
Set >the >current >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)>
Outline >or >fill >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)>
Set >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)>
Return >information >about >the >current >OpenGL >font. >
void >gl_draw(const >char >*) >
void >gl_draw(const >char >*, >int >n)>
Draw >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)>
Draw >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)>
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 >
fl_draw()> . >
Performance >of >Fl_Gl_Window >may >be >improved >on >
some >types >of >OpenGL >implementations >(in >particular >
MESA >or >other >software >emulators) >by >setting >the >
GL_SWAP_TYPE> environment >variable. > This >variable >
declares >what >is >in >the >back >buffer >after >you >
do >a >swapbuffers. >
- 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. >
- 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. >
- All >other >values >for >GL_SWAP_TYPE>, >and >
not >setting >the >variable, >cause >fltk >to >assumme >
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. >
OpenGL >Optimizer>
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. >
OptimizerWindow >Class >Definition>
To >use >OpenGL >Optimizer >with >FLTK >you'll >need >
to >create >a >subclass >of > Fl_Gl_Widget> that >
includes >several >state >variables: >
>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();
> }
> }
>};
>
>
>
The >camera() >Method>
The >camera()> method >sets >the >camera >
(projection >and > viewpoint) >to >use >when >drawing >
the >scene. >The >scene >is >redrawn >after > this >
call. >
The >draw() >Method>
The >draw()> method >performs >the >needed >
initialization >and >does > the >actual >drawing: >
>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_);
>}
>
The >scene() >Method>
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. >
Contents
Previous
Next
No comments for this page.
|