2 ==============================================================================
\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
7 ------------------------------------------------------------------------------
\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
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
34 #define ThreadSafeNSOpenGLView MakeObjCClassName(ThreadSafeNSOpenGLView)
\r
36 //==============================================================================
\r
37 @interface ThreadSafeNSOpenGLView : NSOpenGLView
\r
39 CriticalSection* contextLock;
\r
43 - (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format;
\r
44 - (bool) makeActive;
\r
45 - (void) makeInactive;
\r
47 - (void) rightMouseDown: (NSEvent*) ev;
\r
48 - (void) rightMouseUp: (NSEvent*) ev;
\r
51 @implementation ThreadSafeNSOpenGLView
\r
53 - (id) initWithFrame: (NSRect) frameRect
\r
54 pixelFormat: (NSOpenGLPixelFormat*) format
\r
56 contextLock = new CriticalSection();
\r
57 self = [super initWithFrame: frameRect pixelFormat: format];
\r
60 [[NSNotificationCenter defaultCenter] addObserver: self
\r
61 selector: @selector (_surfaceNeedsUpdate:)
\r
62 name: NSViewGlobalFrameDidChangeNotification
\r
69 [[NSNotificationCenter defaultCenter] removeObserver: self];
\r
76 const ScopedLock sl (*contextLock);
\r
78 if ([self openGLContext] == 0)
\r
81 [[self openGLContext] makeCurrentContext];
\r
86 needsUpdate = false;
\r
92 - (void) makeInactive
\r
94 const ScopedLock sl (*contextLock);
\r
95 [NSOpenGLContext clearCurrentContext];
\r
98 - (void) _surfaceNeedsUpdate: (NSNotification*) notification
\r
100 (void) notification;
\r
101 const ScopedLock sl (*contextLock);
\r
102 needsUpdate = true;
\r
107 const ScopedLock sl (*contextLock);
\r
108 needsUpdate = true;
\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
128 BEGIN_JUCE_NAMESPACE
\r
130 //==============================================================================
\r
131 class WindowedGLContext : public OpenGLContext
\r
134 WindowedGLContext (Component& component,
\r
135 const OpenGLPixelFormat& pixelFormat_,
\r
136 NSOpenGLContext* sharedContext)
\r
137 : renderContext (nil),
\r
138 pixelFormat (pixelFormat_)
\r
140 NSOpenGLPixelFormatAttribute attribs[] =
\r
142 NSOpenGLPFADoubleBuffer,
\r
143 NSOpenGLPFAAccelerated,
\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
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
175 viewHolder = new NSViewComponentInternal (view, component);
\r
178 ~WindowedGLContext()
\r
184 void deleteContext()
\r
187 [renderContext clearDrawable];
\r
188 [renderContext setView: nil];
\r
189 [view setOpenGLContext: nil];
\r
190 renderContext = nil;
\r
193 bool makeActive() const noexcept
\r
195 jassert (renderContext != nil);
\r
197 if ([renderContext view] != view)
\r
198 [renderContext setView: view];
\r
204 bool makeInactive() const noexcept
\r
206 [view makeInactive];
\r
210 bool isActive() const noexcept
\r
212 return [NSOpenGLContext currentContext] == renderContext;
\r
215 const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
\r
216 void* getRawContext() const noexcept { return renderContext; }
\r
218 void updateWindowPosition (const Rectangle<int>&) {}
\r
222 [renderContext flushBuffer];
\r
225 bool setSwapInterval (const int numFramesPerSwap)
\r
227 [renderContext setValues: (const GLint*) &numFramesPerSwap
\r
228 forParameter: NSOpenGLCPSwapInterval];
\r
232 int getSwapInterval() const
\r
234 GLint numFrames = 0;
\r
235 [renderContext getValues: &numFrames
\r
236 forParameter: NSOpenGLCPSwapInterval];
\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
254 void* getNativeWindowHandle() const { return viewHolder->view; }
\r
256 //==============================================================================
\r
257 NSOpenGLContext* renderContext;
\r
258 ThreadSafeNSOpenGLView* view;
\r
261 OpenGLPixelFormat pixelFormat;
\r
262 ScopedPointer <NSViewComponentInternal> viewHolder;
\r
264 //==============================================================================
\r
265 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowedGLContext);
\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
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
291 [p getValues: &val forAttribute: att forVirtualScreen: 0];
\r
295 void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/,
\r
296 OwnedArray <OpenGLPixelFormat>& results)
\r
298 NSOpenGLPixelFormatAttribute attributes[] =
\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
311 NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes];
\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
331 //==============================================================================
\r
335 @interface JuceGLView : UIView
\r
338 + (Class) layerClass;
\r
341 @implementation JuceGLView
\r
342 + (Class) layerClass
\r
344 return [CAEAGLLayer class];
\r
348 BEGIN_JUCE_NAMESPACE
\r
350 //==============================================================================
\r
351 class GLESContext : public OpenGLContext
\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
363 view = [[JuceGLView alloc] initWithFrame: CGRectMake (0, 0, 64, 64)];
\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
376 context = [[EAGLContext alloc] initWithAPI: apiType];
\r
385 [view removeFromSuperview];
\r
390 void deleteContext()
\r
397 bool makeActive() const noexcept
\r
399 jassert (context != nil);
\r
401 [EAGLContext setCurrentContext: context];
\r
402 glBindFramebufferOES (GL_FRAMEBUFFER_OES, frameBufferHandle);
\r
408 glBindRenderbufferOES (GL_RENDERBUFFER_OES, colorBufferHandle);
\r
409 [context presentRenderbuffer: GL_RENDERBUFFER_OES];
\r
412 bool makeInactive() const noexcept
\r
414 return [EAGLContext setCurrentContext: nil];
\r
417 bool isActive() const noexcept
\r
419 return [EAGLContext currentContext] == context;
\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
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
432 lastWidth = bounds.getWidth();
\r
433 lastHeight = bounds.getHeight();
\r
439 bool setSwapInterval (const int numFramesPerSwap)
\r
441 numFrames = numFramesPerSwap;
\r
445 int getSwapInterval() const
\r
454 //==============================================================================
\r
455 void createGLBuffers()
\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
472 glBindRenderbufferOES (GL_RENDERBUFFER_OES, depthBufferHandle);
\r
473 glRenderbufferStorageOES (GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height);
\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
487 void freeGLBuffers()
\r
489 if (frameBufferHandle != 0)
\r
491 glDeleteFramebuffersOES (1, &frameBufferHandle);
\r
492 frameBufferHandle = 0;
\r
495 if (colorBufferHandle != 0)
\r
497 glDeleteRenderbuffersOES (1, &colorBufferHandle);
\r
498 colorBufferHandle = 0;
\r
501 if (depthBufferHandle != 0)
\r
503 glDeleteRenderbuffersOES (1, &depthBufferHandle);
\r
504 depthBufferHandle = 0;
\r
508 //==============================================================================
\r
510 WeakReference<Component> component;
\r
511 OpenGLPixelFormat pixelFormat;
\r
513 CAEAGLLayer* glLayer;
\r
514 EAGLContext* context;
\r
515 bool useDepthBuffer;
\r
516 GLuint frameBufferHandle, colorBufferHandle, depthBufferHandle;
\r
518 int lastWidth, lastHeight;
\r
520 //==============================================================================
\r
521 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GLESContext);
\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
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