1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxGLCanvas, for using OpenGL with wxWindows under MS Windows 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "glcanvas.h" 
  16 #include "wx/wxprec.h" 
  18 #if defined(__BORLANDC__) 
  30 #include <wx/msw/private.h> 
  31 #include <wx/settings.h> 
  34 #include <wx/glcanvas.h> 
  36 wxChar wxGLCanvasClassName
[]        = wxT("wxGLCanvasClass"); 
  38 LRESULT WXDLLEXPORT APIENTRY _EXPORT 
wxWndProc(HWND hWnd
, UINT message
, 
  39                                    WPARAM wParam
, LPARAM lParam
); 
  42  * GLContext implementation 
  45 wxGLContext::wxGLContext(bool isRGB
, wxGLCanvas 
*win
, const wxPalette
& palette
) 
  49   m_hDC 
= win
->GetHDC(); 
  51   m_glContext 
= wglCreateContext((HDC
) m_hDC
); 
  52   wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGl context") ); 
  54   wglMakeCurrent((HDC
) m_hDC
, m_glContext
); 
  57 wxGLContext::wxGLContext( 
  58                bool isRGB
, wxGLCanvas 
*win
, 
  59                const wxPalette
& palette
, 
  60                const wxGLContext 
*other        
/* for sharing display lists */ 
  65     m_hDC 
= win
->GetHDC(); 
  67     m_glContext 
= wglCreateContext((HDC
) m_hDC
); 
  68     wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGl context") ); 
  71       wglShareLists( other
->m_glContext
, m_glContext 
); 
  73     wglMakeCurrent((HDC
) m_hDC
, m_glContext
); 
  76 wxGLContext::~wxGLContext() 
  80     wglMakeCurrent(NULL
, NULL
); 
  81         wglDeleteContext(m_glContext
); 
  85 void wxGLContext::SwapBuffers() 
  89     wglMakeCurrent((HDC
) m_hDC
, m_glContext
); 
  90     ::SwapBuffers((HDC
) m_hDC
);    //blits the backbuffer into DC 
  94 void wxGLContext::SetCurrent() 
  98     wglMakeCurrent((HDC
) m_hDC
, m_glContext
); 
 102         setupPixelFormat(hDC); 
 107 void wxGLContext::SetColour(const char *colour
) 
 112   wxColour 
*col 
= wxTheColourDatabase
->FindColour(colour
); 
 115     r 
= (float)(col
->Red()/256.0); 
 116     g 
= (float)(col
->Green()/256.0); 
 117     b 
= (float)(col
->Blue()/256.0); 
 124  * wxGLCanvas implementation 
 127 IMPLEMENT_CLASS(wxGLCanvas
, wxScrolledWindow
) 
 129 BEGIN_EVENT_TABLE(wxGLCanvas
, wxScrolledWindow
) 
 130     EVT_SIZE(wxGLCanvas::OnSize
) 
 131     EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged
) 
 132     EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette
) 
 135 wxGLCanvas::wxGLCanvas(wxWindow 
*parent
, wxWindowID id
, 
 136     const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
, 
 137     int *attribList 
/* not used yet! */, const wxPalette
& palette
): 
 140     m_glContext 
= (wxGLContext
*) NULL
; 
 142     bool ret 
= Create(parent
, id
, pos
, size
, style
, name
); 
 146         SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
)); 
 147         SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
)); 
 150         m_hDC 
= (WXHDC
) ::GetDC((HWND
) GetHWND()); 
 153     SetupPalette(palette
); 
 155     m_glContext 
= new wxGLContext(TRUE
, this, palette
); 
 158 wxGLCanvas::wxGLCanvas( wxWindow 
*parent
, 
 159               const wxGLContext 
*shared
, wxWindowID id
, 
 160               const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
, 
 161               int *attribList
, const wxPalette
& palette 
) 
 164    m_glContext 
= (wxGLContext
*) NULL
; 
 166    bool ret 
= Create(parent
, id
, pos
, size
, style
, name
); 
 170         SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
)); 
 171         SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
)); 
 174     m_hDC 
= (WXHDC
) ::GetDC((HWND
) GetHWND()); 
 177     SetupPalette(palette
); 
 179     m_glContext 
