|  | /*
  ==============================================================================
   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-11 by Raw Material Software Ltd.
  ------------------------------------------------------------------------------
   JUCE can be redistributed and/or modified under the terms of the GNU General
   Public License (Version 2), as published by the Free Software Foundation.
   A copy of the license is included in the JUCE distribution, or can be found
   online at www.gnu.org/licenses.
   JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  ------------------------------------------------------------------------------
   To release a closed-source product which uses JUCE, commercial licenses are
   available: visit www.rawmaterialsoftware.com/juce for more information.
  ==============================================================================
*/
END_JUCE_NAMESPACE
#define ThreadSafeNSOpenGLView MakeObjCClassName(ThreadSafeNSOpenGLView)
//==============================================================================
@interface ThreadSafeNSOpenGLView  : NSOpenGLView
{
    CriticalSection* contextLock;
    bool needsUpdate;
}
- (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format;
- (bool) makeActive;
- (void) makeInactive;
- (void) reshape;
- (void) rightMouseDown: (NSEvent*) ev;
- (void) rightMouseUp: (NSEvent*) ev;
@end
@implementation ThreadSafeNSOpenGLView
- (id) initWithFrame: (NSRect) frameRect
         pixelFormat: (NSOpenGLPixelFormat*) format
{
    contextLock = new CriticalSection();
    self = [super initWithFrame: frameRect pixelFormat: format];
    if (self != nil)
        [[NSNotificationCenter defaultCenter] addObserver: self
                                                 selector: @selector (_surfaceNeedsUpdate:)
                                                     name: NSViewGlobalFrameDidChangeNotification
                                                   object: self];
    return self;
}
- (void) dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver: self];
    delete contextLock;
    [super dealloc];
}
- (bool) makeActive
{
    const ScopedLock sl (*contextLock);
    if ([self openGLContext] == 0)
        return false;
    [[self openGLContext] makeCurrentContext];
    if (needsUpdate)
    {
        [super update];
        needsUpdate = false;
    }
    return true;
}
- (void) makeInactive
{
    const ScopedLock sl (*contextLock);
    [NSOpenGLContext clearCurrentContext];
}
- (void) _surfaceNeedsUpdate: (NSNotification*) notification
{
    (void) notification;
    const ScopedLock sl (*contextLock);
    needsUpdate = true;
}
- (void) update
{
    const ScopedLock sl (*contextLock);
    needsUpdate = true;
}
- (void) reshape
{
    const ScopedLock sl (*contextLock);
    needsUpdate = true;
}
- (void) rightMouseDown: (NSEvent*) ev
{
    [[self superview] rightMouseDown: ev];
}
- (void) rightMouseUp: (NSEvent*) ev
{
    [[self superview] rightMouseUp: ev];
}
@end
BEGIN_JUCE_NAMESPACE
//==============================================================================
class WindowedGLContext     : public OpenGLContext
{
public:
    WindowedGLContext (OpenGLComponent& component,
                       const OpenGLPixelFormat& pixelFormat_,
                       NSOpenGLContext* sharedContext)
        : renderContext (nil),
          pixelFormat (pixelFormat_)
    {
        NSOpenGLPixelFormatAttribute attribs[] =
        {
            NSOpenGLPFADoubleBuffer,
            NSOpenGLPFAAccelerated,
            NSOpenGLPFAMPSafe,
            NSOpenGLPFAClosestPolicy,
            NSOpenGLPFANoRecovery,
            NSOpenGLPFAColorSize,   (NSOpenGLPixelFormatAttribute) (pixelFormat.redBits
                                                                        + pixelFormat.greenBits
                                                                        + pixelFormat.blueBits),
            NSOpenGLPFAAlphaSize,   (NSOpenGLPixelFormatAttribute) pixelFormat.alphaBits,
            NSOpenGLPFADepthSize,   (NSOpenGLPixelFormatAttribute) pixelFormat.depthBufferBits,
            NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute) pixelFormat.stencilBufferBits,
            NSOpenGLPFAAccumSize,   (NSOpenGLPixelFormatAttribute) (pixelFormat.accumulationBufferRedBits
                                                                        + pixelFormat.accumulationBufferGreenBits
                                                                        + pixelFormat.accumulationBufferBlueBits
                                                                        + pixelFormat.accumulationBufferAlphaBits),
            NSOpenGLPFASampleBuffers, (NSOpenGLPixelFormatAttribute) 1,
            (NSOpenGLPixelFormatAttribute) 0
        };
        NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
        view = [[ThreadSafeNSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
                                                 pixelFormat: format];
        renderContext = [[[NSOpenGLContext alloc] initWithFormat: format
                                                    shareContext: sharedContext] autorelease];
        const GLint swapInterval = 1;
        [renderContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval];
        [view setOpenGLContext: renderContext];
        [format release];
        component.setView (view);
    }
    ~WindowedGLContext()
    {
        deleteContext();
    }
    void deleteContext()
    {
        makeInactive();
        [renderContext clearDrawable];
        [renderContext setView: nil];
        [view setOpenGLContext: nil];
        renderContext = nil;
    }
    bool makeActive() const noexcept
    {
        jassert (renderContext != nil);
        if ([renderContext view] != view)
            [renderContext setView: view];
        [view makeActive];
        return isActive();
    }
    bool makeInactive() const noexcept
    {
        [view makeInactive];
        return true;
    }
    bool isActive() const noexcept
    {
        return [NSOpenGLContext currentContext] == renderContext;
    }
    OpenGLPixelFormat getPixelFormat() const        { return pixelFormat; }
    void* getRawContext() const noexcept            { return renderContext; }
    void updateWindowPosition (const Rectangle<int>&) {}
    void swapBuffers()
    {
        [renderContext flushBuffer];
    }
    bool setSwapInterval (const int numFramesPerSwap)
    {
        [renderContext setValues: (const GLint*) &numFramesPerSwap
                    forParameter: NSOpenGLCPSwapInterval];
        return true;
    }
    int getSwapInterval() const
    {
        GLint numFrames = 0;
        [renderContext getValues: &numFrames
                    forParameter: NSOpenGLCPSwapInterval];
        return numFrames;
    }
    void repaint()
    {
        // we need to invalidate the juce view that holds this gl view, to make it
        // cause a repaint callback
        NSRect r = [view frame];
        // bit of a bodge here.. if we only invalidate the area of the gl component,
        // it's completely covered by the NSOpenGLView, so the OS throws away the
        // repaint message, thus never causing our paint() callback, and never repainting
        // the comp. So invalidating just a little bit around the edge helps..
        [[view superview] setNeedsDisplayInRect: NSInsetRect (r, -2.0f, -2.0f)];
    }
    void* getNativeWindowHandle() const     { return view; }
    //==============================================================================
    NSOpenGLContext* renderContext;
    ThreadSafeNSOpenGLView* view;
private:
    OpenGLPixelFormat pixelFormat;
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowedGLContext);
};
//==============================================================================
OpenGLContext* OpenGLComponent::createContext()
{
    ScopedPointer<WindowedGLContext> c (new WindowedGLContext (*this, preferredPixelFormat,
                                                               contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil));
    return (c->renderContext != nil) ? c.release() : nullptr;
}
void* OpenGLComponent::getNativeWindowHandle() const
{
    return context != nullptr ? static_cast<WindowedGLContext*> (static_cast<OpenGLContext*> (context))->getNativeWindowHandle()
                              : nullptr;
}
static int getPixelFormatAttribute (NSOpenGLPixelFormat* p, NSOpenGLPixelFormatAttribute att)
{
    GLint val = 0;
    [p getValues: &val forAttribute: att forVirtualScreen: 0];
    return (int) val;
}
void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/,
                                                  OwnedArray <OpenGLPixelFormat>& results)
{
    NSOpenGLPixelFormatAttribute attributes[] =
    {
        NSOpenGLPFAWindow,
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFAAccelerated,
        NSOpenGLPFANoRecovery,
        NSOpenGLPFADepthSize,  (NSOpenGLPixelFormatAttribute) 16,
        NSOpenGLPFAAlphaSize,  (NSOpenGLPixelFormatAttribute) 8,
        NSOpenGLPFAColorSize,  (NSOpenGLPixelFormatAttribute) 24,
        NSOpenGLPFAAccumSize,  (NSOpenGLPixelFormatAttribute) 32,
        (NSOpenGLPixelFormatAttribute) 0
    };
    NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes];
    if (format != nil)
    {
        OpenGLPixelFormat* const pf = new OpenGLPixelFormat();
        pf->redBits = pf->greenBits = pf->blueBits = getPixelFormatAttribute (format, NSOpenGLPFAColorSize) / 3;
        pf->alphaBits = getPixelFormatAttribute (format, NSOpenGLPFAAlphaSize);
        pf->depthBufferBits = getPixelFormatAttribute (format, NSOpenGLPFADepthSize);
        pf->stencilBufferBits = getPixelFormatAttribute (format, NSOpenGLPFAStencilSize);
        pf->accumulationBufferRedBits = pf->accumulationBufferGreenBits
            = pf->accumulationBufferBlueBits = pf->accumulationBufferAlphaBits
            = getPixelFormatAttribute (format, NSOpenGLPFAAccumSize) / 4;
        [format release];
        results.add (pf);
    }
}
 |