|  | /*
  ==============================================================================
   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.
  ==============================================================================
*/
BEGIN_JUCE_NAMESPACE
//==============================================================================
OpenGLPixelFormat::OpenGLPixelFormat (const int bitsPerRGBComponent,
                                      const int alphaBits_,
                                      const int depthBufferBits_,
                                      const int stencilBufferBits_)
    : redBits (bitsPerRGBComponent),
      greenBits (bitsPerRGBComponent),
      blueBits (bitsPerRGBComponent),
      alphaBits (alphaBits_),
      depthBufferBits (depthBufferBits_),
      stencilBufferBits (stencilBufferBits_),
      accumulationBufferRedBits (0),
      accumulationBufferGreenBits (0),
      accumulationBufferBlueBits (0),
      accumulationBufferAlphaBits (0),
      fullSceneAntiAliasingNumSamples (0)
{
}
OpenGLPixelFormat::OpenGLPixelFormat (const OpenGLPixelFormat& other)
    : redBits (other.redBits),
      greenBits (other.greenBits),
      blueBits (other.blueBits),
      alphaBits (other.alphaBits),
      depthBufferBits (other.depthBufferBits),
      stencilBufferBits (other.stencilBufferBits),
      accumulationBufferRedBits (other.accumulationBufferRedBits),
      accumulationBufferGreenBits (other.accumulationBufferGreenBits),
      accumulationBufferBlueBits (other.accumulationBufferBlueBits),
      accumulationBufferAlphaBits (other.accumulationBufferAlphaBits),
      fullSceneAntiAliasingNumSamples (other.fullSceneAntiAliasingNumSamples)
{
}
OpenGLPixelFormat& OpenGLPixelFormat::operator= (const OpenGLPixelFormat& other)
{
    redBits = other.redBits;
    greenBits = other.greenBits;
    blueBits = other.blueBits;
    alphaBits = other.alphaBits;
    depthBufferBits = other.depthBufferBits;
    stencilBufferBits = other.stencilBufferBits;
    accumulationBufferRedBits = other.accumulationBufferRedBits;
    accumulationBufferGreenBits = other.accumulationBufferGreenBits;
    accumulationBufferBlueBits = other.accumulationBufferBlueBits;
    accumulationBufferAlphaBits = other.accumulationBufferAlphaBits;
    fullSceneAntiAliasingNumSamples = other.fullSceneAntiAliasingNumSamples;
    return *this;
}
bool OpenGLPixelFormat::operator== (const OpenGLPixelFormat& other) const
{
    return redBits == other.redBits
            && greenBits == other.greenBits
            && blueBits == other.blueBits
            && alphaBits == other.alphaBits
            && depthBufferBits == other.depthBufferBits
            && stencilBufferBits == other.stencilBufferBits
            && accumulationBufferRedBits == other.accumulationBufferRedBits
            && accumulationBufferGreenBits == other.accumulationBufferGreenBits
            && accumulationBufferBlueBits == other.accumulationBufferBlueBits
            && accumulationBufferAlphaBits == other.accumulationBufferAlphaBits
            && fullSceneAntiAliasingNumSamples == other.fullSceneAntiAliasingNumSamples;
}
//==============================================================================
static Array<OpenGLContext*> knownContexts;
OpenGLContext::OpenGLContext() noexcept
{
    knownContexts.add (this);
}
OpenGLContext::~OpenGLContext()
{
    knownContexts.removeValue (this);
}
OpenGLContext* OpenGLContext::getCurrentContext()
{
    for (int i = knownContexts.size(); --i >= 0;)
    {
        OpenGLContext* const oglc = knownContexts.getUnchecked(i);
        if (oglc->isActive())
            return oglc;
    }
    return nullptr;
}
//==============================================================================
class OpenGLComponent::OpenGLComponentWatcher  : public ComponentMovementWatcher
{
public:
    //==============================================================================
    OpenGLComponentWatcher (OpenGLComponent* const owner_)
        : ComponentMovementWatcher (owner_),
          owner (owner_)
    {
    }
    //==============================================================================
    void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
    {
        owner->updateContextPosition();
    }
    void componentPeerChanged()
    {
        owner->recreateContextAsync();
    }
    void componentVisibilityChanged()
    {
        if (! owner->isShowing())
            owner->stopBackgroundThread();
    }
    //==============================================================================
private:
    OpenGLComponent* const owner;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher);
};
//==============================================================================
class OpenGLComponent::OpenGLComponentRenderThread  : public Thread
{
public:
    OpenGLComponentRenderThread (OpenGLComponent& owner_)
        : Thread ("OpenGL Render"),
          owner (owner_)
    {
    }
    void run()
    {
       #if JUCE_LINUX
        {
            MessageManagerLock mml (this);
            if (! mml.lockWasGained())
                return;
            owner.updateContext();
            owner.updateContextPosition();
        }
       #endif
        while (! threadShouldExit())
        {
            const uint32 startOfRendering = Time::getMillisecondCounter();
            if (! owner.renderAndSwapBuffers())
                break;
            const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering);
            Thread::sleep (jmax (1, 20 - elapsed));
        }
       #if JUCE_LINUX
        owner.deleteContext();
       #endif
    }
