13c4f1f27ca98d1526310e08cd7a15d50c6f8a9c
[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(HAVE_XLIB)
17
18 #ifndef GL_GLEXT_LEGACY
19 #define GL_GLEXT_LEGACY // To prevent inclusion of system glext.h on Mac OS X 10.6.8
20 #endif
21
22 // macOS 10.4 deprecated OpenGL framework - suppress useless warnings
23 #define GL_SILENCE_DEPRECATION
24
25 #import <TargetConditionals.h>
26
27 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
28   #import <UIKit/UIKit.h>
29 #else
30   #import <Cocoa/Cocoa.h>
31
32 #if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
33 @interface NSView (LionAPI)
34 - (NSSize )convertSizeToBacking: (NSSize )theSize;
35 @end
36 #endif
37
38 #endif
39
40 #include <OpenGl_Window.hxx>
41 #include <OpenGl_FrameBuffer.hxx>
42
43 #include <OpenGl_Context.hxx>
44 #include <Aspect_GraphicDeviceDefinitionError.hxx>
45 #include <Cocoa_LocalPool.hxx>
46 #include <TCollection_AsciiString.hxx>
47 #include <TCollection_ExtendedString.hxx>
48
49 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
50   //
51 #else
52   #include <OpenGL/CGLRenderers.h>
53 #endif
54
55 // =======================================================================
56 // function : OpenGl_Window
57 // purpose  :
58 // =======================================================================
59 OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
60                               const Handle(Aspect_Window)&  thePlatformWindow,
61                               Aspect_RenderingContext       theGContext,
62                               const Handle(OpenGl_Caps)&    theCaps,
63                               const Handle(OpenGl_Context)& theShareCtx)
64 : myGlContext (new OpenGl_Context (theCaps)),
65   myOwnGContext (theGContext == 0),
66   myPlatformWindow (thePlatformWindow),
67 #if defined(__APPLE__) && defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
68   myUIView (NULL),
69 #endif
70   mySwapInterval (theCaps->swapInterval)
71 {
72   (void )theDriver;
73   myPlatformWindow->Size (myWidth, myHeight);
74
75 #if defined(__APPLE__)
76   myWidthPt  = myWidth;
77   myHeightPt = myHeight;
78 #endif
79
80 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
81   EAGLContext* aGLContext = theGContext;
82   if (aGLContext == NULL)
83   {
84     void* aViewPtr = (void* )myPlatformWindow->NativeHandle();
85
86     myUIView = (__bridge UIView* )aViewPtr;
87     CAEAGLLayer* anEaglLayer = (CAEAGLLayer* )myUIView.layer;
88     anEaglLayer.opaque = TRUE;
89     anEaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
90                                         [NSNumber numberWithBool: FALSE], kEAGLDrawablePropertyRetainedBacking,
91                                         kEAGLColorFormatRGBA8,            kEAGLDrawablePropertyColorFormat,
92                                         NULL];
93
94     aGLContext = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES3];
95     if (aGLContext == NULL
96     || ![EAGLContext setCurrentContext: aGLContext])
97     {
98       aGLContext = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES2];
99
100       if (aGLContext == NULL
101       || ![EAGLContext setCurrentContext: aGLContext])
102       {
103         TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: EAGLContext creation failed");
104         throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
105         return;
106       }
107     }
108
109     myGlContext->Init (aGLContext, Standard_False);
110   }
111   else
112   {
113     if (![EAGLContext setCurrentContext: aGLContext])
114     {
115       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: EAGLContext can not be assigned");
116       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
117       return;
118     }
119
120     myGlContext->Init (aGLContext, Standard_False);
121   }
122 #else
123
124   Cocoa_LocalPool aLocalPool;
125
126   // all GL context within one OpenGl_GraphicDriver should be shared!
127   NSOpenGLContext* aGLCtxShare = theShareCtx.IsNull() ? NULL : theShareCtx->myGContext;
128   NSOpenGLContext* aGLContext  = theGContext;
129   bool isCore = false;
130   if (aGLContext == NULL)
131   {
132     NSOpenGLPixelFormatAttribute anAttribs[32] = {};
133     Standard_Integer aLastAttrib = 0;
134     //anAttribs[aLastAttrib++] = NSOpenGLPFAColorSize;    anAttribs[aLastAttrib++] = 32,
135     anAttribs[aLastAttrib++] = NSOpenGLPFADepthSize;    anAttribs[aLastAttrib++] = 24;
136     anAttribs[aLastAttrib++] = NSOpenGLPFAStencilSize;  anAttribs[aLastAttrib++] = 8;
137     anAttribs[aLastAttrib++] = NSOpenGLPFADoubleBuffer;
138     if (theCaps->contextNoAccel)
139     {
140       anAttribs[aLastAttrib++] = NSOpenGLPFARendererID;
141       anAttribs[aLastAttrib++] = (NSOpenGLPixelFormatAttribute )kCGLRendererGenericFloatID;
142     }
143     else
144     {
145       anAttribs[aLastAttrib++] = NSOpenGLPFAAccelerated;
146     }
147     anAttribs[aLastAttrib] = 0;
148     const Standard_Integer aLastMainAttrib = aLastAttrib;
149     Standard_Integer aTryCore   = 0;
150     Standard_Integer aTryStereo = 0;
151     for (aTryCore = 1; aTryCore >= 0; --aTryCore)
152     {
153       aLastAttrib = aLastMainAttrib;
154       if (aTryCore == 1)
155       {
156         if (theCaps->contextCompatible)
157         {
158           continue;
159         }
160
161         // supported since OS X 10.7+
162         anAttribs[aLastAttrib++] = 99;     // NSOpenGLPFAOpenGLProfile
163         anAttribs[aLastAttrib++] = 0x3200; // NSOpenGLProfileVersion3_2Core
164       }
165
166       for (aTryStereo = 1; aTryStereo >= 0; --aTryStereo)
167       {
168         if (aTryStereo == 1)
169         {
170           if (!theCaps->contextStereo)
171           {
172             continue;
173           }
174
175           // deprecated since macOS 10.12 without replacement
176           Standard_DISABLE_DEPRECATION_WARNINGS
177           anAttribs[aLastAttrib++] = NSOpenGLPFAStereo;
178           Standard_ENABLE_DEPRECATION_WARNINGS
179         }
180
181         anAttribs[aLastAttrib] = 0;
182
183         NSOpenGLPixelFormat* aGLFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes: anAttribs] autorelease];
184         aGLContext = [[NSOpenGLContext alloc] initWithFormat: aGLFormat
185                                                 shareContext: aGLCtxShare];
186         if (aGLContext != NULL)
187         {
188           break;
189         }
190       }
191
192       if (aGLContext != NULL)
193       {
194         break;
195       }
196     }
197
198     if (aGLContext == NULL)
199     {
200       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: NSOpenGLContext creation failed");
201       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
202       return;
203     }
204
205     if (aTryStereo == 0
206      && theCaps->contextStereo)
207     {
208       TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: QuadBuffer is unavailable!");
209       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
210     }
211     if (aTryCore == 0
212     && !theCaps->contextCompatible)
213     {
214       TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: core profile creation failed.");
215       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
216     }
217
218     NSView* aView = (NSView* )myPlatformWindow->NativeHandle();
219     [aGLContext setView: aView];
220     isCore = (aTryCore == 1);
221   }
222
223   myGlContext->Init (aGLContext, isCore);
224 #endif
225
226   myGlContext->Share (theShareCtx);
227   myGlContext->SetSwapInterval (mySwapInterval);
228   Init();
229 }
230
231 // =======================================================================
232 // function : ~OpenGl_Window
233 // purpose  :
234 // =======================================================================
235 OpenGl_Window::~OpenGl_Window()
236 {
237   if (!myOwnGContext
238    ||  myGlContext.IsNull())
239   {
240     myGlContext.Nullify();
241     return;
242   }
243
244 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
245   myGlContext.Nullify();
246   [EAGLContext setCurrentContext: NULL];
247   myUIView = NULL;
248 #else
249   NSOpenGLContext* aGLCtx = myGlContext->myGContext;
250   myGlContext.Nullify();
251
252   [NSOpenGLContext clearCurrentContext];
253   [aGLCtx clearDrawable];
254   [aGLCtx release];
255 #endif
256 }
257
258 // =======================================================================
259 // function : Resize
260 // purpose  : call_subr_resize
261 // =======================================================================
262 void OpenGl_Window::Resize()
263 {
264   // If the size is not changed - do nothing
265   Standard_Integer aWidthPt  = 0;
266   Standard_Integer aHeightPt = 0;
267   myPlatformWindow->Size (aWidthPt, aHeightPt);
268   if (myWidthPt  == aWidthPt
269    && myHeightPt == aHeightPt)
270   {
271   #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
272     return;
273   #else
274     // check backing store change (moving to another screen)
275     NSOpenGLContext* aGLCtx = myGlContext->myGContext;
276     NSView* aView = [aGLCtx view];
277     if (![aView respondsToSelector: @selector(convertSizeToBacking:)])
278     {
279       return;
280     }
281
282     NSRect aBounds = [aView bounds];
283     NSSize aRes    = [aView convertSizeToBacking: aBounds.size];
284     if (myWidth  == Standard_Integer(aRes.width)
285      && myHeight == Standard_Integer(aRes.height))
286     {
287       return;
288     }
289   #endif
290   }
291
292   myWidthPt  = aWidthPt;
293   myHeightPt = aHeightPt;
294
295   Init();
296 }
297
298 // =======================================================================
299 // function : Init
300 // purpose  :
301 // =======================================================================
302 void OpenGl_Window::Init()
303 {
304   if (!Activate())
305   {
306     return;
307   }
308
309 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
310   Handle(OpenGl_FrameBuffer) aDefFbo = myGlContext->SetDefaultFrameBuffer (NULL);
311   if (!aDefFbo.IsNull())
312   {
313     aDefFbo->Release (myGlContext.operator->());
314   }
315   else
316   {
317     aDefFbo = new OpenGl_FrameBuffer();
318   }
319
320   if (myOwnGContext)
321   {
322     EAGLContext* aGLCtx      = myGlContext->myGContext;
323     CAEAGLLayer* anEaglLayer = (CAEAGLLayer* )myUIView.layer;
324     GLuint aWinRBColor = 0;
325     ::glGenRenderbuffers (1, &aWinRBColor);
326     ::glBindRenderbuffer (GL_RENDERBUFFER, aWinRBColor);
327     [aGLCtx renderbufferStorage: GL_RENDERBUFFER fromDrawable: anEaglLayer];
328     ::glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &myWidth);
329     ::glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myHeight);
330     ::glBindRenderbuffer (GL_RENDERBUFFER, 0);
331
332     if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, aWinRBColor))
333     {
334       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
335       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
336       return;
337     }
338   }
339   else
340   {
341     if (!aDefFbo->InitWrapper (myGlContext))
342     {
343       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO wrapper creation failed");
344       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
345       return;
346     }
347
348     myWidth  = aDefFbo->GetVPSizeX();
349     myHeight = aDefFbo->GetVPSizeY();
350   }
351   myGlContext->SetDefaultFrameBuffer (aDefFbo);
352   aDefFbo->BindBuffer (myGlContext);
353   aDefFbo.Nullify();
354 #else
355   NSOpenGLContext* aGLCtx  = myGlContext->myGContext;
356   NSView*          aView   = [aGLCtx view];
357   NSRect           aBounds = [aView bounds];
358
359   // we should call this method each time when window is resized
360   [aGLCtx update];
361
362   if ([aView respondsToSelector: @selector(convertSizeToBacking:)])
363   {
364     NSSize aRes = [aView convertSizeToBacking: aBounds.size];
365     myWidth  = Standard_Integer(aRes.width);
366     myHeight = Standard_Integer(aRes.height);
367   }
368   else
369   {
370     myWidth  = Standard_Integer(aBounds.size.width);
371     myHeight = Standard_Integer(aBounds.size.height);
372   }
373   myWidthPt  = Standard_Integer(aBounds.size.width);
374   myHeightPt = Standard_Integer(aBounds.size.height);
375 #endif
376
377   ::glDisable (GL_DITHER);
378   ::glDisable (GL_SCISSOR_TEST);
379   ::glViewport (0, 0, myWidth, myHeight);
380 #if !defined(GL_ES_VERSION_2_0)
381   ::glDrawBuffer (GL_BACK);
382   if (myGlContext->core11ffp != NULL)
383   {
384     ::glMatrixMode (GL_MODELVIEW);
385   }
386 #endif
387 }
388
389 // =======================================================================
390 // function : SetSwapInterval
391 // purpose  :
392 // =======================================================================
393 void OpenGl_Window::SetSwapInterval (Standard_Boolean theToForceNoSync)
394 {
395   const Standard_Integer aSwapInterval = theToForceNoSync ? 0 : myGlContext->caps->swapInterval;
396   if (mySwapInterval != aSwapInterval)
397   {
398     mySwapInterval = aSwapInterval;
399     myGlContext->SetSwapInterval (mySwapInterval);
400   }
401 }
402
403 #endif // __APPLE__