| @@ -31827,11 +31827,10 @@ namespace AudioUnitFormatHelpers | |||
| const String osTypeToString (OSType type) | |||
| { | |||
| char s[4]; | |||
| s[0] = (char) (((uint32) type) >> 24); | |||
| s[1] = (char) (((uint32) type) >> 16); | |||
| s[2] = (char) (((uint32) type) >> 8); | |||
| s[3] = (char) ((uint32) type); | |||
| const juce_wchar s[4] = { (juce_wchar) (((uint32) type) >> 24), | |||
| (juce_wchar) (((uint32) type) >> 16), | |||
| (juce_wchar) (((uint32) type) >> 8), | |||
| (juce_wchar) ((uint32) type) }; | |||
| return String (s, 4); | |||
| } | |||
| @@ -31842,7 +31841,7 @@ namespace AudioUnitFormatHelpers | |||
| return (((OSType) (unsigned char) s[0]) << 24) | |||
| | (((OSType) (unsigned char) s[1]) << 16) | |||
| | (((OSType) (unsigned char) s[2]) << 8) | |||
| | ((OSType) (unsigned char) s[3]); | |||
| | ((OSType) (unsigned char) s[3]); | |||
| } | |||
| static const char* auIdentifierPrefix = "AudioUnit:"; | |||
| @@ -77111,10 +77110,41 @@ OpenGLContext* OpenGLContext::getCurrentContext() | |||
| return nullptr; | |||
| } | |||
| class OpenGLComponent::OpenGLComponentRenderThread : public Thread | |||
| 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_) | |||
| @@ -77134,7 +77164,9 @@ public: | |||
| Thread::sleep (jmax (1, 20 - elapsed)); | |||
| } | |||
| owner.stopRenderThread(); | |||
| #if JUCE_LINUX | |||
| owner.deleteContext(); | |||
| #endif | |||
| } | |||
| private: | |||
| @@ -77143,49 +77175,34 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread); | |||
| }; | |||
| class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher, | |||
| public AsyncUpdater | |||
| void OpenGLComponent::startRenderThread() | |||
| { | |||
| public: | |||
| OpenGLComponentWatcher (OpenGLComponent* const owner_) | |||
| : ComponentMovementWatcher (owner_), | |||
| owner (owner_) | |||
| { | |||
| } | |||
| if (renderThread == nullptr) | |||
| renderThread = new OpenGLComponentRenderThread (*this); | |||
| void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | |||
| { | |||
| owner->updateContextPosition(); | |||
| } | |||
| void componentPeerChanged() | |||
| { | |||
| owner->stopRendering(); | |||
| } | |||
| void componentVisibilityChanged() | |||
| { | |||
| if (! owner->isShowing()) | |||
| owner->stopRendering(); | |||
| } | |||
| renderThread->startThread (6); | |||
| } | |||
| void handleAsyncUpdate() | |||
| void OpenGLComponent::stopRenderThread() | |||
| { | |||
| if (renderThread != nullptr) | |||
| { | |||
| owner->stopRendering(); | |||
| renderThread->stopThread (5000); | |||
| renderThread = nullptr; | |||
| } | |||
| private: | |||
| OpenGLComponent* const owner; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); | |||
| }; | |||
| #if ! JUCE_LINUX | |||
| deleteContext(); | |||
| #endif | |||
| } | |||
| OpenGLComponent::OpenGLComponent (const OpenGLType type_) | |||
| OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread) | |||
| : type (type_), | |||
| contextToShareListsWith (nullptr), | |||
| needToUpdateViewport (true), | |||
| useThread (false) | |||
| needToDeleteContext (false), | |||
| threadStarted (false), | |||
| useThread (useBackgroundThread) | |||
| { | |||
| setOpaque (true); | |||
| componentWatcher = new OpenGLComponentWatcher (this); | |||
| @@ -77193,39 +77210,10 @@ OpenGLComponent::OpenGLComponent (const OpenGLType type_) | |||
| OpenGLComponent::~OpenGLComponent() | |||
| { | |||
| stopRendering(); | |||
| renderThread = nullptr; | |||
| stopBackgroundThread(); | |||
| componentWatcher = nullptr; | |||
| } | |||
| void OpenGLComponent::deleteContext() | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| context = nullptr; | |||
| } | |||
| 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 (getScreenX() - topComp->getScreenX(), | |||
| getScreenY() - topComp->getScreenY(), | |||
| getWidth(), | |||
| getHeight(), | |||
| topComp->getHeight()); | |||
| } | |||
| } | |||
| } | |||
| const OpenGLPixelFormat OpenGLComponent::getPixelFormat() const | |||
| { | |||
| OpenGLPixelFormat pf; | |||
| @@ -77242,8 +77230,8 @@ void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) | |||
| if (! (preferredPixelFormat == formatToUse)) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| deleteContext(); | |||
| preferredPixelFormat = formatToUse; | |||
| recreateContextAsync(); | |||
| } | |||
| } | |||
| @@ -77252,95 +77240,145 @@ void OpenGLComponent::shareWith (OpenGLContext* c) | |||
| if (contextToShareListsWith != c) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| deleteContext(); | |||
| 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 (isShowing() && getTopLevelComponent()->getPeer() != nullptr) | |||
| if (context == nullptr) | |||
| { | |||
| context = createContext(); | |||
| if (context != nullptr) | |||
| { | |||
| #if JUCE_LINUX | |||
| if (! useThread) | |||
| #endif | |||
| updateContextPosition(); | |||
| if (context->makeActive()) | |||
| { | |||
| newOpenGLContextCreated(); | |||
| context->makeInactive(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return context != nullptr && context->makeActive(); | |||
| } | |||
| void OpenGLComponent::makeCurrentContextInactive() | |||
| void OpenGLComponent::deleteContext() | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| context->makeInactive(); | |||
| } | |||
| { | |||
| if (context->makeActive()) | |||
| { | |||
| releaseOpenGLContext(); | |||
| context->makeInactive(); | |||
| } | |||
| bool OpenGLComponent::isActiveContext() const noexcept | |||
| { | |||
| return context != nullptr && context->isActive(); | |||
| context = nullptr; | |||
| } | |||
| needToDeleteContext = false; | |||
| } | |||
| void OpenGLComponent::swapBuffers() | |||
| void OpenGLComponent::updateContextPosition() | |||
| { | |||
| if (context != nullptr) | |||
| context->swapBuffers(); | |||
| needToUpdateViewport = true; | |||
| if (getWidth() > 0 && getHeight() > 0) | |||
| { | |||
| Component* const topComp = getTopLevelComponent(); | |||
| if (topComp->getPeer() != nullptr) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| context->updateWindowPosition (getScreenX() - topComp->getScreenX(), | |||
| getScreenY() - topComp->getScreenY(), | |||
| getWidth(), | |||
| getHeight(), | |||
| topComp->getHeight()); | |||
| } | |||
| } | |||
| } | |||
| void OpenGLComponent::setUsingDedicatedThread (bool useDedicatedThread) noexcept | |||
| void OpenGLComponent::stopBackgroundThread() | |||
| { | |||
| useThread = useDedicatedThread; | |||
| if (threadStarted) | |||
| { | |||
| stopRenderThread(); | |||
| threadStarted = false; | |||
| } | |||
| } | |||
| void OpenGLComponent::paint (Graphics&) | |||
| { | |||
| ComponentPeer* const peer = getPeer(); | |||
| if (useThread) | |||
| { | |||
| if (renderThread == nullptr) | |||
| renderThread = new OpenGLComponentRenderThread (*this); | |||
| if (! renderThread->isThreadRunning()) | |||
| if (peer != nullptr && isShowing()) | |||
| { | |||
| componentWatcher->handleUpdateNowIfNeeded(); // may still be shutting down as well | |||
| #if ! JUCE_LINUX | |||
| // Except for Linux, create the context first | |||
| const ScopedLock sl (contextLock); | |||
| if (makeCurrentContextActive()) // Make active just to create | |||
| makeCurrentContextInactive(); | |||
| updateContext(); | |||
| #endif | |||
| startRenderThread(); | |||
| if (! threadStarted) | |||
| { | |||
| threadStarted = true; | |||
| startRenderThread(); | |||
| } | |||
| } | |||
| // fall-through and update the masking region | |||
| } | |||
| else | |||
| { | |||
| if (renderThread != nullptr) | |||
| { | |||
| stopRendering(); | |||
| renderThread = nullptr; | |||
| } | |||
| updateContext(); | |||
| if (! renderAndSwapBuffers()) | |||
| return; | |||
| } | |||
| ComponentPeer* const peer = getPeer(); | |||
| if (peer != nullptr) | |||
| { | |||
| const Point<int> topLeft (getScreenPosition() - peer->getScreenPosition()); | |||
| @@ -77348,64 +77386,32 @@ void OpenGLComponent::paint (Graphics&) | |||
| } | |||
| } | |||
| void OpenGLComponent::startRenderThread() | |||
| { | |||
| // If this is overriden, user will provide a thread. The renderThread object will | |||
| // not be used | |||
| jassert (renderThread != nullptr); | |||
| renderThread->startThread (6); | |||
| } | |||
| void OpenGLComponent::stopRenderThread() | |||
| bool OpenGLComponent::renderAndSwapBuffers() | |||
| { | |||
| releaseOpenGLContext(); | |||
| const ScopedLock sl (contextLock); | |||
| #if JUCE_LINUX | |||
| deleteContext(); | |||
| #else | |||
| makeCurrentContextInactive(); | |||
| updateContext(); | |||
| #endif | |||
| componentWatcher->triggerAsyncUpdate(); | |||
| } | |||
| bool OpenGLComponent::renderAndSwapBuffers() | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| { | |||
| if (! makeCurrentContextActive()) | |||
| return false; | |||
| if (! makeCurrentContextActive()) | |||
| return false; | |||
| if (needToUpdateViewport) | |||
| { | |||
| needToUpdateViewport = false; | |||
| juce_glViewport (getWidth(), getHeight()); | |||
| } | |||
| if (needToUpdateViewport) | |||
| { | |||
| needToUpdateViewport = false; | |||
| juce_glViewport (getWidth(), getHeight()); | |||
| renderOpenGL(); | |||
| swapBuffers(); | |||
| } | |||
| renderOpenGL(); | |||
| swapBuffers(); | |||
| return true; | |||
| } | |||
| void OpenGLComponent::stopRendering() | |||
| { | |||
| componentWatcher->cancelPendingUpdate(); | |||
| if (renderThread != nullptr) | |||
| renderThread->stopThread (5000); | |||
| if (context != nullptr && makeCurrentContextActive()) | |||
| { | |||
| // On Linux, when threaded, context will have already been cleared | |||
| const ScopedLock sl (contextLock); | |||
| releaseOpenGLContext(); | |||
| deleteContext(); | |||
| } | |||
| } | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| Component::internalRepaint (x, y, w, h); | |||
| @@ -275158,7 +275164,7 @@ private: | |||
| OpenGLContext* OpenGLComponent::createContext() | |||
| { | |||
| ScopedPointer<WindowedGLContext> c (new WindowedGLContext (*this, preferredPixelFormat, | |||
| contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : 0)); | |||
| contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil)); | |||
| return (c->renderContext != nil) ? c.release() : nullptr; | |||
| } | |||
| @@ -281055,7 +281061,7 @@ private: | |||
| OpenGLContext* OpenGLComponent::createContext() | |||
| { | |||
| ScopedPointer<WindowedGLContext> c (new WindowedGLContext (*this, preferredPixelFormat, | |||
| contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : 0)); | |||
| contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil)); | |||
| return (c->renderContext != nil) ? c.release() : nullptr; | |||
| } | |||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 82 | |||
| #define JUCE_BUILDNUMBER 83 | |||
| /** Current Juce version number. | |||
| @@ -64090,8 +64090,13 @@ public: | |||
| #endif | |||
| }; | |||
| /** Creates an OpenGLComponent. */ | |||
| OpenGLComponent (OpenGLType type = openGLDefault); | |||
| /** Creates an OpenGLComponent. | |||
| If useBackgroundThread is true, the component will launch a background thread | |||
| to do the rendering. If false, then renderOpenGL() will be called as part of the | |||
| normal paint() method. | |||
| */ | |||
| OpenGLComponent (OpenGLType type = openGLDefault, | |||
| bool useBackgroundThread = false); | |||
| /** Destructor. */ | |||
| ~OpenGLComponent(); | |||
| @@ -64126,14 +64131,9 @@ public: | |||
| /** Flips the openGL buffers over. */ | |||
| void swapBuffers(); | |||
| /** Indicates whether the component should perform its rendering on a background thread. | |||
| By default, this is set to false, and the renderOpenGL() callback happens on the main | |||
| UI thread, in response to a repaint. If set to true, then the component will create | |||
| a background thread which it uses to repeatedly call renderOpenGL(). | |||
| /** Returns true if the component is performing the rendering on a background thread. | |||
| This property is specified in the constructor. | |||
| */ | |||
| void setUsingDedicatedThread (bool useDedicatedThread) noexcept; | |||
| /** Returns true if the component is performing the rendering on a background thread. */ | |||
| bool isUsingDedicatedThread() const noexcept { return useThread; } | |||
| /** This replaces the normal paint() callback - use it to draw your openGL stuff. | |||
| @@ -64211,7 +64211,7 @@ public: | |||
| */ | |||
| void makeCurrentContextInactive(); | |||
| /** Returns true if this component is the active openGL context for the | |||
| /** Returns true if this component's context is the active openGL context for the | |||
| current thread. | |||
| @see OpenGLContext::isActive | |||
| @@ -64219,12 +64219,7 @@ public: | |||
| bool isActiveContext() const noexcept; | |||
| /** Calls the rendering callback, and swaps the buffers afterwards. | |||
| This is called automatically by paint() when the component needs to be rendered. | |||
| It can be overridden if you need to decouple the rendering from the paint callback | |||
| and render with a custom thread. | |||
| Returns true if the operation succeeded. | |||
| */ | |||
| virtual bool renderAndSwapBuffers(); | |||
| @@ -64238,6 +64233,12 @@ public: | |||
| */ | |||
| CriticalSection& getContextLock() noexcept { return contextLock; } | |||
| /** Delete the context. | |||
| You should only need to call this if you've written a custom thread - if so, make | |||
| sure that your thread calls this before it terminates. | |||
| */ | |||
| void deleteContext(); | |||
| /** Returns the native handle of an embedded heavyweight window, if there is one. | |||
| E.g. On windows, this will return the HWND of the sub-window containing | |||
| @@ -64245,10 +64246,6 @@ public: | |||
| */ | |||
| void* getNativeWindowHandle() const; | |||
| /** Delete the context. | |||
| This can be called back on the same thread that created the context. */ | |||
| void deleteContext(); | |||
| protected: | |||
| /** Kicks off a thread to start rendering. | |||
| The default implementation creates and manages an internal thread that tries | |||
| @@ -64282,12 +64279,15 @@ private: | |||
| CriticalSection contextLock; | |||
| OpenGLPixelFormat preferredPixelFormat; | |||
| bool needToUpdateViewport, useThread; | |||
| bool needToUpdateViewport, needToDeleteContext, threadStarted; | |||
| const bool useThread; | |||
| OpenGLContext* createContext(); | |||
| void updateContext(); | |||
| void updateContextPosition(); | |||
| void stopBackgroundThread(); | |||
| void recreateContextAsync(); | |||
| void internalRepaint (int x, int y, int w, int h); | |||
| void stopRendering(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | |||
| }; | |||
| @@ -210,22 +210,9 @@ namespace | |||
| LRESULT CALLBACK mouseWheelHookCallback (int nCode, WPARAM wParam, LPARAM lParam) | |||
| { | |||
| #ifndef WM_MOUSEWHEEL | |||
| #define WM_MOUSEWHEEL 0x20a | |||
| struct MSLLHOOKSTRUCT | |||
| { | |||
| POINT pt; | |||
| DWORD mouseData; | |||
| DWORD flags; | |||
| DWORD time; | |||
| ULONG_PTR dwExtraInfo; | |||
| }; | |||
| #endif | |||
| if (nCode >= 0 && wParam == WM_MOUSEWHEEL) | |||
| { | |||
| const MSLLHOOKSTRUCT& hs = *(MSLLHOOKSTRUCT*) lParam; | |||
| const MOUSEHOOKSTRUCTEX& hs = *(MOUSEHOOKSTRUCTEX*) lParam; | |||
| Component* const comp = Desktop::getInstance().findComponentAt (Point<int> (hs.pt.x, | |||
| hs.pt.y)); | |||
| @@ -240,7 +227,7 @@ namespace | |||
| void registerMouseWheelHook() | |||
| { | |||
| if (mouseHookUsers++ == 0) | |||
| mouseWheelHook = SetWindowsHookEx (7 /*WH_MOUSE*/, mouseWheelHookCallback, | |||
| mouseWheelHook = SetWindowsHookEx (WH_MOUSE, mouseWheelHookCallback, | |||
| (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), | |||
| GetCurrentThreadId()); | |||
| } | |||
| @@ -72,11 +72,10 @@ namespace AudioUnitFormatHelpers | |||
| const String osTypeToString (OSType type) | |||
| { | |||
| char s[4]; | |||
| s[0] = (char) (((uint32) type) >> 24); | |||
| s[1] = (char) (((uint32) type) >> 16); | |||
| s[2] = (char) (((uint32) type) >> 8); | |||
| s[3] = (char) ((uint32) type); | |||
| const juce_wchar s[4] = { (juce_wchar) (((uint32) type) >> 24), | |||
| (juce_wchar) (((uint32) type) >> 16), | |||
| (juce_wchar) (((uint32) type) >> 8), | |||
| (juce_wchar) ((uint32) type) }; | |||
| return String (s, 4); | |||
| } | |||
| @@ -87,7 +86,7 @@ namespace AudioUnitFormatHelpers | |||
| return (((OSType) (unsigned char) s[0]) << 24) | |||
| | (((OSType) (unsigned char) s[1]) << 16) | |||
| | (((OSType) (unsigned char) s[2]) << 8) | |||
| | ((OSType) (unsigned char) s[3]); | |||
| | ((OSType) (unsigned char) s[3]); | |||
| } | |||
| static const char* auIdentifierPrefix = "AudioUnit:"; | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 82 | |||
| #define JUCE_BUILDNUMBER 83 | |||
| /** Current Juce version number. | |||
| @@ -131,10 +131,44 @@ OpenGLContext* OpenGLContext::getCurrentContext() | |||
| } | |||
| //============================================================================== | |||
| class OpenGLComponent::OpenGLComponentRenderThread : public Thread | |||
| 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_) | |||
| @@ -154,64 +188,46 @@ public: | |||
| Thread::sleep (jmax (1, 20 - elapsed)); | |||
| } | |||
| owner.stopRenderThread(); | |||
| #if JUCE_LINUX | |||
| owner.deleteContext(); | |||
| #endif | |||
| } | |||
| //============================================================================== | |||
| private: | |||
| OpenGLComponent& owner; | |||
| JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread); | |||
| }; | |||
| //============================================================================== | |||
| class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher, | |||
| public AsyncUpdater | |||
| void OpenGLComponent::startRenderThread() | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| OpenGLComponentWatcher (OpenGLComponent* const owner_) | |||
| : ComponentMovementWatcher (owner_), | |||
| owner (owner_) | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | |||
| { | |||
| owner->updateContextPosition(); | |||
| } | |||
| void componentPeerChanged() | |||
| { | |||
| owner->stopRendering(); | |||
| } | |||
| if (renderThread == nullptr) | |||
| renderThread = new OpenGLComponentRenderThread (*this); | |||
| void componentVisibilityChanged() | |||
| { | |||
| if (! owner->isShowing()) | |||
| owner->stopRendering(); | |||
| } | |||
| renderThread->startThread (6); | |||
| } | |||
| void handleAsyncUpdate() | |||
| void OpenGLComponent::stopRenderThread() | |||
| { | |||
| if (renderThread != nullptr) | |||
| { | |||
| owner->stopRendering(); | |||
| renderThread->stopThread (5000); | |||
| renderThread = nullptr; | |||
| } | |||
| //============================================================================== | |||
| private: | |||
| OpenGLComponent* const owner; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); | |||
| }; | |||
| #if ! JUCE_LINUX | |||
| deleteContext(); | |||
| #endif | |||
| } | |||
| //============================================================================== | |||
| OpenGLComponent::OpenGLComponent (const OpenGLType type_) | |||
| OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread) | |||
| : type (type_), | |||
| contextToShareListsWith (nullptr), | |||
| needToUpdateViewport (true), | |||
| useThread (false) | |||
| needToDeleteContext (false), | |||
| threadStarted (false), | |||
| useThread (useBackgroundThread) | |||
| { | |||
| setOpaque (true); | |||
| componentWatcher = new OpenGLComponentWatcher (this); | |||
| @@ -219,39 +235,10 @@ OpenGLComponent::OpenGLComponent (const OpenGLType type_) | |||
| OpenGLComponent::~OpenGLComponent() | |||
| { | |||
| stopRendering(); | |||
| renderThread = nullptr; | |||
| stopBackgroundThread(); | |||
| componentWatcher = nullptr; | |||
| } | |||
| void OpenGLComponent::deleteContext() | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| context = nullptr; | |||
| } | |||
| 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 (getScreenX() - topComp->getScreenX(), | |||
| getScreenY() - topComp->getScreenY(), | |||
| getWidth(), | |||
| getHeight(), | |||
| topComp->getHeight()); | |||
| } | |||
| } | |||
| } | |||
| const OpenGLPixelFormat OpenGLComponent::getPixelFormat() const | |||
| { | |||
| OpenGLPixelFormat pf; | |||
| @@ -268,8 +255,8 @@ void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) | |||
| if (! (preferredPixelFormat == formatToUse)) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| deleteContext(); | |||
| preferredPixelFormat = formatToUse; | |||
| recreateContextAsync(); | |||
| } | |||
| } | |||
| @@ -278,95 +265,145 @@ void OpenGLComponent::shareWith (OpenGLContext* c) | |||
| if (contextToShareListsWith != c) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| deleteContext(); | |||
| 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 (isShowing() && getTopLevelComponent()->getPeer() != nullptr) | |||
| if (context == nullptr) | |||
| { | |||
| context = createContext(); | |||
| if (context != nullptr) | |||
| { | |||
| #if JUCE_LINUX | |||
| if (! useThread) | |||
| #endif | |||
| updateContextPosition(); | |||
| if (context->makeActive()) | |||
| { | |||
| newOpenGLContextCreated(); | |||
| context->makeInactive(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return context != nullptr && context->makeActive(); | |||
| } | |||
| void OpenGLComponent::makeCurrentContextInactive() | |||
| void OpenGLComponent::deleteContext() | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| context->makeInactive(); | |||
| } | |||
| { | |||
| if (context->makeActive()) | |||
| { | |||
| releaseOpenGLContext(); | |||
| context->makeInactive(); | |||
| } | |||
| bool OpenGLComponent::isActiveContext() const noexcept | |||
| { | |||
| return context != nullptr && context->isActive(); | |||
| context = nullptr; | |||
| } | |||
| needToDeleteContext = false; | |||
| } | |||
| void OpenGLComponent::swapBuffers() | |||
| void OpenGLComponent::updateContextPosition() | |||
| { | |||
| if (context != nullptr) | |||
| context->swapBuffers(); | |||
| needToUpdateViewport = true; | |||
| if (getWidth() > 0 && getHeight() > 0) | |||
| { | |||
| Component* const topComp = getTopLevelComponent(); | |||
| if (topComp->getPeer() != nullptr) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| context->updateWindowPosition (getScreenX() - topComp->getScreenX(), | |||
| getScreenY() - topComp->getScreenY(), | |||
| getWidth(), | |||
| getHeight(), | |||
| topComp->getHeight()); | |||
| } | |||
| } | |||
| } | |||
| void OpenGLComponent::setUsingDedicatedThread (bool useDedicatedThread) noexcept | |||
| void OpenGLComponent::stopBackgroundThread() | |||
| { | |||
| useThread = useDedicatedThread; | |||
| if (threadStarted) | |||
| { | |||
| stopRenderThread(); | |||
| threadStarted = false; | |||
| } | |||
| } | |||
| void OpenGLComponent::paint (Graphics&) | |||
| { | |||
| ComponentPeer* const peer = getPeer(); | |||
| if (useThread) | |||
| { | |||
| if (renderThread == nullptr) | |||
| renderThread = new OpenGLComponentRenderThread (*this); | |||
| if (! renderThread->isThreadRunning()) | |||
| if (peer != nullptr && isShowing()) | |||
| { | |||
| componentWatcher->handleUpdateNowIfNeeded(); // may still be shutting down as well | |||
| #if ! JUCE_LINUX | |||
| // Except for Linux, create the context first | |||
| const ScopedLock sl (contextLock); | |||
| if (makeCurrentContextActive()) // Make active just to create | |||
| makeCurrentContextInactive(); | |||
| updateContext(); | |||
| #endif | |||
| startRenderThread(); | |||
| if (! threadStarted) | |||
| { | |||
| threadStarted = true; | |||
| startRenderThread(); | |||
| } | |||
| } | |||
| // fall-through and update the masking region | |||
| } | |||
| else | |||
| { | |||
| if (renderThread != nullptr) | |||
| { | |||
| stopRendering(); | |||
| renderThread = nullptr; | |||
| } | |||
| updateContext(); | |||
| if (! renderAndSwapBuffers()) | |||
| return; | |||
| } | |||
| ComponentPeer* const peer = getPeer(); | |||
| if (peer != nullptr) | |||
| { | |||
| const Point<int> topLeft (getScreenPosition() - peer->getScreenPosition()); | |||
| @@ -374,64 +411,32 @@ void OpenGLComponent::paint (Graphics&) | |||
| } | |||
| } | |||
| void OpenGLComponent::startRenderThread() | |||
| { | |||
| // If this is overriden, user will provide a thread. The renderThread object will | |||
| // not be used | |||
| jassert (renderThread != nullptr); | |||
| renderThread->startThread (6); | |||
| } | |||
| void OpenGLComponent::stopRenderThread() | |||
| bool OpenGLComponent::renderAndSwapBuffers() | |||
| { | |||
| releaseOpenGLContext(); | |||
| const ScopedLock sl (contextLock); | |||
| #if JUCE_LINUX | |||
| deleteContext(); | |||
| #else | |||
| makeCurrentContextInactive(); | |||
| updateContext(); | |||
| #endif | |||
| componentWatcher->triggerAsyncUpdate(); | |||
| } | |||
| bool OpenGLComponent::renderAndSwapBuffers() | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| { | |||
| if (! makeCurrentContextActive()) | |||
| return false; | |||
| if (! makeCurrentContextActive()) | |||
| return false; | |||
| if (needToUpdateViewport) | |||
| { | |||
| needToUpdateViewport = false; | |||
| juce_glViewport (getWidth(), getHeight()); | |||
| } | |||
| if (needToUpdateViewport) | |||
| { | |||
| needToUpdateViewport = false; | |||
| juce_glViewport (getWidth(), getHeight()); | |||
| renderOpenGL(); | |||
| swapBuffers(); | |||
| } | |||
| renderOpenGL(); | |||
| swapBuffers(); | |||
| return true; | |||
| } | |||
| void OpenGLComponent::stopRendering() | |||
| { | |||
| componentWatcher->cancelPendingUpdate(); | |||
| if (renderThread != nullptr) | |||
| renderThread->stopThread (5000); | |||
| if (context != nullptr && makeCurrentContextActive()) | |||
| { | |||
| // On Linux, when threaded, context will have already been cleared | |||
| const ScopedLock sl (contextLock); | |||
| releaseOpenGLContext(); | |||
| deleteContext(); | |||
| } | |||
| } | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| Component::internalRepaint (x, y, w, h); | |||
| @@ -198,8 +198,13 @@ public: | |||
| #endif | |||
| }; | |||
| /** Creates an OpenGLComponent. */ | |||
| OpenGLComponent (OpenGLType type = openGLDefault); | |||
| /** Creates an OpenGLComponent. | |||
| If useBackgroundThread is true, the component will launch a background thread | |||
| to do the rendering. If false, then renderOpenGL() will be called as part of the | |||
| normal paint() method. | |||
| */ | |||
| OpenGLComponent (OpenGLType type = openGLDefault, | |||
| bool useBackgroundThread = false); | |||
| /** Destructor. */ | |||
| ~OpenGLComponent(); | |||
| @@ -237,14 +242,9 @@ public: | |||
| /** Flips the openGL buffers over. */ | |||
| void swapBuffers(); | |||
| /** Indicates whether the component should perform its rendering on a background thread. | |||
| By default, this is set to false, and the renderOpenGL() callback happens on the main | |||
| UI thread, in response to a repaint. If set to true, then the component will create | |||
| a background thread which it uses to repeatedly call renderOpenGL(). | |||
| /** Returns true if the component is performing the rendering on a background thread. | |||
| This property is specified in the constructor. | |||
| */ | |||
| void setUsingDedicatedThread (bool useDedicatedThread) noexcept; | |||
| /** Returns true if the component is performing the rendering on a background thread. */ | |||
| bool isUsingDedicatedThread() const noexcept { return useThread; } | |||
| /** This replaces the normal paint() callback - use it to draw your openGL stuff. | |||
| @@ -323,7 +323,7 @@ public: | |||
| */ | |||
| void makeCurrentContextInactive(); | |||
| /** Returns true if this component is the active openGL context for the | |||
| /** Returns true if this component's context is the active openGL context for the | |||
| current thread. | |||
| @see OpenGLContext::isActive | |||
| @@ -333,12 +333,7 @@ public: | |||
| //============================================================================== | |||
| /** Calls the rendering callback, and swaps the buffers afterwards. | |||
| This is called automatically by paint() when the component needs to be rendered. | |||
| It can be overridden if you need to decouple the rendering from the paint callback | |||
| and render with a custom thread. | |||
| Returns true if the operation succeeded. | |||
| */ | |||
| virtual bool renderAndSwapBuffers(); | |||
| @@ -352,6 +347,12 @@ public: | |||
| */ | |||
| CriticalSection& getContextLock() noexcept { return contextLock; } | |||
| /** Delete the context. | |||
| You should only need to call this if you've written a custom thread - if so, make | |||
| sure that your thread calls this before it terminates. | |||
| */ | |||
| void deleteContext(); | |||
| //============================================================================== | |||
| /** Returns the native handle of an embedded heavyweight window, if there is one. | |||
| @@ -360,10 +361,6 @@ public: | |||
| */ | |||
| void* getNativeWindowHandle() const; | |||
| /** Delete the context. | |||
| This can be called back on the same thread that created the context. */ | |||
| void deleteContext(); | |||
| protected: | |||
| /** Kicks off a thread to start rendering. | |||
| The default implementation creates and manages an internal thread that tries | |||
| @@ -398,12 +395,15 @@ private: | |||
| CriticalSection contextLock; | |||
| OpenGLPixelFormat preferredPixelFormat; | |||
| bool needToUpdateViewport, useThread; | |||
| bool needToUpdateViewport, needToDeleteContext, threadStarted; | |||
| const bool useThread; | |||
| OpenGLContext* createContext(); | |||
| void updateContext(); | |||
| void updateContextPosition(); | |||
| void stopBackgroundThread(); | |||
| void recreateContextAsync(); | |||
| void internalRepaint (int x, int y, int w, int h); | |||
| void stopRendering(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | |||
| }; | |||
| @@ -271,7 +271,7 @@ private: | |||
| OpenGLContext* OpenGLComponent::createContext() | |||
| { | |||
| ScopedPointer<WindowedGLContext> c (new WindowedGLContext (*this, preferredPixelFormat, | |||
| contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : 0)); | |||
| contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil)); | |||
| return (c->renderContext != nil) ? c.release() : nullptr; | |||
| } | |||