private:
    OpenGLComponent& owner;
    JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread);
};
void OpenGLComponent::startRenderThread()
{
    if (renderThread == nullptr)
        renderThread = new OpenGLComponentRenderThread (*this);
    renderThread->startThread (6);
}
void OpenGLComponent::stopRenderThread()
{
    if (renderThread != nullptr)
    {
        renderThread->stopThread (5000);
        renderThread = nullptr;
    }
   #if ! JUCE_LINUX
    deleteContext();
   #endif
}
//==============================================================================
OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread)
    : type (type_),
      contextToShareListsWith (nullptr),
      needToUpdateViewport (true),
      needToDeleteContext (false),
      threadStarted (false),
      useThread (useBackgroundThread)
{
    setOpaque (true);
    componentWatcher = new OpenGLComponentWatcher (this);
}
OpenGLComponent::~OpenGLComponent()
{
    stopBackgroundThread();
    componentWatcher = nullptr;
}
OpenGLPixelFormat OpenGLComponent::getPixelFormat() const
{
    OpenGLPixelFormat pf;
    const ScopedLock sl (contextLock);
    if (context != nullptr)
        pf = context->getPixelFormat();
    return pf;
}
void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse)
{
    if (! (preferredPixelFormat == formatToUse))
    {
        const ScopedLock sl (contextLock);
        preferredPixelFormat = formatToUse;
        recreateContextAsync();
    }
}
void OpenGLComponent::shareWith (OpenGLContext* c)
{
    if (contextToShareListsWith != c)
    {
        const ScopedLock sl (contextLock);
        contextToShareListsWith = c;
        recreateContextAsync();
    }
}
void OpenGLComponent::recreateContextAsync()
{
    const ScopedLock sl (contextLock);
    needToDeleteContext = true;
    repaint();
}
bool OpenGLComponent::makeCurrentContextActive()
{
    return context != nullptr && context->makeActive();
}
void OpenGLComponent::makeCurrentContextInactive()
{
    if (context != nullptr)
        context->makeInactive();
}
bool OpenGLComponent::isActiveContext() const noexcept
{
    return context != nullptr && context->isActive();
}
void OpenGLComponent::swapBuffers()
{
    if (context != nullptr)
        context->swapBuffers();
}
void OpenGLComponent::updateContext()
{
    if (needToDeleteContext)
        deleteContext();
    if (context == nullptr)
    {
        const ScopedLock sl (contextLock);
        if (context == nullptr)
        {
            context = createContext();
            if (context != nullptr)
            {
               #if JUCE_LINUX
                if (! useThread)
               #endif
                    updateContextPosition();
                if (context->makeActive())
                {
                    newOpenGLContextCreated();
                    context->makeInactive();
                }
            }
        }
    }
}
void OpenGLComponent::deleteContext()
{
    const ScopedLock sl (contextLock);
    if (context != nullptr)
    {
        if (context->makeActive())
        {
            releaseOpenGLContext();
            context->makeInactive();
        }
        context = nullptr;
    }
    needToDeleteContext = false;
}
void OpenGLComponent::updateContextPosition()
{
    needToUpdateViewport = true;
    if (getWidth() > 0 && getHeight() > 0)
    {
        Component* const topComp = getTopLevelComponent();
        if (topComp->getPeer() != nullptr)
        {
            const ScopedLock sl (contextLock);
            if (context != nullptr)
                context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
        }
    }
}
void OpenGLComponent::stopBackgroundThread()
{
    if (threadStarted)
    {
        stopRenderThread();
        threadStarted = false;
    }
}
void OpenGLComponent::paint (Graphics&)
{
    ComponentPeer* const peer = getPeer();
    if (useThread)
    {
        if (peer != nullptr && isShowing())
        {
           #if ! JUCE_LINUX
            updateContext();
           #endif
            if (! threadStarted)
            {
                threadStarted = true;
                startRenderThread();
            }
        }
    }
    else
    {
        updateContext();
        if (! renderAndSwapBuffers())
            return;
    }
    if (peer != nullptr)
    {
        const Point<int> topLeft (getScreenPosition() - peer->getScreenPosition());
        peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight());
    }
}
bool OpenGLComponent::renderAndSwapBuffers()
{
    const ScopedLock sl (contextLock);
   #if JUCE_LINUX
    updateContext();
   #endif
    if (context != nullptr)
    {
        if (! makeCurrentContextActive())
            return false;
        if (needToUpdateViewport)
        {
            needToUpdateViewport = false;
            glViewport (0, 0, getWidth(), getHeight());
        }
        renderOpenGL();
        swapBuffers();
    }
    return true;
}
void OpenGLComponent::internalRepaint (int x, int y, int w, int h)
{
    Component::internalRepaint (x, y, w, h);
    if (context != nullptr)
        context->repaint();
}
END_JUCE_NAMESPACE
 |