= new wxGLContext(TRUE
, this, palette
, shared 
); 
 182 // Not very useful for wxMSW, but this is to be wxGTK compliant 
 184 wxGLCanvas::wxGLCanvas( wxWindow 
*parent
, const wxGLCanvas 
*shared
, wxWindowID id
, 
 185                         const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
, 
 186                         int *attribList
, const wxPalette
& palette 
): 
 189     m_glContext 
= (wxGLContext
*) NULL
; 
 191     bool ret 
= Create(parent
, id
, pos
, size
, style
, name
); 
 195         SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
)); 
 196         SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
)); 
 199         m_hDC 
= (WXHDC
) ::GetDC((HWND
) GetHWND()); 
 202     SetupPalette(palette
); 
 204     wxGLContext 
*sharedContext
=0; 
 205     if (shared
) sharedContext
=shared
->GetContext(); 
 206     m_glContext 
= new wxGLContext(TRUE
, this, palette
, sharedContext 
); 
 209 wxGLCanvas::~wxGLCanvas() 
 214   ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
); 
 217 // Replaces wxWindow::Create functionality, since we need to use a different window class 
 218 bool wxGLCanvas::Create(wxWindow 
*parent
, wxWindowID id
, 
 219               const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
) 
 221 /* Suggestion from Kelly Brock <kbrock@8cs.com> (not yet implemented): 
 223 OpenGL corruption fix is simple assuming it doesn't screw anything else 
 224 up.  Add the following line to the top of the create function: 
 225         wxSize parentSize = GetClientSize(); 
 226         All locations within the function that use 'size' are changed to 
 228         The above corrects the initial display corruption with the GeForce and 
 229 TNT2, not sure about other NVidia cards yet. 
 232     static bool registeredGLCanvasClass 
= FALSE
; 
 234     // We have to register a special window class because we need 
 235     // the CS_OWNDC style for GLCanvas. 
 238     From Angel Popov <jumpo@bitex.com> 
 240     Here are two snips from a dicussion in the OpenGL Gamedev list that explains 
 241     how this problem can be fixed: 
 243     "There are 5 common DCs available in Win95. These are aquired when you call 
 244     GetDC or GetDCEx from a window that does _not_ have the OWNDC flag. 
 245     OWNDC flagged windows do not get their DC from the common DC pool, the issue 
 246     is they require 800 bytes each from the limited 64Kb local heap for GDI." 
 248     "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps 
 249     do), Win95 will actually "steal" it from you.  MakeCurrent fails, 
 250     apparently, because Windows re-assigns the HDC to a different window.  The 
 251     only way to prevent this, the only reliable means, is to set CS_OWNDC." 
 254     if (!registeredGLCanvasClass
) 
 258         static const long styleNormal 
= CS_HREDRAW 
| CS_VREDRAW 
| CS_DBLCLKS 
| CS_OWNDC
; 
 260         // the fields which are common to all classes 
 261         wndclass
.lpfnWndProc   
= (WNDPROC
)wxWndProc
; 
 262         wndclass
.cbClsExtra    
= 0; 
 263         wndclass
.cbWndExtra    
= sizeof( DWORD 
); // VZ: what is this DWORD used for? 
 264         wndclass
.hInstance     
= wxhInstance
; 
 265         wndclass
.hIcon         
= (HICON
) NULL
; 
 266         wndclass
.hCursor       
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
); 
 267         wndclass
.lpszMenuName  
= NULL
; 
 269         // Register the GLCanvas class name 
 270         wndclass
.hbrBackground 
= (HBRUSH
)NULL
; 
 271         wndclass
.lpszClassName 
= wxGLCanvasClassName
; 
 272         wndclass
.style         
= styleNormal
; 
 274         if ( !RegisterClass(&wndclass
) ) 
 276             wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)")); 
 280         registeredGLCanvasClass 
= TRUE
; 
 283     wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") ); 
 285     if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) ) 
 288     parent
->AddChild(this); 
 291     if ( style 
& wxBORDER 
) 
 292         msflags 
|= WS_BORDER
; 
 293     if ( style 
& wxTHICK_FRAME 
) 
 294         msflags 
|= WS_THICKFRAME
; 
 297         A general rule with OpenGL and Win32 is that any window that will have a 
 298         HGLRC built for it must have two flags:  WS_CLIPCHILDREN & WS_CLIPSIBLINGS. 
 299         You can find references about this within the knowledge base and most OpenGL 
 300         books that contain the wgl function descriptions. 
 303     msflags 
|= WS_CHILD 
| WS_VISIBLE 
| WS_CLIPSIBLINGS
; 
 304 //    if ( style & wxCLIP_CHILDREN ) 
 305 //        msflags |= WS_CLIPCHILDREN; 
 306     msflags 
|= WS_CLIPCHILDREN
; 
 309     WXDWORD exStyle 
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
); 
 311     // Even with extended styles, need to combine with WS_BORDER 
 312     // for them to look right. 
 313     if ( want3D 
|| (m_windowStyle 
& wxSIMPLE_BORDER
) || (m_windowStyle 
& wxRAISED_BORDER 
) || 
 314         (m_windowStyle 
& wxSUNKEN_BORDER
) || (m_windowStyle 
& wxDOUBLE_BORDER
)) 
 316         msflags 
|= WS_BORDER
; 
 319     // calculate the value to return from WM_GETDLGCODE handler 
 320     if ( GetWindowStyleFlag() & wxWANTS_CHARS 
) 
 322         // want everything: i.e. all keys and WM_CHAR message 
 323         m_lDlgCode 
= DLGC_WANTARROWS 
| DLGC_WANTCHARS 
| 
 324                      DLGC_WANTTAB 
| DLGC_WANTMESSAGE
; 
 327     MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
, 
 329               WidthDefault(size
.x
), HeightDefault(size
.y
), 
 330               msflags
, NULL
, exStyle
); 
 336 void wxGLCanvas::SetupPixelFormat() // (HDC hDC) 
 338     PIXELFORMATDESCRIPTOR pfd 
= { 
 339         sizeof(PIXELFORMATDESCRIPTOR
),  /* size */ 
 343         PFD_DOUBLEBUFFER
