1 /********************************************************************************
2 *                                                                               *
3 *                    O p e n G L   C a n v a s   O b j e c t                    *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 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 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser 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  USA.    *
21 *********************************************************************************
22 * $Id: FXGLCanvas.cpp 3297 2015-12-14 20:30:04Z arthurcnorman $                      *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXThread.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXSettings.h"
35 #include "FXRegistry.h"
36 #include "FXAccelTable.h"
37 #include "FXApp.h"
38 #include "FXException.h"
39 #include "FXVisual.h"
40 #include "FXGLVisual.h"
41 #include "FXCursor.h"
42 #include "FXGLContext.h"
43 #include "FXGLCanvas.h"
44 
45 
46 /*
47   Notes:
48   - Since this only adds SetPixelFormat, perhaps not a bad idea to contemplate
49     moving this call to SetPixelFormat somewhere else [candidates are FXGLVisual,
50     FXWindow, or FXGLContext].
51   - We may opt to have GLContext be created just prior to the first use.
52 */
53 
54 
55 using namespace FX;
56 
57 /*******************************************************************************/
58 
59 namespace FX {
60 
61 
62 // Object implementation
63 FXIMPLEMENT(FXGLCanvas,FXCanvas,NULL,0)
64 
65 
66 // For serialization
FXGLCanvas()67 FXGLCanvas::FXGLCanvas(){
68   flags|=FLAG_ENABLED|FLAG_SHOWN;
69   sgnext=this;
70   sgprev=this;
71   ctx=0;
72   }
73 
74 
75 // Make a canvas
FXGLCanvas(FXComposite * p,FXGLVisual * vis,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)76 FXGLCanvas::FXGLCanvas(FXComposite* p,FXGLVisual *vis,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):
77   FXCanvas(p,tgt,sel,opts,x,y,w,h){
78   flags|=FLAG_ENABLED|FLAG_SHOWN;
79   visual=vis;
80   sgnext=this;
81   sgprev=this;
82   ctx=0;
83   }
84 
85 
86 // Make a canvas sharing display lists
FXGLCanvas(FXComposite * p,FXGLVisual * vis,FXGLCanvas * sharegroup,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)87 FXGLCanvas::FXGLCanvas(FXComposite* p,FXGLVisual *vis,FXGLCanvas* sharegroup,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):
88   FXCanvas(p,tgt,sel,opts,x,y,w,h){
89   flags|=FLAG_ENABLED|FLAG_SHOWN;
90   visual=vis;
91   if(sharegroup){
92     sgnext=sharegroup;
93     sgprev=sharegroup->sgprev;
94     sharegroup->sgprev=this;
95     sgprev->sgnext=this;
96     }
97   else{
98     sgnext=this;
99     sgprev=this;
100     }
101   ctx=0;
102   }
103 
104 
105 
106 #ifdef WIN32
GetClass() const107 const char* FXGLCanvas::GetClass() const { return "FXGLCanvas"; }
108 #endif
109 
110 
111 // Return TRUE if it is sharing display lists
isShared() const112 FXbool FXGLCanvas::isShared() const { return sgnext!=this; }
113 
114 
115 // Create X window (GL CANVAS)
create()116 void FXGLCanvas::create(){
117   FXWindow::create();
118 #ifdef HAVE_GL_H
119   if(!ctx){
120     void *sharedctx=NULL;
121 
122     // Must have GL info available
123     if(!visual->getInfo()){
124       throw FXWindowException("unable to create GL window.");
125       }
126 
127     // Sharing display lists with other context
128     if(sgnext!=this){
129 
130       // Find another member of the group which is already created, and get its context
131       FXGLCanvas *canvas=sgnext;
132       while(canvas!=this){
133         sharedctx=canvas->ctx;
134         if(sharedctx) break;
135         canvas=canvas->sgnext;
136         }
137 
138       // The visuals have to match, the book says...
139       if(sgnext->getVisual()!=canvas->getVisual()){
140         throw FXWindowException("unable to create GL window.");
141         }
142       }
143 
144 #ifndef WIN32
145 
146     // Make context
147     ctx=glXCreateContext((Display*)getApp()->getDisplay(),(XVisualInfo*)visual->getInfo(),(GLXContext)sharedctx,TRUE);
148     if(!ctx){
149       throw FXWindowException("unable to create GL window.");
150       }
151 
152 #else
153 
154     // Make that the pixel format of the device context
155     HDC hdc=::GetDC((HWND)xid);
156     if(!SetPixelFormat(hdc,(FXint)(FXival)visual->getVisual(),(PIXELFORMATDESCRIPTOR*)visual->getInfo())){
157       throw FXWindowException("unable to create GL window.");
158       }
159 
160     // Make context
161     ctx=(void*)wglCreateContext(hdc);
162     if(!ctx){
163       throw FXWindowException("unable to create GL window.");
164       }
165 
166     // I hope I didn't get this backward; the new context obviously has no
167     // display lists yet, but the old one may have, as it has already been around
168     // for a while.  If you see this fail and can't explain why, then that might
169     // be what's going on.  Report this to jeroen@fox-toolkit.org
170     if(sharedctx && !wglShareLists((HGLRC)sharedctx,(HGLRC)ctx)){
171       throw FXWindowException("unable to create GL window.");
172       }
173     ::ReleaseDC((HWND)xid,hdc);
174 
175 #endif
176     }
177 #endif
178   }
179 
180 
181 // Detach the GL Canvas
detach()182 void FXGLCanvas::detach(){
183 #ifdef HAVE_GL_H
184   if(ctx){
185     // Will this leak memory?
186     ctx=0;
187     }
188 #endif
189   FXWindow::detach();
190   }
191 
192 
193 // Destroy the GL Canvas
destroy()194 void FXGLCanvas::destroy(){
195 #ifdef HAVE_GL_H
196   if(ctx){
197 #ifndef WIN32
198     glXDestroyContext((Display*)getApp()->getDisplay(),(GLXContext)ctx);
199 #else
200     wglDeleteContext((HGLRC)ctx);
201 #endif
202     ctx=0;
203     }
204 #endif
205   FXWindow::destroy();
206   }
207 
208 
209 //  Make the rendering context of GL Canvas current
makeCurrent()210 FXbool FXGLCanvas::makeCurrent(){
211 #ifdef HAVE_GL_H
212   if(ctx){
213 #ifndef WIN32
214     return glXMakeCurrent((Display*)getApp()->getDisplay(),xid,(GLXContext)ctx);
215 #else
216     HDC hdc=::GetDC((HWND)xid);
217     if(visual->colormap){
218       SelectPalette(hdc,(HPALETTE)visual->colormap,FALSE);
219       RealizePalette(hdc);
220       }
221     BOOL bStatus=wglMakeCurrent(hdc,(HGLRC)ctx);
222     return bStatus;
223 #endif
224     }
225 #endif
226   return FALSE;
227   }
228 
229 
230 //  Make the rendering context of GL Canvas current
makeNonCurrent()231 FXbool FXGLCanvas::makeNonCurrent(){
232 #ifdef HAVE_GL_H
233   if(ctx){
234 #ifndef WIN32
235     return glXMakeCurrent((Display*)getApp()->getDisplay(),None,(GLXContext)NULL);
236 #else
237     // According to "Steve Granja" <sjgranja@hks.com>,
238     // ::ReleaseDC is still necessary even for owned DC's.
239     // So release it here to prevent resource leak.
240     ::ReleaseDC((HWND)xid,wglGetCurrentDC());
241     BOOL bStatus=wglMakeCurrent(NULL,NULL);
242     return bStatus;
243 #endif
244     }
245 #endif
246   return FALSE;
247   }
248 
249 
250 // Return current context, if any
getCurrentContext()251 void* FXGLCanvas::getCurrentContext(){
252 #ifdef HAVE_GL_H
253 #ifndef WIN32
254   return (void*)glXGetCurrentContext();
255 #else
256   return (void*)wglGetCurrentContext();
257 #endif
258 #else
259   return NULL;
260 #endif
261   }
262 
263 
264 //  Return TRUE if this window's context is current
isCurrent() const265 FXbool FXGLCanvas::isCurrent() const {
266 #ifdef HAVE_GL_H
267   if(ctx){
268 #ifndef WIN32
269     return (glXGetCurrentContext() == (GLXContext)ctx);
270 #else
271     return (wglGetCurrentContext() == (HGLRC)ctx);
272 #endif
273     }
274 #endif
275   return FALSE;
276   }
277 
278 
279 // Used by GL to swap the buffers in double buffer mode, or flush a single buffer
swapBuffers()280 void FXGLCanvas::swapBuffers(){
281 #ifdef HAVE_GL_H
282 #ifndef WIN32
283   glXSwapBuffers((Display*)getApp()->getDisplay(),xid);
284 #else
285   // SwapBuffers(wglGetCurrentDC());
286   // wglSwapLayerBuffers(wglGetCurrentDC(),WGL_SWAP_MAIN_PLANE);
287   HDC hdc=wglGetCurrentDC();
288   if(wglSwapLayerBuffers(hdc,WGL_SWAP_MAIN_PLANE)==FALSE){
289     SwapBuffers(hdc);
290     }
291 #endif
292 #endif
293   }
294 
295 
296 // Save object to stream
save(FXStream & store) const297 void FXGLCanvas::save(FXStream& store) const {
298   FXWindow::save(store);
299   store << sgnext;
300   store << sgprev;
301   }
302 
303 
304 // Load object from stream
load(FXStream & store)305 void FXGLCanvas::load(FXStream& store){
306   FXWindow::load(store);
307   store >> sgnext;
308   store >> sgprev;
309   }
310 
311 
312 // Close and release any resources
~FXGLCanvas()313 FXGLCanvas::~FXGLCanvas(){
314   sgnext->sgprev=sgprev;
315   sgprev->sgnext=sgnext;
316   sgnext=(FXGLCanvas*)-1L;
317   sgprev=(FXGLCanvas*)-1L;
318 #ifdef HAVE_GL_H
319   if(ctx){
320 #ifndef WIN32
321     glXDestroyContext((Display*)getApp()->getDisplay(),(GLXContext)ctx);
322 #else
323     wglDeleteContext((HGLRC)ctx);
324 #endif
325     }
326 #endif
327   }
328 
329 }
330