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