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. >
>#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. >
>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.) >
>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_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: >
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: >
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. >
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. >
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. >
>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(); > } > } >}; >
> >
>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_); >} >