Add remaining files
[juce-lv2.git] / juce / source / src / native / mac / juce_mac_OpenGLComponent.mm
blob98fe686693fa160efabc7ab359c4ed58c67fa6d7
1 /*\r
2   ==============================================================================\r
3 \r
4    This file is part of the JUCE library - "Jules' Utility Class Extensions"\r
5    Copyright 2004-11 by Raw Material Software Ltd.\r
6 \r
7   ------------------------------------------------------------------------------\r
8 \r
9    JUCE can be redistributed and/or modified under the terms of the GNU General\r
10    Public License (Version 2), as published by the Free Software Foundation.\r
11    A copy of the license is included in the JUCE distribution, or can be found\r
12    online at www.gnu.org/licenses.\r
14    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY\r
15    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
16    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
18   ------------------------------------------------------------------------------\r
20    To release a closed-source product which uses JUCE, commercial licenses are\r
21    available: visit www.rawmaterialsoftware.com/juce for more information.\r
23   ==============================================================================\r
24 */\r
26 // (This file gets included by juce_mac_NativeCode.mm, rather than being\r
27 // compiled on its own).\r
28 #if JUCE_INCLUDED_FILE && JUCE_OPENGL\r
30 #if JUCE_MAC\r
32 END_JUCE_NAMESPACE\r
34 #define ThreadSafeNSOpenGLView MakeObjCClassName(ThreadSafeNSOpenGLView)\r
36 //==============================================================================\r
37 @interface ThreadSafeNSOpenGLView  : NSOpenGLView\r
38 {\r
39     CriticalSection* contextLock;\r
40     bool needsUpdate;\r
41 }\r
43 - (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format;\r
44 - (bool) makeActive;\r
45 - (void) makeInactive;\r
46 - (void) reshape;\r
47 - (void) rightMouseDown: (NSEvent*) ev;\r
48 - (void) rightMouseUp: (NSEvent*) ev;\r
49 @end\r
51 @implementation ThreadSafeNSOpenGLView\r
53 - (id) initWithFrame: (NSRect) frameRect\r
54          pixelFormat: (NSOpenGLPixelFormat*) format\r
55 {\r
56     contextLock = new CriticalSection();\r
57     self = [super initWithFrame: frameRect pixelFormat: format];\r
59     if (self != nil)\r
60         [[NSNotificationCenter defaultCenter] addObserver: self\r
61                                                  selector: @selector (_surfaceNeedsUpdate:)\r
62                                                      name: NSViewGlobalFrameDidChangeNotification\r
63                                                    object: self];\r
64     return self;\r
65 }\r
67 - (void) dealloc\r
68 {\r
69     [[NSNotificationCenter defaultCenter] removeObserver: self];\r
70     delete contextLock;\r
71     [super dealloc];\r
72 }\r
74 - (bool) makeActive\r
75 {\r
76     const ScopedLock sl (*contextLock);\r
78     if ([self openGLContext] == 0)\r
79         return false;\r
81     [[self openGLContext] makeCurrentContext];\r
83     if (needsUpdate)\r
84     {\r
85         [super update];\r
86         needsUpdate = false;\r
87     }\r
89     return true;\r
90 }\r
92 - (void) makeInactive\r
93 {\r
94     const ScopedLock sl (*contextLock);\r
95     [NSOpenGLContext clearCurrentContext];\r
96 }\r
98 - (void) _surfaceNeedsUpdate: (NSNotification*) notification\r
99 {\r
100     (void) notification;\r
101     const ScopedLock sl (*contextLock);\r
102     needsUpdate = true;\r
105 - (void) update\r
107     const ScopedLock sl (*contextLock);\r
108     needsUpdate = true;\r
111 - (void) reshape\r
113     const ScopedLock sl (*contextLock);\r
114     needsUpdate = true;\r
117 - (void) rightMouseDown: (NSEvent*) ev\r
119     [[self superview] rightMouseDown: ev];\r
122 - (void) rightMouseUp: (NSEvent*) ev\r
124     [[self superview] rightMouseUp: ev];\r
127 @end\r
128 BEGIN_JUCE_NAMESPACE\r
130 //==============================================================================\r
131 class WindowedGLContext     : public OpenGLContext\r
133 public:\r
134     WindowedGLContext (Component& component,\r
135                        const OpenGLPixelFormat& pixelFormat_,\r
136                        NSOpenGLContext* sharedContext)\r
137         : renderContext (nil),\r
138           pixelFormat (pixelFormat_)\r
139     {\r
140         NSOpenGLPixelFormatAttribute attribs[] =\r
141         {\r
142             NSOpenGLPFADoubleBuffer,\r
143             NSOpenGLPFAAccelerated,\r
144             NSOpenGLPFAMPSafe,\r
145             NSOpenGLPFAClosestPolicy,\r
146             NSOpenGLPFANoRecovery,\r
147             NSOpenGLPFAColorSize,   (NSOpenGLPixelFormatAttribute) (pixelFormat.redBits\r
148                                                                         + pixelFormat.greenBits\r
149                                                                         + pixelFormat.blueBits),\r
150             NSOpenGLPFAAlphaSize,   (NSOpenGLPixelFormatAttribute) pixelFormat.alphaBits,\r
151             NSOpenGLPFADepthSize,   (NSOpenGLPixelFormatAttribute) pixelFormat.depthBufferBits,\r
152             NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute) pixelFormat.stencilBufferBits,\r
153             NSOpenGLPFAAccumSize,   (NSOpenGLPixelFormatAttribute) (pixelFormat.accumulationBufferRedBits\r
154                                                                         + pixelFormat.accumulationBufferGreenBits\r
155                                                                         + pixelFormat.accumulationBufferBlueBits\r
156                                                                         + pixelFormat.accumulationBufferAlphaBits),\r
157             NSOpenGLPFASampleBuffers, (NSOpenGLPixelFormatAttribute) 1,\r
158             (NSOpenGLPixelFormatAttribute) 0\r
159         };\r
161         NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];\r
163         view = [[ThreadSafeNSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)\r
164                                                  pixelFormat: format];\r
166         renderContext = [[[NSOpenGLContext alloc] initWithFormat: format\r
167                                                     shareContext: sharedContext] autorelease];\r
169         const GLint swapInterval = 1;\r
170         [renderContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval];\r
172         [view setOpenGLContext: renderContext];\r
173         [format release];\r
175         viewHolder = new NSViewComponentInternal (view, component);\r
176     }\r
178     ~WindowedGLContext()\r
179     {\r
180         deleteContext();\r
181         viewHolder = 0;\r
182     }\r
184     void deleteContext()\r
185     {\r
186         makeInactive();\r
187         [renderContext clearDrawable];\r
188         [renderContext setView: nil];\r
189         [view setOpenGLContext: nil];\r
190         renderContext = nil;\r
191     }\r
193     bool makeActive() const noexcept\r
194     {\r
195         jassert (renderContext != nil);\r
197         if ([renderContext view] != view)\r
198             [renderContext setView: view];\r
200         [view makeActive];\r
201         return isActive();\r
202     }\r
204     bool makeInactive() const noexcept\r
205     {\r
206         [view makeInactive];\r
207         return true;\r
208     }\r
210     bool isActive() const noexcept\r
211     {\r
212         return [NSOpenGLContext currentContext] == renderContext;\r
213     }\r
215     const OpenGLPixelFormat getPixelFormat() const  { return pixelFormat; }\r
216     void* getRawContext() const noexcept            { return renderContext; }\r
218     void updateWindowPosition (const Rectangle<int>&) {}\r
220     void swapBuffers()\r
221     {\r
222         [renderContext flushBuffer];\r
223     }\r
225     bool setSwapInterval (const int numFramesPerSwap)\r
226     {\r
227         [renderContext setValues: (const GLint*) &numFramesPerSwap\r
228                     forParameter: NSOpenGLCPSwapInterval];\r
229         return true;\r
230     }\r
232     int getSwapInterval() const\r
233     {\r
234         GLint numFrames = 0;\r
235         [renderContext getValues: &numFrames\r
236                     forParameter: NSOpenGLCPSwapInterval];\r
237         return numFrames;\r
238     }\r
240     void repaint()\r
241     {\r
242         // we need to invalidate the juce view that holds this gl view, to make it\r
243         // cause a repaint callback\r
244         NSView* v = (NSView*) viewHolder->view;\r
245         NSRect r = [v frame];\r
247         // bit of a bodge here.. if we only invalidate the area of the gl component,\r
248         // it's completely covered by the NSOpenGLView, so the OS throws away the\r
249         // repaint message, thus never causing our paint() callback, and never repainting\r
250         // the comp. So invalidating just a little bit around the edge helps..\r
251         [[v superview] setNeedsDisplayInRect: NSInsetRect (r, -2.0f, -2.0f)];\r
252     }\r
254     void* getNativeWindowHandle() const     { return viewHolder->view; }\r
256     //==============================================================================\r
257     NSOpenGLContext* renderContext;\r
258     ThreadSafeNSOpenGLView* view;\r
260 private:\r
261     OpenGLPixelFormat pixelFormat;\r
262     ScopedPointer <NSViewComponentInternal> viewHolder;\r
264     //==============================================================================\r
265     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowedGLContext);\r
266 };\r
268 //==============================================================================\r
269 OpenGLContext* OpenGLComponent::createContext()\r
271     ScopedPointer<WindowedGLContext> c (new WindowedGLContext (*this, preferredPixelFormat,\r
272                                                                contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil));\r
274     return (c->renderContext != nil) ? c.release() : nullptr;\r
277 void* OpenGLComponent::getNativeWindowHandle() const\r
279     return context != nullptr ? static_cast<WindowedGLContext*> (static_cast<OpenGLContext*> (context))->getNativeWindowHandle()\r
280                               : nullptr;\r
283 void juce_glViewport (const int w, const int h)\r
285     glViewport (0, 0, w, h);\r
288 static int getPixelFormatAttribute (NSOpenGLPixelFormat* p, NSOpenGLPixelFormatAttribute att)\r
290     GLint val = 0;\r
291     [p getValues: &val forAttribute: att forVirtualScreen: 0];\r
292     return (int) val;\r
295 void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/,\r
296                                                   OwnedArray <OpenGLPixelFormat>& results)\r
298     NSOpenGLPixelFormatAttribute attributes[] =\r
299     {\r
300         NSOpenGLPFAWindow,\r
301         NSOpenGLPFADoubleBuffer,\r
302         NSOpenGLPFAAccelerated,\r
303         NSOpenGLPFANoRecovery,\r
304         NSOpenGLPFADepthSize,  (NSOpenGLPixelFormatAttribute) 16,\r
305         NSOpenGLPFAAlphaSize,  (NSOpenGLPixelFormatAttribute) 8,\r
306         NSOpenGLPFAColorSize,  (NSOpenGLPixelFormatAttribute) 24,\r
307         NSOpenGLPFAAccumSize,  (NSOpenGLPixelFormatAttribute) 32,\r
308         (NSOpenGLPixelFormatAttribute) 0\r
309     };\r
311     NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes];\r
313     if (format != nil)\r
314     {\r
315         OpenGLPixelFormat* const pf = new OpenGLPixelFormat();\r
317         pf->redBits = pf->greenBits = pf->blueBits = getPixelFormatAttribute (format, NSOpenGLPFAColorSize) / 3;\r
318         pf->alphaBits = getPixelFormatAttribute (format, NSOpenGLPFAAlphaSize);\r
319         pf->depthBufferBits = getPixelFormatAttribute (format, NSOpenGLPFADepthSize);\r
320         pf->stencilBufferBits = getPixelFormatAttribute (format, NSOpenGLPFAStencilSize);\r
321         pf->accumulationBufferRedBits = pf->accumulationBufferGreenBits\r
322             = pf->accumulationBufferBlueBits = pf->accumulationBufferAlphaBits\r
323             = getPixelFormatAttribute (format, NSOpenGLPFAAccumSize) / 4;\r
325         [format release];\r
326         results.add (pf);\r
327     }\r
330 #else\r
331 //==============================================================================\r
333 END_JUCE_NAMESPACE\r
335 @interface JuceGLView   : UIView\r
338 + (Class) layerClass;\r
339 @end\r
341 @implementation JuceGLView\r
342 + (Class) layerClass\r
344     return [CAEAGLLayer class];\r
346 @end\r
348 BEGIN_JUCE_NAMESPACE\r
350 //==============================================================================\r
351 class GLESContext   : public OpenGLContext\r
353 public:\r
354     GLESContext (UIViewComponentPeer* peer,\r
355                  Component* const component_,\r
356                  const OpenGLPixelFormat& pixelFormat_,\r
357                  const GLESContext* const sharedContext,\r
358                  NSUInteger apiType)\r
359         : component (component_), pixelFormat (pixelFormat_), glLayer (nil), context (nil),\r
360           useDepthBuffer (pixelFormat_.depthBufferBits > 0), frameBufferHandle (0), colorBufferHandle (0),\r
361           depthBufferHandle (0), lastWidth (0), lastHeight (0)\r
362     {\r
363         view = [[JuceGLView alloc] initWithFrame: CGRectMake (0, 0, 64, 64)];\r
364         view.opaque = YES;\r
365         view.hidden = NO;\r
366         view.backgroundColor = [UIColor blackColor];\r
367         view.userInteractionEnabled = NO;\r
369         glLayer = (CAEAGLLayer*) [view layer];\r
370         [peer->view addSubview: view];\r
372         if (sharedContext != nullptr)\r
373             context = [[EAGLContext alloc] initWithAPI: apiType\r
374                                             sharegroup: [sharedContext->context sharegroup]];\r
375         else\r
376             context = [[EAGLContext alloc] initWithAPI: apiType];\r
378         createGLBuffers();\r
379     }\r
381     ~GLESContext()\r
382     {\r
383         deleteContext();\r
385         [view removeFromSuperview];\r
386         [view release];\r
387         freeGLBuffers();\r
388     }\r
390     void deleteContext()\r
391     {\r
392         makeInactive();\r
393         [context release];\r
394         context = nil;\r
395     }\r
397     bool makeActive() const noexcept\r
398     {\r
399         jassert (context != nil);\r
401         [EAGLContext setCurrentContext: context];\r
402         glBindFramebufferOES (GL_FRAMEBUFFER_OES, frameBufferHandle);\r
403         return true;\r
404     }\r
406     void swapBuffers()\r
407     {\r
408         glBindRenderbufferOES (GL_RENDERBUFFER_OES, colorBufferHandle);\r
409         [context presentRenderbuffer: GL_RENDERBUFFER_OES];\r
410     }\r
412     bool makeInactive() const noexcept\r
413     {\r
414         return [EAGLContext setCurrentContext: nil];\r
415     }\r
417     bool isActive() const noexcept\r
418     {\r
419         return [EAGLContext currentContext] == context;\r
420     }\r
422     const OpenGLPixelFormat getPixelFormat() const  { return pixelFormat; }\r
423     void* getRawContext() const noexcept            { return glLayer; }\r
425     void updateWindowPosition (const Rectangle<int>& bounds)\r
426     {\r
427         view.frame = CGRectMake ((CGFloat) bounds.getX(), (CGFloat) bounds.getY(),\r
428                                  (CGFloat) bounds.getWidth(), (CGFloat) bounds.getHeight());\r
430         if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight())\r
431         {\r
432             lastWidth = bounds.getWidth();\r
433             lastHeight = bounds.getHeight();\r
434             freeGLBuffers();\r
435             createGLBuffers();\r
436         }\r
437     }\r
439     bool setSwapInterval (const int numFramesPerSwap)\r
440     {\r
441         numFrames = numFramesPerSwap;\r
442         return true;\r
443     }\r
445     int getSwapInterval() const\r
446     {\r
447         return numFrames;\r
448     }\r
450     void repaint()\r
451     {\r
452     }\r
454     //==============================================================================\r
455     void createGLBuffers()\r
456     {\r
457         makeActive();\r
459         glGenFramebuffersOES (1, &frameBufferHandle);\r
460         glGenRenderbuffersOES (1, &colorBufferHandle);\r
461         glGenRenderbuffersOES (1, &depthBufferHandle);\r
463         glBindRenderbufferOES (GL_RENDERBUFFER_OES, colorBufferHandle);\r
464         [context renderbufferStorage: GL_RENDERBUFFER_OES fromDrawable: glLayer];\r
466         GLint width, height;\r
467         glGetRenderbufferParameterivOES (GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);\r
468         glGetRenderbufferParameterivOES (GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);\r
470         if (useDepthBuffer)\r
471         {\r
472             glBindRenderbufferOES (GL_RENDERBUFFER_OES, depthBufferHandle);\r
473             glRenderbufferStorageOES (GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height);\r
474         }\r
476         glBindRenderbufferOES (GL_RENDERBUFFER_OES, colorBufferHandle);\r
478         glBindFramebufferOES (GL_FRAMEBUFFER_OES, frameBufferHandle);\r
479         glFramebufferRenderbufferOES (GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorBufferHandle);\r
481         if (useDepthBuffer)\r
482             glFramebufferRenderbufferOES (GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthBufferHandle);\r
484         jassert (glCheckFramebufferStatusOES (GL_FRAMEBUFFER_OES) == GL_FRAMEBUFFER_COMPLETE_OES);\r
485     }\r
487     void freeGLBuffers()\r
488     {\r
489         if (frameBufferHandle != 0)\r
490         {\r
491             glDeleteFramebuffersOES (1, &frameBufferHandle);\r
492             frameBufferHandle = 0;\r
493         }\r
495         if (colorBufferHandle != 0)\r
496         {\r
497             glDeleteRenderbuffersOES (1, &colorBufferHandle);\r
498             colorBufferHandle = 0;\r
499         }\r
501         if (depthBufferHandle != 0)\r
502         {\r
503             glDeleteRenderbuffersOES (1, &depthBufferHandle);\r
504             depthBufferHandle = 0;\r
505         }\r
506     }\r
508     //==============================================================================\r
509 private:\r
510     WeakReference<Component> component;\r
511     OpenGLPixelFormat pixelFormat;\r
512     JuceGLView* view;\r
513     CAEAGLLayer* glLayer;\r
514     EAGLContext* context;\r
515     bool useDepthBuffer;\r
516     GLuint frameBufferHandle, colorBufferHandle, depthBufferHandle;\r
517     int numFrames;\r
518     int lastWidth, lastHeight;\r
520     //==============================================================================\r
521     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GLESContext);\r
522 };\r
525 OpenGLContext* OpenGLComponent::createContext()\r
527     JUCE_AUTORELEASEPOOL\r
528     UIViewComponentPeer* peer = dynamic_cast <UIViewComponentPeer*> (getPeer());\r
530     if (peer != nullptr)\r
531         return new GLESContext (peer, this, preferredPixelFormat,\r
532                                 dynamic_cast <const GLESContext*> (contextToShareListsWith),\r
533                                 type == openGLES2 ? kEAGLRenderingAPIOpenGLES2 : kEAGLRenderingAPIOpenGLES1);\r
535     return nullptr;\r
538 void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/,\r
539                                                   OwnedArray <OpenGLPixelFormat>& /*results*/)\r
543 void juce_glViewport (const int w, const int h)\r
545     glViewport (0, 0, w, h);\r
548 #endif\r
550 #endif\r