diff --git a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp index 50394bc16a..fe61ad2074 100644 --- a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp +++ b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp @@ -60,6 +60,7 @@ public: openGLContext.setRenderer (this); openGLContext.setComponentPaintingEnabled (true); + openGLContext.setContinuousRepainting (true); openGLContext.attachTo (*this); startTimer (1000 / 30); @@ -197,7 +198,6 @@ public: { rotation += (float) speedSlider.getValue(); textScrollPos += 1.4f; - openGLContext.triggerRepaint(); } private: diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp index 12f5b76759..1f00dc2072 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp @@ -315,6 +315,8 @@ public: { if (! renderFrame()) wait (5); // failed to render, so avoid a tight fail-loop. + else if (! context.continuousRepaint) + wait (-1); } shutdownOnThread(); @@ -529,7 +531,8 @@ private: //============================================================================== OpenGLContext::OpenGLContext() : nativeContext (nullptr), renderer (nullptr), currentRenderScale (1.0), - contextToShareWith (nullptr), renderComponents (true), useMultisampling (false) + contextToShareWith (nullptr), renderComponents (true), + useMultisampling (false), continuousRepaint (false) { } @@ -556,6 +559,11 @@ void OpenGLContext::setComponentPaintingEnabled (bool shouldPaintComponent) noex renderComponents = shouldPaintComponent; } +void OpenGLContext::setContinuousRepainting (bool shouldContinuouslyRepaint) noexcept +{ + continuousRepaint = shouldContinuouslyRepaint; +} + void OpenGLContext::setPixelFormat (const OpenGLPixelFormat& preferredPixelFormat) noexcept { // This method must not be called when the context has already been attached! @@ -623,7 +631,7 @@ bool OpenGLContext::makeActive() const noexcept if (nativeContext != nullptr && nativeContext->makeActive()) { - current = const_cast (this); + current = const_cast (this); return true; } diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.h b/modules/juce_opengl/opengl/juce_OpenGLContext.h index 5ca6ba3939..e0abbb44b5 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLContext.h +++ b/modules/juce_opengl/opengl/juce_OpenGLContext.h @@ -58,23 +58,36 @@ public: this method with a null pointer. Note: This must be called BEFORE attaching your context to a target component! */ - void setRenderer (OpenGLRenderer* rendererToUse) noexcept; + void setRenderer (OpenGLRenderer*) noexcept; - /** Enables or disables the use of the GL context to perform 2D rendering - of the component to which it is attached. - If this is false, then only your OpenGLRenderer will be used to perform - any rendering. If true, then each time your target's paint() method needs - to be called, an OpenGLGraphicsContext will be used to render it, (after - calling your OpenGLRenderer if there is one). + /** Attaches the context to a target component. - By default this is set to true. If you're not using any paint() method functionality - and are doing all your rendering in an OpenGLRenderer, you should disable it - to improve performance. + If the component is not fully visible, this call will wait until the component + is shown before actually creating a native context for it. - Note: This must be called BEFORE attaching your context to a target component! + When a native context is created, a thread is started, and will be used to call + the OpenGLRenderer methods. The context will be floated above the target component, + and when the target moves, it will track it. If the component is hidden/shown, the + context may be deleted and re-created. */ - void setComponentPaintingEnabled (bool shouldPaintComponent) noexcept; + void attachTo (Component&); + /** Detaches the context from its target component and deletes any native resources. + If the context has not been attached, this will do nothing. Otherwise, it will block + until the context and its thread have been cleaned up. + */ + void detach(); + + /** Returns true if the context is attached to a component and is on-screen. + Note that if you call attachTo() for a non-visible component, this method will + return false until the component is made visible. + */ + bool isAttached() const noexcept; + + /** Returns the component to which this context is currently attached, or nullptr. */ + Component* getTargetComponent() const noexcept; + + //============================================================================== /** Sets the pixel format which you'd like to use for the target GL surface. Note: This must be called BEFORE attaching your context to a target component! */ @@ -93,53 +106,36 @@ public: */ void setMultisamplingEnabled (bool) noexcept; - //============================================================================== - /** Attaches the context to a target component. - - If the component is not fully visible, this call will wait until the component - is shown before actually creating a native context for it. - - When a native context is created, a thread is started, and will be used to call - the OpenGLRenderer methods. The context will be floated above the target component, - and when the target moves, it will track it. If the component is hidden/shown, the - context may be deleted and re-created. - */ - void attachTo (Component& component); - - /** Detaches the context from its target component and deletes any native resources. - If the context has not been attached, this will do nothing. Otherwise, it will block - until the context and its thread have been cleaned up. - */ - void detach(); - - /** Returns true if the context is attached to a component and is on-screen. - Note that if you call attachTo() for a non-visible component, this method will - return false until the component is made visible. - */ - bool isAttached() const noexcept; - - /** Returns the component to which this context is currently attached, or nullptr. */ - Component* getTargetComponent() const noexcept; - - /** Returns the context that's currently in active use by the calling thread, or - nullptr if no context is active. - */ - static OpenGLContext* getCurrentContext(); - - /** Asynchronously causes a repaint to be made. */ - void triggerRepaint(); - - //============================================================================== - /** If this context is backed by a frame buffer, this returns its ID number, - or 0 if the context does not use a framebuffer. - */ - unsigned int getFrameBufferID() const noexcept; - /** Returns true if shaders can be used in this context. */ bool areShadersAvailable() const; - /** This structure holds a set of dynamically loaded GL functions for use on this context. */ - OpenGLExtensionFunctions extensions; + /** Enables or disables the use of the GL context to perform 2D rendering + of the component to which it is attached. + If this is false, then only your OpenGLRenderer will be used to perform + any rendering. If true, then each time your target's paint() method needs + to be called, an OpenGLGraphicsContext will be used to render it, (after + calling your OpenGLRenderer if there is one). + + By default this is set to true. If you're not using any paint() method functionality + and are doing all your rendering in an OpenGLRenderer, you should disable it + to improve performance. + + Note: This must be called BEFORE attaching your context to a target component! + */ + void setComponentPaintingEnabled (bool shouldPaintComponent) noexcept; + + /** Enables or disables continuous repainting. + If set to true, the context will run a loop, re-rendering itself without waiting + for triggerRepaint() to be called, at a frequency determined by the swap interval + (see setSwapInterval). If false, then after each render callback, it will wait for + another call to triggerRepaint() before rendering again. + This is disabled by default. + @see setSwapInterval + */ + void setContinuousRepainting (bool shouldContinuouslyRepaint) noexcept; + + /** Asynchronously causes a repaint to be made. */ + void triggerRepaint(); //============================================================================== /** This retrieves an object that was previously stored with setAssociatedObject(). @@ -175,6 +171,11 @@ public: */ static void deactivateCurrentContext(); + /** Returns the context that's currently in active use by the calling thread, or + nullptr if no context is active. + */ + static OpenGLContext* getCurrentContext(); + //============================================================================== /** Swaps the buffers (if the context can do this). There's normally no need to call this directly - the buffers will be swapped @@ -192,6 +193,8 @@ public: Returns true if it sets the value successfully - some platforms won't support this setting. + + @see setContinuousRepainting */ bool setSwapInterval (int numFramesPerSwap); @@ -211,6 +214,11 @@ public: double getRenderingScale() const noexcept { return currentRenderScale; } //============================================================================== + /** If this context is backed by a frame buffer, this returns its ID number, + or 0 if the context does not use a framebuffer. + */ + unsigned int getFrameBufferID() const noexcept; + /** Returns an OS-dependent handle to some kind of underlting OS-provided GL context. The exact type of the value returned will depend on the OS and may change @@ -219,6 +227,9 @@ public: */ void* getRawContext() const noexcept; + /** This structure holds a set of dynamically loaded GL functions for use on this context. */ + OpenGLExtensionFunctions extensions; + //============================================================================== /** Draws the currently selected texture into this context at its original size. @@ -253,7 +264,7 @@ private: ScopedPointer attachment; OpenGLPixelFormat pixelFormat; void* contextToShareWith; - bool renderComponents, useMultisampling; + bool renderComponents, useMultisampling, continuousRepaint; CachedImage* getCachedImage() const noexcept; diff --git a/modules/juce_opengl/opengl/juce_OpenGLRenderer.h b/modules/juce_opengl/opengl/juce_OpenGLRenderer.h index 3ad9087186..8b9503c7d8 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLRenderer.h +++ b/modules/juce_opengl/opengl/juce_OpenGLRenderer.h @@ -48,8 +48,10 @@ public: virtual void newOpenGLContextCreated() = 0; /** Called when you should render the next openGL frame. - Note that this callback will be made on a background thread, so make sure - that your implementation is thread-safe. + Note that this callback will be made on a background thread, not the message + thread, so make sure that your implementation is thread-safe. + For information about how to trigger a render callback, see + OpenGLContext::triggerRepaint() and OpenGLContext::setContinuousRepainting(). */ virtual void renderOpenGL() = 0;