fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Gl_Window.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Gl_Window.cxx 8173 2011-01-03 16:50:34Z manolo $"
00003 //
00004 // OpenGL window code for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 #include "flstring.h"
00029 #if HAVE_GL
00030 
00031 extern int fl_gl_load_plugin;
00032 
00033 static int temp = fl_gl_load_plugin;
00034 
00035 #include <FL/Fl.H>
00036 #include <FL/x.H>
00037 #include "Fl_Gl_Choice.H"
00038 #include <FL/Fl_Gl_Window.H>
00039 #include <stdlib.h>
00040 #include <FL/fl_utf8.h>
00041 
00043 
00044 // The symbol SWAP_TYPE defines what is in the back buffer after doing
00045 // a glXSwapBuffers().
00046 
00047 // The OpenGl documentation says that the contents of the backbuffer
00048 // are "undefined" after glXSwapBuffers().  However, if we know what
00049 // is in the backbuffers then we can save a good deal of time.  For
00050 // this reason you can define some symbols to describe what is left in
00051 // the back buffer.
00052 
00053 // Having not found any way to determine this from glx (or wgl) I have
00054 // resorted to letting the user specify it with an environment variable,
00055 // GL_SWAP_TYPE, it should be equal to one of these symbols:
00056 
00057 // contents of back buffer after glXSwapBuffers():
00058 #define UNDEFINED 1     // anything
00059 #define SWAP 2          // former front buffer (same as unknown)
00060 #define COPY 3          // unchanged
00061 #define NODAMAGE 4      // unchanged even by X expose() events
00062 
00063 static char SWAP_TYPE = 0 ; // 0 = determine it from environment variable
00064 
00066 
00068 int Fl_Gl_Window::can_do(int a, const int *b) {
00069   return Fl_Gl_Choice::find(a,b) != 0;
00070 }
00071 
00072 void Fl_Gl_Window::show() {
00073 #if defined(__APPLE__)
00074   int need_redraw = 0;
00075 #endif
00076   if (!shown()) {
00077     if (!g) {
00078       g = Fl_Gl_Choice::find(mode_,alist);
00079 
00080       if (!g && (mode_ & FL_DOUBLE) == FL_SINGLE) {
00081         g = Fl_Gl_Choice::find(mode_ | FL_DOUBLE,alist);
00082         if (g) mode_ |= FL_FAKE_SINGLE;
00083       }
00084 
00085       if (!g) {
00086         Fl::error("Insufficient GL support");
00087         return;
00088       }
00089     }
00090 #if !defined(WIN32) && !defined(__APPLE__)
00091     Fl_X::make_xid(this, g->vis, g->colormap);
00092     if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show();
00093 #elif defined(__APPLE__)
00094         if( ! parent() ) need_redraw=1;
00095         else Fl_X::i(window())->contains_GL_subwindow();
00096 #endif
00097   }
00098   Fl_Window::show();
00099 
00100 #ifdef __APPLE__
00101   set_visible();
00102   if(need_redraw) redraw();//necessary only after creation of a top-level GL window
00103 #endif /* __APPLE__ */
00104 }
00105 
00110 void Fl_Gl_Window::invalidate() {
00111   valid(0);
00112   context_valid(0);
00113 #ifndef WIN32
00114   if (overlay) {
00115     ((Fl_Gl_Window*)overlay)->valid(0);
00116     ((Fl_Gl_Window*)overlay)->context_valid(0);
00117   }
00118 #endif
00119 }
00120 
00124 int Fl_Gl_Window::mode(int m, const int *a) {
00125   if (m == mode_ && a == alist) return 0;
00126 #ifndef __APPLE__
00127   int oldmode = mode_;
00128 #endif // !__APPLE__
00129 #if !defined(WIN32) && !defined(__APPLE__)
00130   Fl_Gl_Choice* oldg = g;
00131 #endif // !WIN32 && !__APPLE__
00132   context(0);
00133   mode_ = m; alist = a;
00134   if (shown()) {
00135     g = Fl_Gl_Choice::find(m, a);
00136 
00137 #if defined(USE_X11)
00138     // under X, if the visual changes we must make a new X window (yuck!):
00139     if (!g || g->vis->visualid!=oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) {
00140       hide();
00141       show();
00142     }
00143 #elif defined(WIN32)
00144     if (!g || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) {
00145       hide();
00146       show();
00147     }
00148 #elif defined(__APPLE_QUARTZ__)
00149     // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
00150     redraw();
00151 #else
00152 #  error unsupported platform
00153 #endif
00154   } else {
00155     g = 0;
00156   }
00157   return 1;
00158 }
00159 
00160 #define NON_LOCAL_CONTEXT 0x80000000
00161 
00169 void Fl_Gl_Window::make_current() {
00170 //  puts("Fl_Gl_Window::make_current()");
00171 //  printf("make_current: context_=%p\n", context_);
00172   if (!context_) {
00173     mode_ &= ~NON_LOCAL_CONTEXT;
00174     context_ = fl_create_gl_context(this, g);
00175     valid(0);
00176     context_valid(0);
00177   }
00178   fl_set_gl_context(this, context_);
00179 
00180 #ifdef __APPLE__
00181   // Set the buffer rectangle here, since in resize() we won't have the
00182   // correct parent window size to work with...
00183   GLint xywh[4];
00184 
00185   if (window()) {
00186     xywh[0] = x();
00187     xywh[1] = window()->h() - y() - h();
00188   } else {
00189     xywh[0] = 0;
00190     xywh[1] = 0;
00191   }
00192 
00193   xywh[2] = w();
00194   xywh[3] = h();
00195 
00196   aglSetInteger(context_, AGL_BUFFER_RECT, xywh);
00197   aglEnable(context_, AGL_BUFFER_RECT);
00198 //  printf("make_current: xywh=[%d %d %d %d]\n", xywh[0], xywh[1], xywh[2], xywh[3]);
00199 #endif // __APPLE__
00200 
00201 #if defined(WIN32) && USE_COLORMAP
00202   if (fl_palette) {
00203     fl_GetDC(fl_xid(this));
00204     SelectPalette(fl_gc, fl_palette, FALSE);
00205     RealizePalette(fl_gc);
00206   }
00207 #endif // USE_COLORMAP
00208   if (mode_ & FL_FAKE_SINGLE) {
00209     glDrawBuffer(GL_FRONT);
00210     glReadBuffer(GL_FRONT);
00211   }
00212   current_ = this;
00213 }
00214 
00220 void Fl_Gl_Window::ortho() {
00221 // Alpha NT seems to have a broken OpenGL that does not like negative coords:
00222 #ifdef _M_ALPHA
00223   glLoadIdentity();
00224   glViewport(0, 0, w(), h());
00225   glOrtho(0, w(), 0, h(), -1, 1);
00226 #else
00227   GLint v[2];
00228   glGetIntegerv(GL_MAX_VIEWPORT_DIMS, v);
00229   glLoadIdentity();
00230   glViewport(w()-v[0], h()-v[1], v[0], v[1]);
00231   glOrtho(w()-v[0], w(), h()-v[1], h(), -1, 1);
00232 #endif
00233 }
00234 
00239 void Fl_Gl_Window::swap_buffers() {
00240 #if defined(USE_X11)
00241   glXSwapBuffers(fl_display, fl_xid(this));
00242 #elif defined(WIN32)
00243 #  if HAVE_GL_OVERLAY
00244   // Do not swap the overlay, to match GLX:
00245   BOOL ret = wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_MAIN_PLANE);
00246   DWORD err = GetLastError();;
00247 #  else
00248   SwapBuffers(Fl_X::i(this)->private_dc);
00249 #  endif
00250 #elif defined(__APPLE_QUARTZ__)
00251   if(overlay != NULL) {
00252     //aglSwapBuffers does not work well with overlays under cocoa
00253     glReadBuffer(GL_BACK);
00254     glDrawBuffer(GL_FRONT);
00255     glCopyPixels(0,0,w(),h(),GL_COLOR);
00256   }
00257   else
00258     aglSwapBuffers((AGLContext)context_);
00259 #else
00260 # error unsupported platform
00261 #endif
00262 }
00263 
00264 #if HAVE_GL_OVERLAY && defined(WIN32)
00265 uchar fl_overlay; // changes how fl_color() works
00266 int fl_overlay_depth = 0;
00267 #endif
00268 
00269 
00270 void Fl_Gl_Window::flush() {
00271   uchar save_valid = valid_f_ & 1;
00272 #if HAVE_GL_OVERLAY && defined(WIN32)
00273   uchar save_valid_f = valid_f_;
00274 #endif
00275 
00276 #if defined(__APPLE_QUARTZ__)
00277   // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
00278   //: clear previous clipping in this shared port
00279 #if ! __LP64__
00280 /*GrafPtr port = GetWindowPort( Fl_X::i(this)->window_ref() );
00281   Rect rect; SetRect( &rect, 0, 0, 0x7fff, 0x7fff );
00282   GrafPtr old; GetPort( &old );
00283   SetPort( port );
00284   ClipRect( &rect );
00285   SetPort( old );*/
00286 #endif
00287 #endif
00288 
00289 #if HAVE_GL_OVERLAY && defined(WIN32)
00290 
00291   bool fixcursor = false; // for fixing the SGI 320 bug
00292 
00293   // Draw into hardware overlay planes if they are damaged:
00294   if (overlay && overlay != this
00295       && (damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid)) {
00296     // SGI 320 messes up overlay with user-defined cursors:
00297     if (Fl_X::i(this)->cursor && Fl_X::i(this)->cursor != fl_default_cursor) {
00298       fixcursor = true; // make it restore cursor later
00299       SetCursor(0);
00300     }
00301     fl_set_gl_context(this, (GLContext)overlay);
00302     if (fl_overlay_depth)
00303       wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE);
00304     glDisable(GL_SCISSOR_TEST);
00305     glClear(GL_COLOR_BUFFER_BIT);
00306     fl_overlay = 1;
00307     draw_overlay();
00308     fl_overlay = 0;
00309     valid_f_ = save_valid_f;
00310     wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_OVERLAY1);
00311     // if only the overlay was damaged we are done, leave main layer alone:
00312     if (damage() == FL_DAMAGE_OVERLAY) {
00313       if (fixcursor) SetCursor(Fl_X::i(this)->cursor);
00314       return;
00315     }
00316   }
00317 #endif
00318 
00319   make_current();
00320 
00321   if (mode_ & FL_DOUBLE) {
00322 
00323     glDrawBuffer(GL_BACK);
00324 
00325     if (!SWAP_TYPE) {
00326 #if defined (__APPLE_QUARTZ__) || defined (USE_X11)
00327       SWAP_TYPE = COPY;
00328 #else
00329       SWAP_TYPE = UNDEFINED;
00330 #endif
00331       const char* c = fl_getenv("GL_SWAP_TYPE");
00332       if (c) {
00333         if (!strcmp(c,"COPY")) SWAP_TYPE = COPY;
00334         else if (!strcmp(c, "NODAMAGE")) SWAP_TYPE = NODAMAGE;
00335         else if (!strcmp(c, "SWAP")) SWAP_TYPE = SWAP;
00336         else SWAP_TYPE = UNDEFINED;
00337       }
00338     }
00339 
00340     if (SWAP_TYPE == NODAMAGE) {
00341 
00342       // don't draw if only overlay damage or expose events:
00343       if ((damage()&~(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE)) || !save_valid)
00344         draw();
00345       swap_buffers();
00346 
00347     } else if (SWAP_TYPE == COPY) {
00348 
00349       // don't draw if only the overlay is damaged:
00350       if (damage() != FL_DAMAGE_OVERLAY || !save_valid) draw();
00351           swap_buffers();
00352 
00353     } else if (SWAP_TYPE == SWAP){
00354       damage(FL_DAMAGE_ALL);
00355       draw();
00356       if (overlay == this) draw_overlay();
00357       swap_buffers();
00358     } else if (SWAP_TYPE == UNDEFINED){ // SWAP_TYPE == UNDEFINED
00359 
00360       // If we are faking the overlay, use CopyPixels to act like
00361       // SWAP_TYPE == COPY.  Otherwise overlay redraw is way too slow.
00362       if (overlay == this) {
00363         // don't draw if only the overlay is damaged:
00364         if (damage1_ || damage() != FL_DAMAGE_OVERLAY || !save_valid) draw();
00365         // we use a separate context for the copy because rasterpos must be 0
00366         // and depth test needs to be off:
00367         static GLContext ortho_context = 0;
00368         static Fl_Gl_Window* ortho_window = 0;
00369         int orthoinit = !ortho_context;
00370         if (orthoinit) ortho_context = fl_create_gl_context(this, g);
00371         fl_set_gl_context(this, ortho_context);
00372         if (orthoinit || !save_valid || ortho_window != this) {
00373           glDisable(GL_DEPTH_TEST);
00374           glReadBuffer(GL_BACK);
00375           glDrawBuffer(GL_FRONT);
00376           glLoadIdentity();
00377           glViewport(0, 0, w(), h());
00378           glOrtho(0, w(), 0, h(), -1, 1);
00379           glRasterPos2i(0,0);
00380           ortho_window = this;
00381         }
00382         glCopyPixels(0,0,w(),h(),GL_COLOR);
00383         make_current(); // set current context back to draw overlay
00384         damage1_ = 0;
00385 
00386       } else {
00387         damage1_ = damage();
00388         clear_damage(0xff); draw();
00389         swap_buffers();
00390       }
00391 
00392     }
00393 
00394     if (overlay==this && SWAP_TYPE != SWAP) { // fake overlay in front buffer
00395       glDrawBuffer(GL_FRONT);
00396       draw_overlay();
00397       glDrawBuffer(GL_BACK);
00398       glFlush();
00399     }
00400 
00401   } else {      // single-buffered context is simpler:
00402 
00403     draw();
00404     if (overlay == this) draw_overlay();
00405     glFlush();
00406 
00407   }
00408 
00409 #if HAVE_GL_OVERLAY && defined(WIN32)
00410   if (fixcursor) SetCursor(Fl_X::i(this)->cursor);
00411 #endif
00412   valid(1);
00413   context_valid(1);
00414 }
00415 
00416 void Fl_Gl_Window::resize(int X,int Y,int W,int H) {
00417 //  printf("Fl_Gl_Window::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H);
00418 //  printf("current: x()=%d, y()=%d, w()=%d, h()=%d\n", x(), y(), w(), h());
00419 
00420   if (W != w() || H != h()) valid(0);
00421 
00422 #ifdef __APPLE__
00423   if (X != x() || Y != y() || W != w() || H != h()) aglUpdateContext(context_);
00424 #elif !defined(WIN32)
00425   if ((W != w() || H != h()) && !resizable() && overlay && overlay != this) {
00426     ((Fl_Gl_Window*)overlay)->resize(0,0,W,H);
00427   }
00428 #endif
00429 
00430   Fl_Window::resize(X,Y,W,H);
00431 }
00432 
00444 void Fl_Gl_Window::context(void* v, int destroy_flag) {
00445   if (context_ && !(mode_&NON_LOCAL_CONTEXT)) fl_delete_gl_context(context_);
00446   context_ = (GLContext)v;
00447   if (destroy_flag) mode_ &= ~NON_LOCAL_CONTEXT;
00448   else mode_ |= NON_LOCAL_CONTEXT;
00449 }    
00450 
00454 void Fl_Gl_Window::hide() {
00455   context(0);
00456 #if HAVE_GL_OVERLAY && defined(WIN32)
00457   if (overlay && overlay != this) {
00458     fl_delete_gl_context((GLContext)overlay);
00459     overlay = 0;
00460   }
00461 #endif
00462   Fl_Window::hide();
00463 }
00464 
00469 Fl_Gl_Window::~Fl_Gl_Window() {
00470   hide();
00471 //  delete overlay; this is done by ~Fl_Group
00472 }
00473 
00474 void Fl_Gl_Window::init() {
00475   end(); // we probably don't want any children
00476   box(FL_NO_BOX);
00477 
00478   mode_    = FL_RGB | FL_DEPTH | FL_DOUBLE;
00479   alist    = 0;
00480   context_ = 0;
00481   g        = 0;
00482   overlay  = 0;
00483   valid_f_ = 0;
00484   damage1_ = 0;
00485 
00486 #if 0 // This breaks resizing on Linux/X11
00487   int H = h();
00488   h(1); // Make sure we actually do something in resize()...
00489   resize(x(), y(), w(), H);
00490 #endif // 0
00491 }
00492 
00508 void Fl_Gl_Window::draw_overlay() {}
00509 
00510 #endif
00511 
00527 void Fl_Gl_Window::draw() {
00528     Fl::fatal("Fl_Gl_Window::draw() *must* be overriden. Please refer to the documentation.");
00529 }
00530 
00531 
00535 int Fl_Gl_Window::handle(int event) 
00536 {
00537 #ifdef __APPLE_QUARTZ__
00538   if (event==FL_HIDE) {
00539     // if we are not hidden, just the parent was hidden, so we must throw away the context
00540     if (!visible_r())
00541       context(0); // remove context wthout setting the hidden flags
00542   }
00543   if (event==FL_SHOW) {
00544     // if we are not hidden, just the parent was shown, so we must create a new context
00545     if (visible_r())
00546       show(); //
00547   }
00548 #endif
00549   return Fl_Window::handle(event);
00550 }
00551 
00552 //
00553 // End of "$Id: Fl_Gl_Window.cxx 8173 2011-01-03 16:50:34Z manolo $".
00554 //