0025973: Visualization, TKOpenGl - support EAGLContext as alternative to NSOpenGLContext
[occt.git] / src / OpenGl / OpenGl_Window_1.mm
1 // Created on: 2012-11-12
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2012-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
17
18 #define GL_GLEXT_LEGACY // To prevent inclusion of system glext.h on Mac OS X 10.6.8
19
20 #import <TargetConditionals.h>
21
22 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
23   #import <UIKit/UIKit.h>
24 #else
25   #import <Cocoa/Cocoa.h>
26
27 #if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
28 @interface NSView (LionAPI)
29 - (NSSize )convertSizeToBacking: (NSSize )theSize;
30 @end
31 #endif
32
33 #endif
34
35 #include <InterfaceGraphic.hxx>
36
37 #include <OpenGl_Window.hxx>
38 #include <OpenGl_FrameBuffer.hxx>
39
40 #include <OpenGl_Context.hxx>
41 #include <Aspect_GraphicDeviceDefinitionError.hxx>
42 #include <Cocoa_LocalPool.hxx>
43 #include <TCollection_AsciiString.hxx>
44 #include <TCollection_ExtendedString.hxx>
45
46 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
47   //
48 #else
49   #include <OpenGL/CGLRenderers.h>
50 #endif
51
52 namespace
53 {
54   static const TEL_COLOUR THE_DEFAULT_BG_COLOR = { { 0.F, 0.F, 0.F, 1.F } };
55 }
56
57 // =======================================================================
58 // function : OpenGl_Window
59 // purpose  :
60 // =======================================================================
61 OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
62                               const CALL_DEF_WINDOW&        theCWindow,
63                               Aspect_RenderingContext       theGContext,
64                               const Handle(OpenGl_Caps)&    theCaps,
65                               const Handle(OpenGl_Context)& theShareCtx)
66 : myGlContext (new OpenGl_Context (theCaps)),
67   myOwnGContext (theGContext == 0),
68 #if defined(__APPLE__)
69 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
70   myUIView (NULL),
71 #endif
72   myWidthPt  (theCWindow.dx),
73   myHeightPt (theCWindow.dy),
74 #endif
75   myWidth    (theCWindow.dx),
76   myHeight   (theCWindow.dy),
77   myBgColor (THE_DEFAULT_BG_COLOR)
78 {
79   myBgColor.rgb[0] = theCWindow.Background.r;
80   myBgColor.rgb[1] = theCWindow.Background.g;
81   myBgColor.rgb[2] = theCWindow.Background.b;
82
83 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
84   EAGLContext* aGLContext = theGContext;
85   if (aGLContext == NULL)
86   {
87     void* aViewPtr = (void* )theCWindow.XWindow;
88
89     myUIView = (__bridge UIView* )aViewPtr;
90     CAEAGLLayer* anEaglLayer = (CAEAGLLayer* )myUIView.layer;
91     anEaglLayer.opaque = TRUE;
92     anEaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
93                                         [NSNumber numberWithBool: FALSE], kEAGLDrawablePropertyRetainedBacking,
94                                         kEAGLColorFormatRGBA8,            kEAGLDrawablePropertyColorFormat,
95                                         NULL];
96
97     aGLContext = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES2];
98     if (aGLContext == NULL
99     || ![EAGLContext setCurrentContext: aGLContext])
100     {
101       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: EAGLContext creation failed");
102       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
103       return;
104     }
105
106     myGlContext->Init (aGLContext, Standard_False);
107   }
108   else
109   {
110     if (![EAGLContext setCurrentContext: aGLContext])
111     {
112       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: EAGLContext can not be assigned");
113       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
114       return;
115     }
116
117     myGlContext->Init (aGLContext, Standard_False);
118   }
119 #else
120
121   Cocoa_LocalPool aLocalPool;
122
123   // all GL context within one OpenGl_GraphicDriver should be shared!
124   NSOpenGLContext* aGLCtxShare = theShareCtx.IsNull() ? NULL : theShareCtx->myGContext;
125   NSOpenGLContext* aGLContext  = theGContext;
126   bool isCore = false;
127   if (aGLContext == NULL)
128   {
129     NSOpenGLPixelFormatAttribute anAttribs[32] = {};
130     Standard_Integer aLastAttrib = 0;
131     //anAttribs[aLastAttrib++] = NSOpenGLPFAColorSize;    anAttribs[aLastAttrib++] = 32,
132     anAttribs[aLastAttrib++] = NSOpenGLPFADepthSize;    anAttribs[aLastAttrib++] = 24;
133     anAttribs[aLastAttrib++] = NSOpenGLPFAStencilSize;  anAttribs[aLastAttrib++] = 8;
134     anAttribs[aLastAttrib++] = NSOpenGLPFADoubleBuffer;
135     if (theCaps->contextNoAccel)
136     {
137       anAttribs[aLastAttrib++] = NSOpenGLPFARendererID;
138       anAttribs[aLastAttrib++] = (NSOpenGLPixelFormatAttribute )kCGLRendererGenericFloatID;
139     }
140     else
141     {
142       anAttribs[aLastAttrib++] = NSOpenGLPFAAccelerated;
143     }
144     anAttribs[aLastAttrib] = 0;
145     const Standard_Integer aLastMainAttrib = aLastAttrib;
146     Standard_Integer aTryCore   = 0;
147     Standard_Integer aTryStereo = 0;
148     for (aTryCore = 1; aTryCore >= 0; --aTryCore)
149     {
150       aLastAttrib = aLastMainAttrib;
151       if (aTryCore == 1)
152       {
153         if (theCaps->contextCompatible)
154         {
155           continue;
156         }
157
158         // supported since OS X 10.7+
159         anAttribs[aLastAttrib++] = 99;     // NSOpenGLPFAOpenGLProfile
160         anAttribs[aLastAttrib++] = 0x3200; // NSOpenGLProfileVersion3_2Core
161       }
162
163       for (aTryStereo = 1; aTryStereo >= 0; --aTryStereo)
164       {
165         if (aTryStereo == 1)
166         {
167           if (!theCaps->contextStereo)
168           {
169             continue;
170           }
171           anAttribs[aLastAttrib++] = NSOpenGLPFAStereo;
172         }
173
174         anAttribs[aLastAttrib] = 0;
175
176         NSOpenGLPixelFormat* aGLFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes: anAttribs] autorelease];
177         aGLContext = [[NSOpenGLContext alloc] initWithFormat: aGLFormat
178                                                 shareContext: aGLCtxShare];
179         if (aGLContext != NULL)
180         {
181           break;
182         }
183       }
184
185       if (aGLContext != NULL)
186       {
187         break;
188       }
189     }
190
191     if (aGLContext == NULL)
192     {
193       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: NSOpenGLContext creation failed");
194       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
195       return;
196     }
197
198     if (aTryStereo == 0
199      && theCaps->contextStereo)
200     {
201       TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: QuadBuffer is unavailable!");
202       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMsg);
203     }
204     if (aTryCore == 0
205     && !theCaps->contextCompatible)
206     {
207       TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: core profile creation failed.");
208       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMsg);
209     }
210
211     NSView* aView = (NSView* )theCWindow.XWindow;
212     [aGLContext setView: aView];
213     isCore = (aTryCore == 1);
214   }
215
216   myGlContext->Init (aGLContext, isCore);
217 #endif
218
219   myGlContext->Share (theShareCtx);
220   Init();
221 }
222
223 // =======================================================================
224 // function : ~OpenGl_Window
225 // purpose  :
226 // =======================================================================
227 OpenGl_Window::~OpenGl_Window()
228 {
229   if (!myOwnGContext
230    ||  myGlContext.IsNull())
231   {
232     myGlContext.Nullify();
233     return;
234   }
235
236 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
237   myGlContext.Nullify();
238   [EAGLContext setCurrentContext: NULL];
239   myUIView = NULL;
240 #else
241   NSOpenGLContext* aGLCtx = myGlContext->myGContext;
242   myGlContext.Nullify();
243
244   [NSOpenGLContext clearCurrentContext];
245   [aGLCtx clearDrawable];
246   [aGLCtx release];
247 #endif
248 }
249
250 // =======================================================================
251 // function : Resize
252 // purpose  : call_subr_resize
253 // =======================================================================
254 void OpenGl_Window::Resize (const CALL_DEF_WINDOW& theCWindow)
255 {
256   // If the size is not changed - do nothing
257   if (myWidthPt  == theCWindow.dx
258    && myHeightPt == theCWindow.dy)
259   {
260     return;
261   }
262
263   myWidthPt  = theCWindow.dx;
264   myHeightPt = theCWindow.dy;
265
266   Init();
267 }
268
269 // =======================================================================
270 // function : Init
271 // purpose  :
272 // =======================================================================
273 void OpenGl_Window::Init()
274 {
275   if (!Activate())
276   {
277     return;
278   }
279
280 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
281   Handle(OpenGl_FrameBuffer) aDefFbo = myGlContext->SetDefaultFrameBuffer (NULL);
282   if (!aDefFbo.IsNull())
283   {
284     aDefFbo->Release (myGlContext.operator->());
285   }
286   else
287   {
288     aDefFbo = new OpenGl_FrameBuffer();
289   }
290
291   if (myOwnGContext)
292   {
293     EAGLContext* aGLCtx      = myGlContext->myGContext;
294     CAEAGLLayer* anEaglLayer = (CAEAGLLayer* )myUIView.layer;
295     GLuint aWinRBColor = 0;
296     ::glGenRenderbuffers (1, &aWinRBColor);
297     ::glBindRenderbuffer (GL_RENDERBUFFER, aWinRBColor);
298     [aGLCtx renderbufferStorage: GL_RENDERBUFFER fromDrawable: anEaglLayer];
299     ::glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &myWidth);
300     ::glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myHeight);
301     ::glBindRenderbuffer (GL_RENDERBUFFER, 0);
302
303     if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, aWinRBColor))
304     {
305       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
306       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
307       return;
308     }
309   }
310   else
311   {
312     if (!aDefFbo->InitWrapper (myGlContext))
313     {
314       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO wrapper creation failed");
315       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
316       return;
317     }
318
319     myWidth  = aDefFbo->GetVPSizeX();
320     myHeight = aDefFbo->GetVPSizeY();
321   }
322   myGlContext->SetDefaultFrameBuffer (aDefFbo);
323   aDefFbo->BindBuffer (myGlContext);
324   aDefFbo.Nullify();
325 #else
326   NSOpenGLContext* aGLCtx  = myGlContext->myGContext;
327   NSView*          aView   = [aGLCtx view];
328   NSRect           aBounds = [aView bounds];
329
330   // we should call this method each time when window is resized
331   [aGLCtx update];
332
333   if ([aView respondsToSelector: @selector(convertSizeToBacking:)])
334   {
335     NSSize aRes = [aView convertSizeToBacking: aBounds.size];
336     myWidth  = Standard_Integer(aRes.width);
337     myHeight = Standard_Integer(aRes.height);
338   }
339   else
340   {
341     myWidth  = Standard_Integer(aBounds.size.width);
342     myHeight = Standard_Integer(aBounds.size.height);
343   }
344   myWidthPt  = Standard_Integer(aBounds.size.width);
345   myHeightPt = Standard_Integer(aBounds.size.height);
346 #endif
347
348   ::glDisable (GL_DITHER);
349   ::glDisable (GL_SCISSOR_TEST);
350   ::glViewport (0, 0, myWidth, myHeight);
351 #if !defined(GL_ES_VERSION_2_0)
352   ::glDrawBuffer (GL_BACK);
353   if (myGlContext->core11 != NULL)
354   {
355     ::glMatrixMode (GL_MODELVIEW);
356   }
357 #endif
358 }
359
360 #endif // __APPLE__