|
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) ![]() |
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 //