,               /* support double-buffering */ 
 344         PFD_TYPE_RGBA
,                  /* color type */ 
 345         16,                             /* prefered color depth */ 
 346         0, 0, 0, 0, 0, 0,               /* color bits (ignored) */ 
 347         0,                              /* no alpha buffer */ 
 348         0,                              /* alpha bits (ignored) */ 
 349         0,                              /* no accumulation buffer */ 
 350         0, 0, 0, 0,                     /* accum bits (ignored) */ 
 351         16,                             /* depth buffer */ 
 352         0,                              /* no stencil buffer */ 
 353         0,                              /* no auxiliary buffers */ 
 354         PFD_MAIN_PLANE
,                 /* main layer */ 
 356         0, 0, 0,                        /* no layer, visible, damage masks */ 
 360     pixelFormat 
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
); 
 361     if (pixelFormat 
== 0) { 
 362         MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("ChoosePixelFormat failed."), wxT("Error"), 
 363                 MB_ICONERROR 
| MB_OK
); 
 367     if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) { 
 368         MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("SetPixelFormat failed."), wxT("Error"), 
 369                 MB_ICONERROR 
| MB_OK
); 
 374 void wxGLCanvas::SetupPalette(const wxPalette
& palette
) 
 376     int pixelFormat 
= GetPixelFormat((HDC
) m_hDC
); 
 377     PIXELFORMATDESCRIPTOR pfd
; 
 379     DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
); 
 381     if (pfd
.dwFlags 
& PFD_NEED_PALETTE
) 
 391     if ( !m_palette
.Ok() ) 
 393         m_palette 
= CreateDefaultPalette(); 
 398         SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
); 
 399         RealizePalette((HDC
) m_hDC
); 
 403 wxPalette 
wxGLCanvas::CreateDefaultPalette() 
 405     PIXELFORMATDESCRIPTOR pfd
; 
 407     int pixelFormat 
= GetPixelFormat((HDC
) m_hDC
); 
 409     DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
); 
 411         paletteSize 
= 1 << pfd
.cColorBits
; 
 414      (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize 
* sizeof(PALETTEENTRY
)); 
 415     pPal
->palVersion 
= 0x300; 
 416     pPal
->palNumEntries 
= paletteSize
; 
 418     /* build a simple RGB color palette */ 
 420         int redMask 
= (1 << pfd
.cRedBits
) - 1; 
 421         int greenMask 
