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