| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: glcanvas.cpp |
| 3 | // Purpose: wxGLCanvas, for using OpenGL with wxWindows under Macintosh |
| 4 | // Author: AUTHOR |
| 5 | // Modified by: |
| 6 | // Created: ??/??/98 |
| 7 | // RCS-ID: $Id$ |
| 8 | // Copyright: (c) AUTHOR |
| 9 | // Licence: wxWindows licence |
| 10 | ///////////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | #ifdef __GNUG__ |
| 13 | #pragma implementation "glcanvas.h" |
| 14 | #endif |
| 15 | |
| 16 | #include "wx/wxprec.h" |
| 17 | |
| 18 | #if defined(__BORLANDC__) |
| 19 | #pragma hdrstop |
| 20 | #endif |
| 21 | |
| 22 | #include "wx/setup.h" |
| 23 | |
| 24 | #if wxUSE_GLCANVAS |
| 25 | |
| 26 | #ifndef WX_PRECOMP |
| 27 | #include "wx/frame.h" |
| 28 | #endif |
| 29 | |
| 30 | #include "wx/settings.h" |
| 31 | #include "wx/log.h" |
| 32 | |
| 33 | #include "wx/glcanvas.h" |
| 34 | #include "wx/mac/uma.h" |
| 35 | |
| 36 | /* |
| 37 | * GLContext implementation |
| 38 | */ |
| 39 | |
| 40 | wxGLContext::wxGLContext( |
| 41 | AGLPixelFormat fmt, wxGLCanvas *win, |
| 42 | const wxPalette& palette, |
| 43 | const wxGLContext *other /* for sharing display lists */ |
| 44 | ) |
| 45 | { |
| 46 | m_window = win; |
| 47 | |
| 48 | m_drawable = (AGLDrawable) UMAGetWindowPort(win->GetMacRootWindow()); |
| 49 | |
| 50 | m_glContext = aglCreateContext(fmt, other ? other->m_glContext : NULL); |
| 51 | wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGl context") ); |
| 52 | |
| 53 | GLboolean b; |
| 54 | b = aglSetDrawable(m_glContext, m_drawable); |
| 55 | wxCHECK_RET( b, wxT("Couldn't bind OpenGl context") ); |
| 56 | aglEnable(m_glContext , AGL_BUFFER_RECT ) ; |
| 57 | b = aglSetCurrentContext(m_glContext); |
| 58 | wxCHECK_RET( b, wxT("Couldn't activate OpenGl context") ); |
| 59 | } |
| 60 | |
| 61 | wxGLContext::~wxGLContext() |
| 62 | { |
| 63 | if (m_glContext) |
| 64 | { |
| 65 | aglSetCurrentContext(NULL); |
| 66 | aglDestroyContext(m_glContext); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | void wxGLContext::SwapBuffers() |
| 71 | { |
| 72 | if (m_glContext) |
| 73 | { |
| 74 | aglSwapBuffers(m_glContext); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | void wxGLContext::SetCurrent() |
| 79 | { |
| 80 | if (m_glContext) |
| 81 | { |
| 82 | aglSetCurrentContext(m_glContext); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | void wxGLContext::Update() |
| 87 | { |
| 88 | if (m_glContext) |
| 89 | { |
| 90 | aglUpdateContext(m_glContext); |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | void wxGLContext::SetColour(const char *colour) |
| 95 | { |
| 96 | float r = 0.0; |
| 97 | float g = 0.0; |
| 98 | float b = 0.0; |
| 99 | wxColour *col = wxTheColourDatabase->FindColour(colour); |
| 100 | if (col) |
| 101 | { |
| 102 | r = (float)(col->Red()/256.0); |
| 103 | g = (float)(col->Green()/256.0); |
| 104 | b = (float)(col->Blue()/256.0); |
| 105 | glColor3f( r, g, b); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | |
| 110 | /* |
| 111 | * wxGLCanvas implementation |
| 112 | */ |
| 113 | |
| 114 | IMPLEMENT_CLASS(wxGLCanvas, wxWindow) |
| 115 | |
| 116 | BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow) |
| 117 | EVT_SIZE(wxGLCanvas::OnSize) |
| 118 | END_EVENT_TABLE() |
| 119 | |
| 120 | wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, |
| 121 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, |
| 122 | int *attribList, const wxPalette& palette) |
| 123 | { |
| 124 | Create(parent, NULL, id, pos, size, style, name, attribList, palette); |
| 125 | } |
| 126 | |
| 127 | wxGLCanvas::wxGLCanvas( wxWindow *parent, |
| 128 | const wxGLContext *shared, wxWindowID id, |
| 129 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, |
| 130 | int *attribList, const wxPalette& palette ) |
| 131 | { |
| 132 | Create(parent, shared, id, pos, size, style, name, attribList, palette); |
| 133 | } |
| 134 | |
| 135 | wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id, |
| 136 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, |
| 137 | int *attribList, const wxPalette& palette ) |
| 138 | { |
| 139 | Create(parent, shared ? shared->GetContext() : NULL, id, pos, size, style, name, attribList, palette); |
| 140 | } |
| 141 | |
| 142 | wxGLCanvas::~wxGLCanvas() |
| 143 | { |
| 144 | if (m_glContext) |
| 145 | delete m_glContext; |
| 146 | } |
| 147 | |
| 148 | static AGLPixelFormat ChoosePixelFormat(const int *attribList) |
| 149 | { |
| 150 | GLint data[512]; |
| 151 | GLint defaultAttribs[] = { AGL_RGBA, |
| 152 | AGL_DOUBLEBUFFER, |
| 153 | AGL_MINIMUM_POLICY, |
| 154 | AGL_DEPTH_SIZE, 1, // use largest available depth buffer |
| 155 | AGL_RED_SIZE, 1, |
| 156 | AGL_GREEN_SIZE, 1, |
| 157 | AGL_BLUE_SIZE, 1, |
| 158 | AGL_ALPHA_SIZE, 0, |
| 159 | AGL_NONE }; |
| 160 | GLint *attribs; |
| 161 | if (!attribList) |
| 162 | { |
| 163 | attribs = defaultAttribs; |
| 164 | } |
| 165 | else |
| 166 | { |
| 167 | int arg=0, p=0; |
| 168 | |
| 169 | data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX |
| 170 | while( (attribList[arg]!=0) && (p<512) ) |
| 171 | { |
| 172 | switch( attribList[arg++] ) |
| 173 | { |
| 174 | case WX_GL_RGBA: data[p++] = AGL_RGBA; break; |
| 175 | case WX_GL_BUFFER_SIZE: |
| 176 | data[p++]=AGL_BUFFER_SIZE; data[p++]=attribList[arg++]; break; |
| 177 | case WX_GL_LEVEL: |
| 178 | data[p++]=AGL_LEVEL; data[p++]=attribList[arg++]; break; |
| 179 | case WX_GL_DOUBLEBUFFER: data[p++] = AGL_DOUBLEBUFFER; break; |
| 180 | case WX_GL_STEREO: data[p++] = AGL_STEREO; break; |
| 181 | case WX_GL_AUX_BUFFERS: |
| 182 | data[p++]=AGL_AUX_BUFFERS; data[p++]=attribList[arg++]; break; |
| 183 | case WX_GL_MIN_RED: |
| 184 | data[p++]=AGL_RED_SIZE; data[p++]=attribList[arg++]; break; |
| 185 | case WX_GL_MIN_GREEN: |
| 186 | data[p++]=AGL_GREEN_SIZE; data[p++]=attribList[arg++]; break; |
| 187 | case WX_GL_MIN_BLUE: |
| 188 | data[p++]=AGL_BLUE_SIZE; data[p++]=attribList[arg++]; break; |
| 189 | case WX_GL_MIN_ALPHA: |
| 190 | data[p++]=AGL_ALPHA_SIZE; data[p++]=attribList[arg++]; break; |
| 191 | case WX_GL_DEPTH_SIZE: |
| 192 | data[p++]=AGL_DEPTH_SIZE; data[p++]=attribList[arg++]; break; |
| 193 | case WX_GL_STENCIL_SIZE: |
| 194 | data[p++]=AGL_STENCIL_SIZE; data[p++]=attribList[arg++]; break; |
| 195 | case WX_GL_MIN_ACCUM_RED: |
| 196 | data[p++]=AGL_ACCUM_RED_SIZE; data[p++]=attribList[arg++]; break; |
| 197 | case WX_GL_MIN_ACCUM_GREEN: |
| 198 | data[p++]=AGL_ACCUM_GREEN_SIZE; data[p++]=attribList[arg++]; break; |
| 199 | case WX_GL_MIN_ACCUM_BLUE: |
| 200 | data[p++]=AGL_ACCUM_BLUE_SIZE; data[p++]=attribList[arg++]; break; |
| 201 | case WX_GL_MIN_ACCUM_ALPHA: |
| 202 | data[p++]=AGL_ACCUM_ALPHA_SIZE; data[p++]=attribList[arg++]; break; |
| 203 | default: |
| 204 | break; |
| 205 | } |
| 206 | } |
| 207 | data[p] = 0; |
| 208 | |
| 209 | attribs = data; |
| 210 | } |
| 211 | |
| 212 | return aglChoosePixelFormat(NULL, 0, attribs); |
| 213 | } |
| 214 | |
| 215 | bool wxGLCanvas::Create(wxWindow *parent, const wxGLContext *shared, wxWindowID id, |
| 216 | const wxPoint& pos, const wxSize& size, long style, const wxString& name, |
| 217 | int *attribList, const wxPalette& palette) |
| 218 | { |
| 219 | m_macEraseOnRedraw = false ; |
| 220 | wxWindow::Create( parent, id, pos, size, style, name ); |
| 221 | |
| 222 | AGLPixelFormat fmt = ChoosePixelFormat(attribList); |
| 223 | wxCHECK_MSG( fmt, false, wxT("Couldn't create OpenGl pixel format") ); |
| 224 | |
| 225 | m_glContext = new wxGLContext(fmt, this, palette, shared); |
| 226 | |
| 227 | aglDestroyPixelFormat(fmt); |
| 228 | |
| 229 | return true; |
| 230 | } |
| 231 | |
| 232 | void wxGLCanvas::SwapBuffers() |
| 233 | { |
| 234 | if (m_glContext) |
| 235 | m_glContext->SwapBuffers(); |
| 236 | } |
| 237 | |
| 238 | void wxGLCanvas::UpdateContext() |
| 239 | { |
| 240 | if (m_glContext) |
| 241 | m_glContext->Update(); |
| 242 | } |
| 243 | |
| 244 | void wxGLCanvas::SetViewport() |
| 245 | { |
| 246 | // viewport is initially set to entire port |
| 247 | // adjust glViewport to just this window |
| 248 | int x = 0 ; |
| 249 | int y = 0 ; |
| 250 | |
| 251 | MacClientToRootWindow( &x , &y ) ; |
| 252 | int width, height; |
| 253 | GetClientSize(& width, & height); |
| 254 | Rect bounds ; |
| 255 | GetWindowPortBounds( GetMacRootWindow() , &bounds ) ; |
| 256 | GLint parms[4] ; |
| 257 | parms[0] = x ; |
| 258 | parms[1] = bounds.bottom - bounds.top - ( y + height ) ; |
| 259 | parms[2] = width ; |
| 260 | parms[3] = height ; |
| 261 | |
| 262 | aglSetInteger( m_glContext->m_glContext , AGL_BUFFER_RECT , parms ) ; |
| 263 | } |
| 264 | |
| 265 | void wxGLCanvas::OnSize(wxSizeEvent& event) |
| 266 | { |
| 267 | if (m_glContext) |
| 268 | { |
| 269 | UpdateContext(); |
| 270 | m_glContext->SetCurrent(); |
| 271 | |
| 272 | SetViewport(); |
| 273 | glMatrixMode(GL_PROJECTION); |
| 274 | glLoadIdentity(); |
| 275 | glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 ); |
| 276 | glMatrixMode(GL_MODELVIEW); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | void wxGLCanvas::SetCurrent() |
| 281 | { |
| 282 | if (m_glContext) |
| 283 | { |
| 284 | m_glContext->SetCurrent(); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | void wxGLCanvas::SetColour(const char *colour) |
| 289 | { |
| 290 | if (m_glContext) |
| 291 | m_glContext->SetColour(colour); |
| 292 | } |
| 293 | |
| 294 | |
| 295 | //--------------------------------------------------------------------------- |
| 296 | // wxGLApp |
| 297 | //--------------------------------------------------------------------------- |
| 298 | |
| 299 | IMPLEMENT_CLASS(wxGLApp, wxApp) |
| 300 | |
| 301 | bool wxGLApp::InitGLVisual(int *attribList) |
| 302 | { |
| 303 | AGLPixelFormat fmt = ChoosePixelFormat(attribList); |
| 304 | if (fmt != NULL) { |
| 305 | aglDestroyPixelFormat(fmt); |
| 306 | return true; |
| 307 | } else |
| 308 | return false; |
| 309 | } |
| 310 | |
| 311 | wxGLApp::~wxGLApp(void) |
| 312 | { |
| 313 | } |
| 314 | |
| 315 | #endif // wxUSE_GLCANVAS |