source: rtems-graphics-toolkit/fltk-1.1.10/src/Fl_Gl_Window.cxx @ 513eea1

Last change on this file since 513eea1 was 513eea1, checked in by Joel Sherrill <joel.sherrill@…>, on 01/09/10 at 22:43:24

2010-01-08 Joel Sherrill <joel.sherrill@…>

fltk 1.1.10. imported

  • ORIGIN: Updated.
  • Property mode set to 100644
File size: 11.7 KB
Line 
1//
2// "$Id$"
3//
4// OpenGL window code for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2006 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25//     http://www.fltk.org/str.php
26//
27
28#include "flstring.h"
29#if HAVE_GL
30
31#include <FL/Fl.H>
32#include <FL/x.H>
33#include "Fl_Gl_Choice.H"
34#include <FL/Fl_Gl_Window.H>
35#include <stdlib.h>
36
37////////////////////////////////////////////////////////////////
38
39// The symbol SWAP_TYPE defines what is in the back buffer after doing
40// a glXSwapBuffers().
41
42// The OpenGl documentation says that the contents of the backbuffer
43// are "undefined" after glXSwapBuffers().  However, if we know what
44// is in the backbuffers then we can save a good deal of time.  For
45// this reason you can define some symbols to describe what is left in
46// the back buffer.
47
48// Having not found any way to determine this from glx (or wgl) I have
49// resorted to letting the user specify it with an environment variable,
50// GL_SWAP_TYPE, it should be equal to one of these symbols:
51
52// contents of back buffer after glXSwapBuffers():
53#define UNDEFINED 1     // anything
54#define SWAP 2          // former front buffer (same as unknown)
55#define COPY 3          // unchanged
56#define NODAMAGE 4      // unchanged even by X expose() events
57
58static char SWAP_TYPE = 0 ; // 0 = determine it from environment variable
59
60////////////////////////////////////////////////////////////////
61
62int Fl_Gl_Window::can_do(int a, const int *b) {
63  return Fl_Gl_Choice::find(a,b) != 0;
64}
65
66void Fl_Gl_Window::show() {
67  if (!shown()) {
68    if (!g) {
69      g = Fl_Gl_Choice::find(mode_,alist);
70
71      if (!g && (mode_ & FL_DOUBLE) == FL_SINGLE) {
72        g = Fl_Gl_Choice::find(mode_ | FL_DOUBLE,alist);
73        if (g) mode_ |= FL_FAKE_SINGLE;
74      }
75
76      if (!g) {
77        Fl::error("Insufficient GL support");
78        return;
79      }
80    }
81#if !defined(WIN32) && !defined(__APPLE__)
82    Fl_X::make_xid(this, g->vis, g->colormap);
83    if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show();
84#endif
85  }
86  Fl_Window::show();
87
88#ifdef __APPLE__
89  set_visible();
90#endif /* __APPLE__ */
91}
92
93void Fl_Gl_Window::invalidate() {
94  valid(0);
95  context_valid(0);
96#ifndef WIN32
97  if (overlay) {
98    ((Fl_Gl_Window*)overlay)->valid(0);
99    ((Fl_Gl_Window*)overlay)->context_valid(0);
100  }
101#endif
102}
103
104int Fl_Gl_Window::mode(int m, const int *a) {
105  if (m == mode_ && a == alist) return 0;
106#ifndef __APPLE__
107  int oldmode = mode_;
108#endif // !__APPLE__
109#if !defined(WIN32) && !defined(__APPLE__)
110  Fl_Gl_Choice* oldg = g;
111#endif // !WIN32 && !__APPLE__
112  context(0);
113  mode_ = m; alist = a;
114  if (shown()) {
115    g = Fl_Gl_Choice::find(m, a);
116#if defined(WIN32)
117    if (!g || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) {
118      hide();
119      show();
120    }
121#elif defined(__APPLE_QD__)
122    redraw();
123#elif defined(__APPLE_QUARTZ__)
124    // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
125    redraw();
126#else
127    // under X, if the visual changes we must make a new X window (yuck!):
128    if (!g || g->vis->visualid!=oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) {
129      hide();
130      show();
131    }
132#endif
133  } else {
134    g = 0;
135  }
136  return 1;
137}
138
139#define NON_LOCAL_CONTEXT 0x80000000
140
141void Fl_Gl_Window::make_current() {
142//  puts("Fl_Gl_Window::make_current()");
143//  printf("make_current: context_=%p\n", context_);
144  if (!context_) {
145    mode_ &= ~NON_LOCAL_CONTEXT;
146    context_ = fl_create_gl_context(this, g);
147    valid(0);
148    context_valid(0);
149  }
150  fl_set_gl_context(this, context_);
151
152#ifdef __APPLE__
153  // Set the buffer rectangle here, since in resize() we won't have the
154  // correct parent window size to work with...
155  GLint xywh[4];
156
157  if (window()) {
158    xywh[0] = x();
159    xywh[1] = window()->h() - y() - h();
160  } else {
161    xywh[0] = 0;
162    xywh[1] = 0;
163  }
164
165  xywh[2] = w();
166  xywh[3] = h();
167
168  aglSetInteger(context_, AGL_BUFFER_RECT, xywh);
169  aglEnable(context_, AGL_BUFFER_RECT);
170//  printf("make_current: xywh=[%d %d %d %d]\n", xywh[0], xywh[1], xywh[2], xywh[3]);
171#endif // __APPLE__
172
173#if defined(WIN32) && USE_COLORMAP
174  if (fl_palette) {
175    fl_GetDC(fl_xid(this));
176    SelectPalette(fl_gc, fl_palette, FALSE);
177    RealizePalette(fl_gc);
178  }
179#endif // USE_COLORMAP
180  if (mode_ & FL_FAKE_SINGLE) {
181    glDrawBuffer(GL_FRONT);
182    glReadBuffer(GL_FRONT);
183  }
184  current_ = this;
185}
186
187void Fl_Gl_Window::ortho() {
188// Alpha NT seems to have a broken OpenGL that does not like negative coords:
189#ifdef _M_ALPHA
190  glLoadIdentity();
191  glViewport(0, 0, w(), h());
192  glOrtho(0, w(), 0, h(), -1, 1);
193#else
194  GLint v[2];
195  glGetIntegerv(GL_MAX_VIEWPORT_DIMS, v);
196  glLoadIdentity();
197  glViewport(w()-v[0], h()-v[1], v[0], v[1]);
198  glOrtho(w()-v[0], w(), h()-v[1], h(), -1, 1);
199#endif
200}
201
202void Fl_Gl_Window::swap_buffers() {
203#ifdef WIN32
204#  if HAVE_GL_OVERLAY
205  // Do not swap the overlay, to match GLX:
206  BOOL ret = wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_MAIN_PLANE);
207  DWORD err = GetLastError();;
208#  else
209  SwapBuffers(Fl_X::i(this)->private_dc);
210#  endif
211#elif defined(__APPLE_QD__)
212  aglSwapBuffers((AGLContext)context_);
213#elif defined(__APPLE_QUARTZ__)
214  // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
215  aglSwapBuffers((AGLContext)context_);
216#else
217  glXSwapBuffers(fl_display, fl_xid(this));
218#endif
219}
220
221#if HAVE_GL_OVERLAY && defined(WIN32)
222uchar fl_overlay; // changes how fl_color() works
223int fl_overlay_depth = 0;
224#endif
225
226void Fl_Gl_Window::flush() {
227  uchar save_valid = valid_f_ & 1;
228#if HAVE_GL_OVERLAY && defined(WIN32)
229  uchar save_valid_f = valid_f_;
230#endif
231
232#ifdef __APPLE_QD__
233  //: clear previous clipping in this shared port
234  GrafPtr port = GetWindowPort( fl_xid(this) );
235  Rect rect; SetRect( &rect, 0, 0, 0x7fff, 0x7fff );
236  GrafPtr old; GetPort( &old );
237  SetPort( port );
238  ClipRect( &rect );
239  SetPort( old );
240#elif defined(__APPLE_QUARTZ__)
241  // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
242  //: clear previous clipping in this shared port
243  GrafPtr port = GetWindowPort( fl_xid(this) );
244  Rect rect; SetRect( &rect, 0, 0, 0x7fff, 0x7fff );
245  GrafPtr old; GetPort( &old );
246  SetPort( port );
247  ClipRect( &rect );
248  SetPort( old );
249#endif
250
251#if HAVE_GL_OVERLAY && defined(WIN32)
252
253  bool fixcursor = false; // for fixing the SGI 320 bug
254
255  // Draw into hardware overlay planes if they are damaged:
256  if (overlay && overlay != this
257      && (damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid)) {
258    // SGI 320 messes up overlay with user-defined cursors:
259    if (Fl_X::i(this)->cursor && Fl_X::i(this)->cursor != fl_default_cursor) {
260      fixcursor = true; // make it restore cursor later
261      SetCursor(0);
262    }
263    fl_set_gl_context(this, (GLContext)overlay);
264    if (fl_overlay_depth)
265      wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE);
266    glDisable(GL_SCISSOR_TEST);
267    glClear(GL_COLOR_BUFFER_BIT);
268    fl_overlay = 1;
269    draw_overlay();
270    fl_overlay = 0;
271    valid_f_ = save_valid_f;
272    wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_OVERLAY1);
273    // if only the overlay was damaged we are done, leave main layer alone:
274    if (damage() == FL_DAMAGE_OVERLAY) {
275      if (fixcursor) SetCursor(Fl_X::i(this)->cursor);
276      return;
277    }
278  }
279#endif
280
281  make_current();
282
283  if (mode_ & FL_DOUBLE) {
284
285    glDrawBuffer(GL_BACK);
286
287    if (!SWAP_TYPE) {
288#ifdef __APPLE_QD__
289      SWAP_TYPE = COPY;
290#elif defined __APPLE_QUARTZ__
291      // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
292      SWAP_TYPE = COPY;
293#else
294      SWAP_TYPE = UNDEFINED;
295#endif
296      const char* c = getenv("GL_SWAP_TYPE");
297      if (c) {
298        if (!strcmp(c,"COPY")) SWAP_TYPE = COPY;
299        else if (!strcmp(c, "NODAMAGE")) SWAP_TYPE = NODAMAGE;
300        else if (!strcmp(c, "SWAP")) SWAP_TYPE = SWAP;
301      }
302    }
303
304    if (SWAP_TYPE == NODAMAGE) {
305
306      // don't draw if only overlay damage or expose events:
307      if ((damage()&~(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE)) || !save_valid)
308        draw();
309      swap_buffers();
310
311    } else if (SWAP_TYPE == COPY) {
312
313      // don't draw if only the overlay is damaged:
314      if (damage() != FL_DAMAGE_OVERLAY || !save_valid) draw();
315      swap_buffers();
316
317    } else { // SWAP_TYPE == UNDEFINED
318
319      // If we are faking the overlay, use CopyPixels to act like
320      // SWAP_TYPE == COPY.  Otherwise overlay redraw is way too slow.
321      if (overlay == this) {
322        // don't draw if only the overlay is damaged:
323        if (damage1_ || damage() != FL_DAMAGE_OVERLAY || !save_valid) draw();
324        // we use a seperate context for the copy because rasterpos must be 0
325        // and depth test needs to be off:
326        static GLContext ortho_context = 0;
327        static Fl_Gl_Window* ortho_window = 0;
328        int orthoinit = !ortho_context;
329        if (orthoinit) ortho_context = fl_create_gl_context(this, g);
330        fl_set_gl_context(this, ortho_context);
331        if (orthoinit || !save_valid || ortho_window != this) {
332          glDisable(GL_DEPTH_TEST);
333          glReadBuffer(GL_BACK);
334          glDrawBuffer(GL_FRONT);
335          glLoadIdentity();
336          glViewport(0, 0, w(), h());
337          glOrtho(0, w(), 0, h(), -1, 1);
338          glRasterPos2i(0,0);
339          ortho_window = this;
340        }
341        glCopyPixels(0,0,w(),h(),GL_COLOR);
342        make_current(); // set current context back to draw overlay
343        damage1_ = 0;
344
345      } else {
346        damage1_ = damage();
347        clear_damage(0xff); draw();
348        swap_buffers();
349      }
350
351    }
352
353    if (overlay==this) { // fake overlay in front buffer
354      glDrawBuffer(GL_FRONT);
355      draw_overlay();
356      glDrawBuffer(GL_BACK);
357      glFlush();
358    }
359
360  } else {      // single-buffered context is simpler:
361
362    draw();
363    if (overlay == this) draw_overlay();
364    glFlush();
365
366  }
367
368#if HAVE_GL_OVERLAY && defined(WIN32)
369  if (fixcursor) SetCursor(Fl_X::i(this)->cursor);
370#endif
371  valid(1);
372  context_valid(1);
373}
374
375void Fl_Gl_Window::resize(int X,int Y,int W,int H) {
376//  printf("Fl_Gl_Window::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H);
377//  printf("current: x()=%d, y()=%d, w()=%d, h()=%d\n", x(), y(), w(), h());
378
379  if (W != w() || H != h()) valid(0);
380
381#ifdef __APPLE__
382  if (X != x() || Y != y() || W != w() || H != h()) aglUpdateContext(context_);
383#elif !defined(WIN32)
384  if ((W != w() || H != h()) && !resizable() && overlay && overlay != this) {
385    ((Fl_Gl_Window*)overlay)->resize(0,0,W,H);
386  }
387#endif
388
389  Fl_Window::resize(X,Y,W,H);
390}
391
392void Fl_Gl_Window::context(void* v, int destroy_flag) {
393  if (context_ && !(mode_&NON_LOCAL_CONTEXT)) fl_delete_gl_context(context_);
394  context_ = (GLContext)v;
395  if (destroy_flag) mode_ &= ~NON_LOCAL_CONTEXT;
396  else mode_ |= NON_LOCAL_CONTEXT;
397}   
398
399void Fl_Gl_Window::hide() {
400  context(0);
401#if HAVE_GL_OVERLAY && defined(WIN32)
402  if (overlay && overlay != this) {
403    fl_delete_gl_context((GLContext)overlay);
404    overlay = 0;
405  }
406#endif
407  Fl_Window::hide();
408}
409
410Fl_Gl_Window::~Fl_Gl_Window() {
411  hide();
412//  delete overlay; this is done by ~Fl_Group
413}
414
415void Fl_Gl_Window::init() {
416  end(); // we probably don't want any children
417  box(FL_NO_BOX);
418
419  mode_    = FL_RGB | FL_DEPTH | FL_DOUBLE;
420  alist    = 0;
421  context_ = 0;
422  g        = 0;
423  overlay  = 0;
424  valid_f_ = 0;
425  damage1_ = 0;
426
427#if 0 // This breaks resizing on Linux/X11
428  int H = h();
429  h(1); // Make sure we actually do something in resize()...
430  resize(x(), y(), w(), H);
431#endif // 0
432}
433
434void Fl_Gl_Window::draw_overlay() {}
435
436#endif
437
438//
439// End of "$Id$".
440//
Note: See TracBrowser for help on using the repository browser.