]>
Commit | Line | Data |
---|---|---|
8b089c5e | 1 | ///////////////////////////////////////////////////////////////////////////// |
2b8646e0 | 2 | // Name: src/msw/glcanvas.cpp |
77ffb593 | 3 | // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under MS Windows |
8b089c5e JS |
4 | // Author: Julian Smart |
5 | // Modified by: | |
6 | // Created: 04/01/98 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Julian Smart | |
65571936 | 9 | // Licence: wxWindows licence |
8b089c5e JS |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
8b089c5e JS |
12 | #include "wx/wxprec.h" |
13 | ||
14 | #if defined(__BORLANDC__) | |
02761f6c | 15 | #pragma hdrstop |
8b089c5e JS |
16 | #endif |
17 | ||
8b089c5e JS |
18 | #if wxUSE_GLCANVAS |
19 | ||
20 | #ifndef WX_PRECOMP | |
af0b1533 VZ |
21 | #include "wx/frame.h" |
22 | #include "wx/settings.h" | |
23 | #include "wx/intl.h" | |
24 | #include "wx/log.h" | |
234d8e90 | 25 | #include "wx/app.h" |
02761f6c | 26 | #include "wx/module.h" |
8b089c5e JS |
27 | #endif |
28 | ||
af0b1533 | 29 | #include "wx/msw/private.h" |
8b089c5e | 30 | |
34fdf762 VS |
31 | // DLL options compatibility check: |
32 | #include "wx/build.h" | |
33 | WX_CHECK_BUILD_OPTIONS("wxGL") | |
34 | ||
af0b1533 | 35 | #include "wx/glcanvas.h" |
8b089c5e | 36 | |
b8ee9a86 WS |
37 | #if GL_EXT_vertex_array |
38 | #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) name | |
39 | #else | |
40 | #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) WXUNUSED(name) | |
41 | #endif | |
42 | ||
0e82bd96 VZ |
43 | /* |
44 | The following two compiler directives are specific to the Microsoft Visual | |
45 | C++ family of compilers | |
46 | ||
47 | Fundementally what they do is instruct the linker to use these two libraries | |
48 | for the resolution of symbols. In essence, this is the equivalent of adding | |
49 | these two libraries to either the Makefile or project file. | |
50 | ||
51 | This is NOT a recommended technique, and certainly is unlikely to be used | |
77ffb593 | 52 | anywhere else in wxWidgets given it is so specific to not only wxMSW, but |
0e82bd96 VZ |
53 | also the VC compiler. However, in the case of opengl support, it's an |
54 | applicable technique as opengl is optional in setup.h This code (wrapped by | |
55 | wxUSE_GLCANVAS), now allows opengl support to be added purely by modifying | |
56 | setup.h rather than by having to modify either the project or DSP fle. | |
57 | ||
58 | See MSDN for further information on the exact usage of these commands. | |
59 | */ | |
60 | #ifdef _MSC_VER | |
61 | # pragma comment( lib, "opengl32" ) | |
62 | # pragma comment( lib, "glu32" ) | |
63 | #endif | |
64 | ||
34fdf762 | 65 | |
b225f659 VZ |
66 | static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass"); |
67 | static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR"); | |
8b089c5e JS |
68 | |
69 | LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, | |
70 | WPARAM wParam, LPARAM lParam); | |
71 | ||
53fcd32e VZ |
72 | // ---------------------------------------------------------------------------- |
73 | // wxGLModule is responsible for unregistering wxGLCanvasClass Windows class | |
74 | // ---------------------------------------------------------------------------- | |
75 | ||
76 | class wxGLModule : public wxModule | |
77 | { | |
78 | public: | |
79 | bool OnInit() { return true; } | |
80 | void OnExit() { UnregisterClasses(); } | |
81 | ||
82 | // register the GL classes if not done yet, return true if ok, false if | |
83 | // registration failed | |
84 | static bool RegisterClasses(); | |
85 | ||
86 | // unregister the classes, done automatically on program termination | |
87 | static void UnregisterClasses(); | |
88 | ||
89 | private: | |
90 | // wxGLCanvas is only used from the main thread so this is MT-ok | |
91 | static bool ms_registeredGLClasses; | |
92 | ||
93 | DECLARE_DYNAMIC_CLASS(wxGLModule) | |
94 | }; | |
95 | ||
96 | IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule) | |
97 | ||
98 | bool wxGLModule::ms_registeredGLClasses = false; | |
99 | ||
100 | /* static */ | |
101 | bool wxGLModule::RegisterClasses() | |
102 | { | |
103 | if (ms_registeredGLClasses) | |
104 | return true; | |
105 | ||
106 | // We have to register a special window class because we need the CS_OWNDC | |
107 | // style for GLCanvas. | |
108 | ||
109 | /* | |
110 | From Angel Popov <jumpo@bitex.com> | |
111 | ||
112 | Here are two snips from a dicussion in the OpenGL Gamedev list that explains | |
113 | how this problem can be fixed: | |
114 | ||
115 | "There are 5 common DCs available in Win95. These are aquired when you call | |
116 | GetDC or GetDCEx from a window that does _not_ have the OWNDC flag. | |
117 | OWNDC flagged windows do not get their DC from the common DC pool, the issue | |
118 | is they require 800 bytes each from the limited 64Kb local heap for GDI." | |
119 | ||
120 | "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps | |
121 | do), Win95 will actually "steal" it from you. MakeCurrent fails, | |
122 | apparently, because Windows re-assigns the HDC to a different window. The | |
123 | only way to prevent this, the only reliable means, is to set CS_OWNDC." | |
124 | */ | |
125 | ||
126 | WNDCLASS wndclass; | |
127 | ||
128 | // the fields which are common to all classes | |
129 | wndclass.lpfnWndProc = (WNDPROC)wxWndProc; | |
130 | wndclass.cbClsExtra = 0; | |
131 | wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for? | |
132 | wndclass.hInstance = wxhInstance; | |
133 | wndclass.hIcon = (HICON) NULL; | |
134 | wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW); | |
135 | wndclass.lpszMenuName = NULL; | |
136 | ||
137 | // Register the GLCanvas class name | |
138 | wndclass.hbrBackground = (HBRUSH)NULL; | |
139 | wndclass.lpszClassName = wxGLCanvasClassName; | |
140 | wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC; | |
141 | ||
142 | if ( !::RegisterClass(&wndclass) ) | |
143 | { | |
144 | wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)")); | |
145 | return false; | |
146 | } | |
147 | ||
148 | // Register the GLCanvas class name for windows which don't do full repaint | |
149 | // on resize | |
150 | wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw; | |
151 | wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW); | |
152 | ||
153 | if ( !::RegisterClass(&wndclass) ) | |
154 | { | |
155 | wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)")); | |
156 | ||
157 | ::UnregisterClass(wxGLCanvasClassName, wxhInstance); | |
158 | ||
159 | return false; | |
160 | } | |
161 | ||
162 | ms_registeredGLClasses = true; | |
163 | ||
164 | return true; | |
165 | } | |
166 | ||
167 | /* static */ | |
168 | void wxGLModule::UnregisterClasses() | |
169 | { | |
170 | // we need to unregister the classes in case we're in a DLL which is | |
171 | // unloaded and then loaded again because if we don't, the registration is | |
172 | // going to fail in wxGLCanvas::Create() the next time we're loaded | |
173 | if ( ms_registeredGLClasses ) | |
174 | { | |
175 | ::UnregisterClass(wxGLCanvasClassName, wxhInstance); | |
176 | ::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance); | |
177 | ||
178 | ms_registeredGLClasses = false; | |
179 | } | |
180 | } | |
181 | ||
8b089c5e JS |
182 | /* |
183 | * GLContext implementation | |
184 | */ | |
185 | ||
2341cf5f | 186 | wxGLContext::wxGLContext(bool WXUNUSED(isRGB), wxGLCanvas *win, const wxPalette& WXUNUSED(palette)) |
8b089c5e JS |
187 | { |
188 | m_window = win; | |
189 | ||
190 | m_hDC = win->GetHDC(); | |
191 | ||
192 | m_glContext = wglCreateContext((HDC) m_hDC); | |
87b6002d | 193 | wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") ); |
8b089c5e JS |
194 | |
195 | wglMakeCurrent((HDC) m_hDC, m_glContext); | |
196 | } | |
197 | ||
198 | wxGLContext::wxGLContext( | |
2341cf5f MB |
199 | bool WXUNUSED(isRGB), wxGLCanvas *win, |
200 | const wxPalette& WXUNUSED(palette), | |
f48d169c UN |
201 | const wxGLContext *other /* for sharing display lists */ |
202 | ) | |
8b089c5e | 203 | { |
f48d169c | 204 | m_window = win; |
8b089c5e | 205 | |
f48d169c | 206 | m_hDC = win->GetHDC(); |
8b089c5e | 207 | |
f48d169c | 208 | m_glContext = wglCreateContext((HDC) m_hDC); |
87b6002d | 209 | wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") ); |
8b089c5e | 210 | |
f48d169c UN |
211 | if( other != 0 ) |
212 | wglShareLists( other->m_glContext, m_glContext ); | |
8b089c5e | 213 | |
f48d169c | 214 | wglMakeCurrent((HDC) m_hDC, m_glContext); |
8b089c5e JS |
215 | } |
216 | ||
217 | wxGLContext::~wxGLContext() | |
218 | { | |
219 | if (m_glContext) | |
220 | { | |
221 | wglMakeCurrent(NULL, NULL); | |
f48d169c | 222 | wglDeleteContext(m_glContext); |
8b089c5e JS |
223 | } |
224 | } | |
225 | ||
226 | void wxGLContext::SwapBuffers() | |
227 | { | |
228 | if (m_glContext) | |
229 | { | |
230 | wglMakeCurrent((HDC) m_hDC, m_glContext); | |
231 | ::SwapBuffers((HDC) m_hDC); //blits the backbuffer into DC | |
232 | } | |
233 | } | |
234 | ||
235 | void wxGLContext::SetCurrent() | |
236 | { | |
237 | if (m_glContext) | |
238 | { | |
239 | wglMakeCurrent((HDC) m_hDC, m_glContext); | |
240 | } | |
8b089c5e JS |
241 | } |
242 | ||
2b5f62a0 | 243 | void wxGLContext::SetColour(const wxChar *colour) |
8b089c5e | 244 | { |
564a150b VZ |
245 | wxColour col = wxTheColourDatabase->Find(colour); |
246 | if (col.Ok()) | |
247 | { | |
248 | float r = (float)(col.Red()/256.0); | |
249 | float g = (float)(col.Green()/256.0); | |
250 | float b = (float)(col.Blue()/256.0); | |
251 | glColor3f( r, g, b); | |
252 | } | |
8b089c5e JS |
253 | } |
254 | ||
255 | ||
256 | /* | |
257 | * wxGLCanvas implementation | |
258 | */ | |
259 | ||
4660d7e5 | 260 | IMPLEMENT_CLASS(wxGLCanvas, wxWindow) |
8b089c5e | 261 | |
4660d7e5 | 262 | BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow) |
8b089c5e JS |
263 | EVT_SIZE(wxGLCanvas::OnSize) |
264 | EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged) | |
265 | EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette) | |
266 | END_EVENT_TABLE() | |
267 | ||
268 | wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, | |
269 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, | |
4660d7e5 | 270 | int *attribList, const wxPalette& palette) : wxWindow() |
8b089c5e | 271 | { |
f48d169c | 272 | m_glContext = (wxGLContext*) NULL; |
8b089c5e | 273 | |
f48d169c | 274 | bool ret = Create(parent, id, pos, size, style, name); |
8b089c5e | 275 | |
f48d169c UN |
276 | if ( ret ) |
277 | { | |
a756f210 | 278 | SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); |
f48d169c | 279 | } |
8b089c5e | 280 | |
f48d169c | 281 | m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); |
8b089c5e | 282 | |
f48d169c UN |
283 | SetupPixelFormat(attribList); |
284 | SetupPalette(palette); | |
8b089c5e | 285 | |
213ceb3f | 286 | m_glContext = new wxGLContext(true, this, palette); |
8b089c5e JS |
287 | } |
288 | ||
289 | wxGLCanvas::wxGLCanvas( wxWindow *parent, | |
290 | const wxGLContext *shared, wxWindowID id, | |
291 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, | |
292 | int *attribList, const wxPalette& palette ) | |
4660d7e5 | 293 | : wxWindow() |
8b089c5e | 294 | { |
f48d169c | 295 | m_glContext = (wxGLContext*) NULL; |
8b089c5e | 296 | |
f48d169c | 297 | bool ret = Create(parent, id, pos, size, style, name); |
8b089c5e | 298 | |
f48d169c UN |
299 | if ( ret ) |
300 | { | |
a756f210 | 301 | SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); |
f48d169c | 302 | } |
8b089c5e | 303 | |
f48d169c | 304 | m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); |
8b089c5e | 305 | |
f48d169c UN |
306 | SetupPixelFormat(attribList); |
307 | SetupPalette(palette); | |
8b089c5e | 308 | |
213ceb3f | 309 | m_glContext = new wxGLContext(true, this, palette, shared ); |
8b089c5e JS |
310 | } |
311 | ||
f6bcfd97 | 312 | // Not very useful for wxMSW, but this is to be wxGTK compliant |
8b089c5e JS |
313 | |
314 | wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id, | |
315 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, | |
316 | int *attribList, const wxPalette& palette ): | |
4660d7e5 | 317 | wxWindow() |
8b089c5e | 318 | { |
f48d169c | 319 | m_glContext = (wxGLContext*) NULL; |
8b089c5e | 320 | |
f48d169c | 321 | bool ret = Create(parent, id, pos, size, style, name); |
8b089c5e | 322 | |
f48d169c UN |
323 | if ( ret ) |
324 | { | |
a756f210 | 325 | SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); |
f48d169c | 326 | } |
8b089c5e | 327 | |
f48d169c | 328 | m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); |
8b089c5e | 329 | |
f48d169c UN |
330 | SetupPixelFormat(attribList); |
331 | SetupPalette(palette); | |
8b089c5e | 332 | |
f48d169c UN |
333 | wxGLContext *sharedContext=0; |
334 | if (shared) sharedContext=shared->GetContext(); | |
213ceb3f | 335 | m_glContext = new wxGLContext(true, this, palette, sharedContext ); |
8b089c5e JS |
336 | } |
337 | ||
338 | wxGLCanvas::~wxGLCanvas() | |
339 | { | |
53fcd32e | 340 | delete m_glContext; |
8b089c5e JS |
341 | |
342 | ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC); | |
343 | } | |
344 | ||
b225f659 VZ |
345 | // Replaces wxWindow::Create functionality, since we need to use a different |
346 | // window class | |
347 | bool wxGLCanvas::Create(wxWindow *parent, | |
348 | wxWindowID id, | |
349 | const wxPoint& pos, | |
350 | const wxSize& size, | |
351 | long style, | |
352 | const wxString& name) | |
8b089c5e | 353 | { |
53fcd32e | 354 | wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") ); |
8b089c5e | 355 | |
53fcd32e | 356 | if ( !wxGLModule::RegisterClasses() ) |
b225f659 | 357 | { |
53fcd32e | 358 | wxLogError(_("Failed to register OpenGL window class.")); |
b225f659 | 359 | |
213ceb3f | 360 | return false; |
b225f659 VZ |
361 | } |
362 | ||
53fcd32e VZ |
363 | if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) |
364 | return false; | |
f48d169c | 365 | |
53fcd32e | 366 | parent->AddChild(this); |
f48d169c | 367 | |
53fcd32e | 368 | DWORD msflags = 0; |
f48d169c | 369 | |
53fcd32e VZ |
370 | /* |
371 | A general rule with OpenGL and Win32 is that any window that will have a | |
372 | HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS. | |
373 | You can find references about this within the knowledge base and most OpenGL | |
374 | books that contain the wgl function descriptions. | |
375 | */ | |
8b089c5e | 376 | |
53fcd32e VZ |
377 | WXDWORD exStyle = 0; |
378 | msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; | |
379 | msflags |= MSWGetStyle(style, & exStyle) ; | |
f48d169c | 380 | |
53fcd32e | 381 | return MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle); |
8b089c5e JS |
382 | } |
383 | ||
a3081354 | 384 | static void AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, int *attribList) |
8b089c5e | 385 | { |
f48d169c UN |
386 | if (attribList) { |
387 | pfd.dwFlags &= ~PFD_DOUBLEBUFFER; | |
388 | pfd.iPixelType = PFD_TYPE_COLORINDEX; | |
389 | pfd.cColorBits = 0; | |
390 | int arg=0; | |
b225f659 | 391 | |
f48d169c UN |
392 | while( (attribList[arg]!=0) ) |
393 | { | |
394 | switch( attribList[arg++] ) | |
395 | { | |
396 | case WX_GL_RGBA: | |
397 | pfd.iPixelType = PFD_TYPE_RGBA; | |
398 | break; | |
399 | case WX_GL_BUFFER_SIZE: | |
b8ee9a86 | 400 | pfd.cColorBits = (BYTE)attribList[arg++]; |
f48d169c UN |
401 | break; |
402 | case WX_GL_LEVEL: | |
403 | // this member looks like it may be obsolete | |
404 | if (attribList[arg] > 0) { | |
d728116a | 405 | pfd.iLayerType = (BYTE)PFD_OVERLAY_PLANE; |
f48d169c | 406 | } else if (attribList[arg] < 0) { |
d728116a | 407 | pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE; |
f48d169c | 408 | } else { |
d728116a | 409 | pfd.iLayerType = (BYTE)PFD_MAIN_PLANE; |
f48d169c UN |
410 | } |
411 | arg++; | |
412 | break; | |
413 | case WX_GL_DOUBLEBUFFER: | |
414 | pfd.dwFlags |= PFD_DOUBLEBUFFER; | |
415 | break; | |
416 | case WX_GL_STEREO: | |
417 | pfd.dwFlags |= PFD_STEREO; | |
418 | break; | |
419 | case WX_GL_AUX_BUFFERS: | |
b8ee9a86 | 420 | pfd.cAuxBuffers = (BYTE)attribList[arg++]; |
f48d169c UN |
421 | break; |
422 | case WX_GL_MIN_RED: | |
b8ee9a86 | 423 | pfd.cColorBits = (BYTE)(pfd.cColorBits + (pfd.cRedBits = (BYTE)attribList[arg++])); |
f48d169c UN |
424 | break; |
425 | case WX_GL_MIN_GREEN: | |
b8ee9a86 | 426 | pfd.cColorBits = (BYTE)(pfd.cColorBits + (pfd.cGreenBits = (BYTE)attribList[arg++])); |
f48d169c UN |
427 | break; |
428 | case WX_GL_MIN_BLUE: | |
b8ee9a86 | 429 | pfd.cColorBits = (BYTE)(pfd.cColorBits + (pfd.cBlueBits = (BYTE)attribList[arg++])); |
f48d169c UN |
430 | break; |
431 | case WX_GL_MIN_ALPHA: | |
432 | // doesn't count in cColorBits | |
b8ee9a86 | 433 | pfd.cAlphaBits = (BYTE)attribList[arg++]; |
f48d169c | 434 | break; |
b225f659 | 435 | case WX_GL_DEPTH_SIZE: |
b8ee9a86 | 436 | pfd.cDepthBits = (BYTE)attribList[arg++]; |
f48d169c | 437 | break; |
b225f659 | 438 | case WX_GL_STENCIL_SIZE: |
b8ee9a86 | 439 | pfd.cStencilBits = (BYTE)attribList[arg++]; |
f48d169c UN |
440 | break; |
441 | case WX_GL_MIN_ACCUM_RED: | |
b8ee9a86 | 442 | pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumRedBits = (BYTE)attribList[arg++])); |
f48d169c UN |
443 | break; |
444 | case WX_GL_MIN_ACCUM_GREEN: | |
b8ee9a86 | 445 | pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumGreenBits = (BYTE)attribList[arg++])); |
f48d169c UN |
446 | break; |
447 | case WX_GL_MIN_ACCUM_BLUE: | |
b8ee9a86 | 448 | pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumBlueBits = (BYTE)attribList[arg++])); |
f48d169c UN |
449 | break; |
450 | case WX_GL_MIN_ACCUM_ALPHA: | |
b8ee9a86 | 451 | pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumAlphaBits = (BYTE)attribList[arg++])); |
f48d169c UN |
452 | break; |
453 | default: | |
454 | break; | |
455 | } | |
8b089c5e | 456 | } |
f48d169c | 457 | } |
a3081354 VZ |
458 | } |
459 | ||
460 | void wxGLCanvas::SetupPixelFormat(int *attribList) // (HDC hDC) | |
461 | { | |
a3081354 | 462 | PIXELFORMATDESCRIPTOR pfd = { |
b225f659 VZ |
463 | sizeof(PIXELFORMATDESCRIPTOR), /* size */ |
464 | 1, /* version */ | |
465 | PFD_SUPPORT_OPENGL | | |
466 | PFD_DRAW_TO_WINDOW | | |
467 | PFD_DOUBLEBUFFER, /* support double-buffering */ | |
468 | PFD_TYPE_RGBA, /* color type */ | |
3103e8a9 | 469 | 16, /* preferred color depth */ |
b225f659 VZ |
470 | 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ |
471 | 0, /* no alpha buffer */ | |
472 | 0, /* alpha bits (ignored) */ | |
473 | 0, /* no accumulation buffer */ | |
474 | 0, 0, 0, 0, /* accum bits (ignored) */ | |
475 | 16, /* depth buffer */ | |
476 | 0, /* no stencil buffer */ | |
477 | 0, /* no auxiliary buffers */ | |
478 | PFD_MAIN_PLANE, /* main layer */ | |
479 | 0, /* reserved */ | |
480 | 0, 0, 0, /* no layer, visible, damage masks */ | |
481 | }; | |
a3081354 VZ |
482 | |
483 | AdjustPFDForAttributes(pfd, attribList); | |
484 | ||
72adfc4b | 485 | int pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd); |
f48d169c | 486 | if (pixelFormat == 0) { |
72adfc4b | 487 | wxLogLastError(_T("ChoosePixelFormat")); |
f48d169c | 488 | } |
a3081354 | 489 | else { |
72adfc4b VZ |
490 | if ( !::SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) ) { |
491 | wxLogLastError(_T("SetPixelFormat")); | |
a3081354 | 492 | } |
f48d169c | 493 | } |
8b089c5e JS |
494 | } |
495 | ||
496 | void wxGLCanvas::SetupPalette(const wxPalette& palette) | |
497 | { | |
498 | int pixelFormat = GetPixelFormat((HDC) m_hDC); | |
499 | PIXELFORMATDESCRIPTOR pfd; | |
500 | ||
501 | DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); | |
502 | ||
503 | if (pfd.dwFlags & PFD_NEED_PALETTE) | |
504 | { | |
505 | } | |
506 | else | |
507 | { | |
b225f659 | 508 | return; |
8b089c5e JS |
509 | } |
510 | ||
511 | m_palette = palette; | |
512 | ||
513 | if ( !m_palette.Ok() ) | |
514 | { | |
515 | m_palette = CreateDefaultPalette(); | |
516 | } | |
517 | ||
518 | if (m_palette.Ok()) | |
519 | { | |
213ceb3f WS |
520 | ::SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE); |
521 | ::RealizePalette((HDC) m_hDC); | |
8b089c5e JS |
522 | } |
523 | } | |
524 | ||
525 | wxPalette wxGLCanvas::CreateDefaultPalette() | |
526 | { | |
527 | PIXELFORMATDESCRIPTOR pfd; | |
528 | int paletteSize; | |
529 | int pixelFormat = GetPixelFormat((HDC) m_hDC); | |
530 | ||
531 | DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); | |
532 | ||
f48d169c | 533 | paletteSize = 1 << pfd.cColorBits; |
8b089c5e JS |
534 | |
535 | LOGPALETTE* pPal = | |
536 | (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY)); | |
537 | pPal->palVersion = 0x300; | |
b8ee9a86 | 538 | pPal->palNumEntries = (WORD)paletteSize; |
8b089c5e JS |
539 | |
540 | /* build a simple RGB color palette */ | |
541 | { | |
b225f659 VZ |
542 | int redMask = (1 << pfd.cRedBits) - 1; |
543 | int greenMask = (1 << pfd.cGreenBits) - 1; | |
544 | int blueMask = (1 << pfd.cBlueBits) - 1; | |
545 | int i; | |
546 | ||
547 | for (i=0; i<paletteSize; ++i) { | |
548 | pPal->palPalEntry[i].peRed = | |
b8ee9a86 | 549 | (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask); |
b225f659 | 550 | pPal->palPalEntry[i].peGreen = |
b8ee9a86 | 551 | (BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask); |
b225f659 | 552 | pPal->palPalEntry[i].peBlue = |
b8ee9a86 | 553 | (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask); |
b225f659 VZ |
554 | pPal->palPalEntry[i].peFlags = 0; |
555 | } | |
8b089c5e JS |
556 | } |
557 | ||
558 | HPALETTE hPalette = CreatePalette(pPal); | |
559 | free(pPal); | |
560 | ||
561 | wxPalette palette; | |
562 | palette.SetHPALETTE((WXHPALETTE) hPalette); | |
563 | ||
564 | return palette; | |
565 | } | |
566 | ||
567 | void wxGLCanvas::SwapBuffers() | |
568 | { | |
569 | if (m_glContext) | |
570 | m_glContext->SwapBuffers(); | |
571 | } | |
572 | ||
2341cf5f | 573 | void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event)) |
8b089c5e | 574 | { |
8b089c5e JS |
575 | } |
576 | ||
577 | void wxGLCanvas::SetCurrent() | |
578 | { | |
2d918775 VZ |
579 | // although on MSW it works even if the window is still hidden, it doesn't |
580 | // under wxGTK and documentation mentions that SetCurrent() can only be | |
581 | // called for a shown window, so check it | |
582 | wxASSERT_MSG( GetParent()->IsShown(), | |
583 | _T("can't make hidden GL canvas current") ); | |
584 | ||
8b089c5e JS |
585 | if (m_glContext) |
586 | { | |
587 | m_glContext->SetCurrent(); | |
588 | } | |
589 | } | |
590 | ||
2b5f62a0 | 591 | void wxGLCanvas::SetColour(const wxChar *colour) |
8b089c5e JS |
592 | { |
593 | if (m_glContext) | |
594 | m_glContext->SetColour(colour); | |
595 | } | |
596 | ||
597 | // TODO: Have to have this called by parent frame (?) | |
598 | // So we need wxFrame to call OnQueryNewPalette for all children... | |
599 | void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event) | |
600 | { | |
f48d169c UN |
601 | /* realize palette if this is the current window */ |
602 | if ( GetPalette()->Ok() ) { | |
603 | ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE()); | |
604 | ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); | |
605 | ::RealizePalette((HDC) GetHDC()); | |
606 | Refresh(); | |
213ceb3f | 607 | event.SetPaletteRealized(true); |
f48d169c UN |
608 | } |
609 | else | |
213ceb3f | 610 | event.SetPaletteRealized(false); |
8b089c5e JS |
611 | } |
612 | ||
613 | // I think this doesn't have to be propagated to child windows. | |
614 | void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event) | |
615 | { | |
f48d169c UN |
616 | /* realize palette if this is *not* the current window */ |
617 | if ( GetPalette() && | |
8b089c5e | 618 | GetPalette()->Ok() && (this != event.GetChangedWindow()) ) |
f48d169c UN |
619 | { |
620 | ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE()); | |
621 | ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); | |
622 | ::RealizePalette((HDC) GetHDC()); | |
623 | Refresh(); | |
624 | } | |
8b089c5e JS |
625 | } |
626 | ||
627 | /* Give extensions proper function names. */ | |
628 | ||
629 | /* EXT_vertex_array */ | |
2341cf5f | 630 | void glArrayElementEXT(GLint WXUNUSED(i)) |
8b089c5e JS |
631 | { |
632 | } | |
633 | ||
2341cf5f | 634 | void glColorPointerEXT(GLint WXUNUSED(size), GLenum WXUNUSED(type), GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLvoid *WXUNUSED(pointer)) |
8b089c5e JS |
635 | { |
636 | } | |
637 | ||
b8ee9a86 WS |
638 | void glDrawArraysEXT(GLenum WXUNUSED_WITHOUT_GL_EXT_vertex_array(mode), |
639 | GLint WXUNUSED_WITHOUT_GL_EXT_vertex_array(first), | |
640 | GLsizei WXUNUSED_WITHOUT_GL_EXT_vertex_array(count)) | |
8b089c5e JS |
641 | { |
642 | #ifdef GL_EXT_vertex_array | |
643 | static PFNGLDRAWARRAYSEXTPROC proc = 0; | |
644 | ||
645 | if ( !proc ) | |
646 | { | |
647 | proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT"); | |
648 | } | |
649 | ||
650 | if ( proc ) | |
651 | (* proc) (mode, first, count); | |
652 | #endif | |
653 | } | |
654 | ||
2341cf5f | 655 | void glEdgeFlagPointerEXT(GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLboolean *WXUNUSED(pointer)) |
8b089c5e JS |
656 | { |
657 | } | |
658 | ||
2341cf5f | 659 | void glGetPointervEXT(GLenum WXUNUSED(pname), GLvoid* *WXUNUSED(params)) |
8b089c5e JS |
660 | { |
661 | } | |
662 | ||
2341cf5f | 663 | void glIndexPointerEXT(GLenum WXUNUSED(type), GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLvoid *WXUNUSED(pointer)) |
8b089c5e JS |
664 | { |
665 | } | |
666 | ||
b8ee9a86 WS |
667 | void glNormalPointerEXT(GLenum WXUNUSED_WITHOUT_GL_EXT_vertex_array(type), |
668 | GLsizei WXUNUSED_WITHOUT_GL_EXT_vertex_array(stride), | |
669 | GLsizei WXUNUSED_WITHOUT_GL_EXT_vertex_array(count), | |
670 | const GLvoid *WXUNUSED_WITHOUT_GL_EXT_vertex_array(pointer)) | |
8b089c5e JS |
671 | { |
672 | #ifdef GL_EXT_vertex_array | |
f48d169c | 673 | static PFNGLNORMALPOINTEREXTPROC proc = 0; |
8b089c5e | 674 | |
f48d169c UN |
675 | if ( !proc ) |
676 | { | |
677 | proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT"); | |
678 | } | |
8b089c5e | 679 | |
f48d169c UN |
680 | if ( proc ) |
681 | (* proc) (type, stride, count, pointer); | |
8b089c5e JS |
682 | #endif |
683 | } | |
684 | ||
2341cf5f | 685 | void glTexCoordPointerEXT(GLint WXUNUSED(size), GLenum WXUNUSED(type), GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLvoid *WXUNUSED(pointer)) |
8b089c5e JS |
686 | { |
687 | } | |
688 | ||
b8ee9a86 WS |
689 | void glVertexPointerEXT(GLint WXUNUSED_WITHOUT_GL_EXT_vertex_array(size), |
690 | GLenum WXUNUSED_WITHOUT_GL_EXT_vertex_array(type), | |
691 | GLsizei WXUNUSED_WITHOUT_GL_EXT_vertex_array(stride), | |
692 | GLsizei WXUNUSED_WITHOUT_GL_EXT_vertex_array(count), | |
693 | const GLvoid *WXUNUSED_WITHOUT_GL_EXT_vertex_array(pointer)) | |
8b089c5e JS |
694 | { |
695 | #ifdef GL_EXT_vertex_array | |
f48d169c | 696 | static PFNGLVERTEXPOINTEREXTPROC proc = 0; |
8b089c5e | 697 | |
f48d169c UN |
698 | if ( !proc ) |
699 | { | |
700 | proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT"); | |
701 | } | |
702 | if ( proc ) | |
703 | (* proc) (size, type, stride, count, pointer); | |
8b089c5e JS |
704 | #endif |
705 | } | |
706 | ||
707 | /* EXT_color_subtable */ | |
2341cf5f | 708 | void glColorSubtableEXT(GLenum WXUNUSED(target), GLsizei WXUNUSED(start), GLsizei WXUNUSED(count), GLenum WXUNUSED(format), GLenum WXUNUSED(type), const GLvoid *WXUNUSED(table)) |
8b089c5e JS |
709 | { |
710 | } | |
711 | ||
712 | /* EXT_color_table */ | |
2341cf5f | 713 | void glColorTableEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(internalformat), GLsizei WXUNUSED(width), GLenum WXUNUSED(format), GLenum WXUNUSED(type), const GLvoid *WXUNUSED(table)) |
8b089c5e JS |
714 | { |
715 | } | |
716 | ||
2341cf5f | 717 | void glCopyColorTableEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(internalformat), GLint WXUNUSED(x), GLint WXUNUSED(y), GLsizei WXUNUSED(width)) |
8b089c5e JS |
718 | { |
719 | } | |
720 | ||
2341cf5f | 721 | void glGetColorTableEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(format), GLenum WXUNUSED(type), GLvoid *WXUNUSED(table)) |
8b089c5e JS |
722 | { |
723 | } | |
724 | ||
2341cf5f | 725 | void glGetColorTableParamaterfvEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(pname), GLfloat *WXUNUSED(params)) |
8b089c5e JS |
726 | { |
727 | } | |
728 | ||
2341cf5f | 729 | void glGetColorTavleParameterivEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(pname), GLint *WXUNUSED(params)) |
8b089c5e JS |
730 | { |
731 | } | |
732 | ||
733 | /* SGI_compiled_vertex_array */ | |
2341cf5f | 734 | void glLockArraysSGI(GLint WXUNUSED(first), GLsizei WXUNUSED(count)) |
8b089c5e JS |
735 | { |
736 | } | |
737 | ||
738 | void glUnlockArraysSGI() | |
739 | { | |
740 | } | |
741 | ||
742 | ||
743 | /* SGI_cull_vertex */ | |
2341cf5f | 744 | void glCullParameterdvSGI(GLenum WXUNUSED(pname), GLdouble* WXUNUSED(params)) |
8b089c5e JS |
745 | { |
746 | } | |
747 | ||
2341cf5f | 748 | void glCullParameterfvSGI(GLenum WXUNUSED(pname), GLfloat* WXUNUSED(params)) |
8b089c5e JS |
749 | { |
750 | } | |
751 | ||
752 | /* SGI_index_func */ | |
2341cf5f | 753 | void glIndexFuncSGI(GLenum WXUNUSED(func), GLclampf WXUNUSED(ref)) |
8b089c5e JS |
754 | { |
755 | } | |
756 | ||
757 | /* SGI_index_material */ | |
2341cf5f | 758 | void glIndexMaterialSGI(GLenum WXUNUSED(face), GLenum WXUNUSED(mode)) |
8b089c5e JS |
759 | { |
760 | } | |
761 | ||
762 | /* WIN_swap_hint */ | |
2341cf5f | 763 | void glAddSwapHintRectWin(GLint WXUNUSED(x), GLint WXUNUSED(y), GLsizei WXUNUSED(width), GLsizei WXUNUSED(height)) |
8b089c5e JS |
764 | { |
765 | } | |
766 | ||
a3081354 VZ |
767 | |
768 | //--------------------------------------------------------------------------- | |
769 | // wxGLApp | |
770 | //--------------------------------------------------------------------------- | |
771 | ||
772 | IMPLEMENT_CLASS(wxGLApp, wxApp) | |
773 | ||
774 | bool wxGLApp::InitGLVisual(int *attribList) | |
775 | { | |
776 | int pixelFormat; | |
777 | PIXELFORMATDESCRIPTOR pfd = { | |
b225f659 VZ |
778 | sizeof(PIXELFORMATDESCRIPTOR), /* size */ |
779 | 1, /* version */ | |
780 | PFD_SUPPORT_OPENGL | | |
781 | PFD_DRAW_TO_WINDOW | | |
782 | PFD_DOUBLEBUFFER, /* support double-buffering */ | |
783 | PFD_TYPE_RGBA, /* color type */ | |
3103e8a9 | 784 | 16, /* preferred color depth */ |
b225f659 VZ |
785 | 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ |
786 | 0, /* no alpha buffer */ | |
787 | 0, /* alpha bits (ignored) */ | |
788 | 0, /* no accumulation buffer */ | |
789 | 0, 0, 0, 0, /* accum bits (ignored) */ | |
790 | 16, /* depth buffer */ | |
791 | 0, /* no stencil buffer */ | |
792 | 0, /* no auxiliary buffers */ | |
793 | PFD_MAIN_PLANE, /* main layer */ | |
794 | 0, /* reserved */ | |
795 | 0, 0, 0, /* no layer, visible, damage masks */ | |
796 | }; | |
a3081354 VZ |
797 | |
798 | AdjustPFDForAttributes(pfd, attribList); | |
799 | ||
800 | // use DC for whole (root) screen, since no windows have yet been created | |
2b8646e0 | 801 | pixelFormat = ChoosePixelFormat(ScreenHDC(), &pfd); |
a3081354 VZ |
802 | |
803 | if (pixelFormat == 0) { | |
804 | wxLogError(_("Failed to initialize OpenGL")); | |
213ceb3f | 805 | return false; |
a3081354 VZ |
806 | } |
807 | ||
213ceb3f | 808 | return true; |
a3081354 VZ |
809 | } |
810 | ||
811 | wxGLApp::~wxGLApp() | |
812 | { | |
813 | } | |
814 | ||
8b089c5e JS |
815 | #endif |
816 | // wxUSE_GLCANVAS |