= (1 << pfd
.cGreenBits
) - 1; 
 422         int blueMask 
= (1 << pfd
.cBlueBits
) - 1; 
 425         for (i
=0; i
<paletteSize
; ++i
) { 
 426             pPal
->palPalEntry
[i
].peRed 
= 
 427                     (((i 
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
; 
 428             pPal
->palPalEntry
[i
].peGreen 
= 
 429                     (((i 
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
; 
 430             pPal
->palPalEntry
[i
].peBlue 
= 
 431                     (((i 
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
; 
 432             pPal
->palPalEntry
[i
].peFlags 
= 0; 
 436     HPALETTE hPalette 
= CreatePalette(pPal
); 
 440     palette
.SetHPALETTE((WXHPALETTE
) hPalette
); 
 445 void wxGLCanvas::SwapBuffers() 
 448     m_glContext
->SwapBuffers(); 
 451 void wxGLCanvas::OnSize(wxSizeEvent
& event
) 
 454   GetClientSize(& width
, & height
); 
 458     m_glContext
->SetCurrent(); 
 460     glViewport(0, 0, (GLint
)width
, (GLint
)height
); 
 461     glMatrixMode(GL_PROJECTION
); 
 463     glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 ); 
 464     glMatrixMode(GL_MODELVIEW
); 
 468 void wxGLCanvas::SetCurrent() 
 472     m_glContext
->SetCurrent(); 
 476 void wxGLCanvas::SetColour(const char *colour
) 
 479     m_glContext
->SetColour(colour
); 
 482 // TODO: Have to have this called by parent frame (?) 
 483 // So we need wxFrame to call OnQueryNewPalette for all children... 
 484 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
) 
 486         /* realize palette if this is the current window */ 
 487         if ( GetPalette()->Ok() ) { 
 488             ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE()); 
 489             ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
); 
 490             ::RealizePalette((HDC
) GetHDC()); 
 492             event
.SetPaletteRealized(TRUE
); 
 495             event
.SetPaletteRealized(FALSE
); 
 498 // I think this doesn't have to be propagated to child windows. 
 499 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
) 
 501         /* realize palette if this is *not* the current window */ 
 503        GetPalette()->Ok() && (this != event
.GetChangedWindow()) ) 
 505             ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE()); 
 506             ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
); 
 507             ::RealizePalette((HDC
) GetHDC()); 
 512 /* Give extensions proper function names. */ 
 514 /* EXT_vertex_array */ 
 515 void glArrayElementEXT(GLint i
) 
 519 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid 
*pointer
) 
 523 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
) 
 525 #ifdef GL_EXT_vertex_array 
 526     static PFNGLDRAWARRAYSEXTPROC proc 
= 0; 
 530         proc 
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT"); 
 534         (* proc
) (mode
, first
, count
); 
 538 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean 
*pointer
) 
 542 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
) 
 546 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid 
*pointer
) 
 550 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid 
*pointer
) 
 552 #ifdef GL_EXT_vertex_array 
 553     static PFNGLNORMALPOINTEREXTPROC proc 
= 0; 
 557         proc 
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT"); 
 561         (* proc
) (type
, stride
, count
, pointer
); 
 565 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid 
*pointer
) 
 569 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid 
*pointer
) 
 571 #ifdef GL_EXT_vertex_array 
 572     static PFNGLVERTEXPOINTEREXTPROC proc 
= 0; 
 576         proc 
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT"); 
 580         (* proc
) (size
, type
, stride
, count
, pointer
); 
 584 /* EXT_color_subtable */ 
 585 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid 
*table
) 
 589 /* EXT_color_table */ 
 590 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid 
*table
) 
 594 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
) 
 598 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid 
*table
) 
 602 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat 
*params
) 
 606 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint 
*params
) 
 610 /* SGI_compiled_vertex_array */ 
 611 void glLockArraysSGI(GLint first
, GLsizei count
) 
 615 void glUnlockArraysSGI() 
 620 /* SGI_cull_vertex */ 
 621 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
) 
 625 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
) 
 630 void glIndexFuncSGI(GLenum func
, GLclampf ref
) 
 634 /* SGI_index_material */ 
 635 void glIndexMaterialSGI(GLenum face
, GLenum mode
) 
 640 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)