| @@ -157,8 +157,9 @@ public: | |||
| void drawBackground2DStuff() | |||
| { | |||
| OpenGLGraphicsContext glRenderer (*this); // Create an OpenGLGraphicsContext that will draw into this GL window.. | |||
| Graphics g (&glRenderer); // ..and then wrap it in a normal Graphics object so we can draw with it. | |||
| // Create an OpenGLGraphicsContext that will draw into this GL window.. | |||
| ScopedPointer<LowLevelGraphicsContext> glRenderer (createOpenGLGraphicsContext (*this)); | |||
| Graphics g (glRenderer); | |||
| // This stuff just creates a spinning star shape and fills it.. | |||
| Path p; | |||
| @@ -322,7 +322,7 @@ protected: | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void paint (Graphics& g); | |||
| /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */ | |||
| /** (if overriding this, make sure you call ResizableWindow::moved() in your subclass) */ | |||
| void moved(); | |||
| /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */ | |||
| void resized(); | |||
| @@ -121,6 +121,26 @@ public: | |||
| return frameBuffer; | |||
| } | |||
| void clearRegionInFrameBuffer (const RectangleList& list) | |||
| { | |||
| glClearColor (0, 0, 0, 0); | |||
| glEnable (GL_SCISSOR_TEST); | |||
| const GLuint previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget(); | |||
| frameBuffer.makeCurrentRenderingTarget(); | |||
| for (RectangleList::Iterator i (list); i.next();) | |||
| { | |||
| const Rectangle<int>& r = *i.getRectangle(); | |||
| glScissor (r.getX(), owner.getHeight() - r.getBottom(), r.getWidth(), r.getHeight()); | |||
| glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||
| } | |||
| glDisable (GL_SCISSOR_TEST); | |||
| owner.getCurrentContext()->extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| } | |||
| RectangleList validArea; | |||
| private: | |||
| @@ -152,7 +172,9 @@ public: | |||
| void componentVisibilityChanged() | |||
| { | |||
| if (! owner.isShowing()) | |||
| if (owner.isShowing()) | |||
| owner.triggerRepaint(); | |||
| else | |||
| owner.stopRenderThread(); | |||
| } | |||
| @@ -172,34 +194,54 @@ public: | |||
| { | |||
| } | |||
| void run() | |||
| virtual void initialise() | |||
| { | |||
| #if JUCE_LINUX | |||
| { | |||
| MessageManagerLock mml (this); | |||
| if (! mml.lockWasGained()) | |||
| return; | |||
| MessageManagerLock mml (this); | |||
| if (mml.lockWasGained()) | |||
| { | |||
| owner.updateContext(); | |||
| owner.updateContextPosition(); | |||
| } | |||
| #endif | |||
| } | |||
| virtual void shutdown() | |||
| { | |||
| #if JUCE_LINUX | |||
| owner.deleteContext(); | |||
| #endif | |||
| } | |||
| virtual bool renderFrame() | |||
| { | |||
| return owner.performRender(); | |||
| } | |||
| virtual void waitForNextFrame (const uint32 frameRenderStartTime) | |||
| { | |||
| const int defaultFPS = 60; | |||
| const int elapsed = (int) (Time::getMillisecondCounter() - frameRenderStartTime); | |||
| Thread::sleep (jmax (1, (1000 / defaultFPS) - elapsed)); | |||
| } | |||
| void run() | |||
| { | |||
| initialise(); | |||
| while (! threadShouldExit()) | |||
| { | |||
| const uint32 startOfRendering = Time::getMillisecondCounter(); | |||
| const uint32 frameRenderStartTime = Time::getMillisecondCounter(); | |||
| if (! owner.performRender()) | |||
| if (! renderFrame()) | |||
| break; | |||
| const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering); | |||
| Thread::sleep (jmax (1, (1000 / 60) - elapsed)); | |||
| waitForNextFrame (frameRenderStartTime); | |||
| } | |||
| #if JUCE_LINUX | |||
| owner.deleteContext(); | |||
| #endif | |||
| shutdown(); | |||
| } | |||
| private: | |||
| @@ -458,17 +500,14 @@ bool OpenGLComponent::performRender() | |||
| { | |||
| jassert (getCurrentContext() != nullptr); | |||
| cachedImage->clearRegionInFrameBuffer (invalid); | |||
| { | |||
| OpenGLGraphicsContext g (*getCurrentContext(), frameBuffer); | |||
| ScopedPointer<LowLevelGraphicsContext> g (createOpenGLGraphicsContext (*getCurrentContext(), frameBuffer)); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| g.clipToRectangleList (invalid); | |||
| g.setFill (Colours::transparentBlack); | |||
| g.fillRect (bounds, true); | |||
| g.setFill (Colours::black); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| paintSelf (g); | |||
| g->clipToRectangleList (invalid); | |||
| paintSelf (*g); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| } | |||
| @@ -484,7 +523,7 @@ bool OpenGLComponent::performRender() | |||
| glBindTexture (GL_TEXTURE_2D, frameBuffer.getTextureID()); | |||
| jassert (bounds.getPosition() == Point<int>()); | |||
| context->copyTexture (bounds, bounds); | |||
| context->copyTexture (bounds, bounds, context->getWidth(), context->getHeight()); | |||
| glBindTexture (GL_TEXTURE_2D, 0); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| } | |||
| @@ -495,9 +534,9 @@ bool OpenGLComponent::performRender() | |||
| return true; | |||
| } | |||
| void OpenGLComponent::paintSelf (OpenGLGraphicsContext& glRenderer) | |||
| void OpenGLComponent::paintSelf (LowLevelGraphicsContext& context) | |||
| { | |||
| Graphics g (&glRenderer); | |||
| Graphics g (&context); | |||
| #if JUCE_ENABLE_REPAINT_DEBUGGING | |||
| g.saveState(); | |||
| @@ -289,7 +289,7 @@ private: | |||
| void updateEmbeddedPosition (const Rectangle<int>&); | |||
| void startRenderThread(); | |||
| bool performRender(); | |||
| void paintSelf (OpenGLGraphicsContext&); | |||
| void paintSelf (LowLevelGraphicsContext&); | |||
| int renderAndSwapBuffers(); // (This method has been deprecated) | |||
| @@ -127,7 +127,8 @@ bool OpenGLContext::areShadersAvailable() const | |||
| } | |||
| void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea, | |||
| const Rectangle<int>& anchorPosAndTextureSize) | |||
| const Rectangle<int>& anchorPosAndTextureSize, | |||
| int contextWidth, int contextHeight) | |||
| { | |||
| glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); | |||
| glEnable (GL_BLEND); | |||
| @@ -138,9 +139,7 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea, | |||
| struct OverlayShaderProgram : public ReferenceCountedObject | |||
| { | |||
| OverlayShaderProgram (OpenGLContext& context) | |||
| : program (context), | |||
| builder (program), | |||
| params (program) | |||
| : program (context), builder (program), params (program) | |||
| {} | |||
| static const OverlayShaderProgram& select (OpenGLContext& context) | |||
| @@ -225,7 +224,7 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea, | |||
| const GLshort vertices[] = { left, bottom, right, bottom, left, top, right, top }; | |||
| const OverlayShaderProgram& program = OverlayShaderProgram::select (*this); | |||
| program.params.set ((float) getWidth(), (float) getHeight(), anchorPosAndTextureSize.toFloat()); | |||
| program.params.set ((float) contextWidth, (float) contextHeight, anchorPosAndTextureSize.toFloat()); | |||
| extensions.glVertexAttribPointer (program.params.positionAttribute.attributeID, 2, GL_SHORT, GL_FALSE, 4, vertices); | |||
| extensions.glEnableVertexAttribArray (program.params.positionAttribute.attributeID); | |||
| @@ -241,26 +240,29 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea, | |||
| #if JUCE_USE_OPENGL_FIXED_FUNCTION | |||
| { | |||
| (void) anchorPosAndTextureSize; // xxx need to scissor | |||
| const GLshort left = (GLshort) targetClipArea.getX(); | |||
| const GLshort right = (GLshort) targetClipArea.getRight(); | |||
| const GLshort top = (GLshort) (getHeight() - targetClipArea.getY()); | |||
| const GLshort bottom = (GLshort) (getHeight() - targetClipArea.getBottom()); | |||
| const GLshort vertices[] = { left, bottom, right, bottom, left, top, right, top }; | |||
| OpenGLHelpers::prepareFor2D (getWidth(), getHeight()); | |||
| glEnable (GL_SCISSOR_TEST); | |||
| glScissor (targetClipArea.getX(), contextHeight - targetClipArea.getBottom(), | |||
| targetClipArea.getWidth(), targetClipArea.getHeight()); | |||
| glColor4f (1.0f, 1.0f, 1.0f, 1.0f); | |||
| glDisableClientState (GL_COLOR_ARRAY); | |||
| glDisableClientState (GL_NORMAL_ARRAY); | |||
| glEnableClientState (GL_VERTEX_ARRAY); | |||
| glEnableClientState (GL_TEXTURE_COORD_ARRAY); | |||
| OpenGLHelpers::prepareFor2D (contextWidth, contextHeight); | |||
| const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f }; | |||
| glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); | |||
| const GLshort left = (GLshort) anchorPosAndTextureSize.getX(); | |||
| const GLshort right = (GLshort) anchorPosAndTextureSize.getRight(); | |||
| const GLshort top = (GLshort) (contextHeight - anchorPosAndTextureSize.getY()); | |||
| const GLshort bottom = (GLshort) (contextHeight - anchorPosAndTextureSize.getBottom()); | |||
| const GLshort vertices[] = { left, bottom, right, bottom, left, top, right, top }; | |||
| glVertexPointer (2, GL_SHORT, 0, vertices); | |||
| glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | |||
| glDisable (GL_SCISSOR_TEST); | |||
| } | |||
| #endif | |||
| } | |||
| @@ -112,9 +112,14 @@ public: | |||
| @param anchorPosAndTextureSize the position of this rectangle is the texture's top-left | |||
| anchor position in the target space, and the size must be | |||
| the total size of the texture. | |||
| @param contextWidth the width of the context or framebuffer that is being drawn into, | |||
| used for scaling of the coordinates. | |||
| @param contextHeight the height of the context or framebuffer that is being drawn into, | |||
| used for vertical flipping of the y coordinates. | |||
| */ | |||
| void copyTexture (const Rectangle<int>& targetClipArea, | |||
| const Rectangle<int>& anchorPosAndTextureSize); | |||
| const Rectangle<int>& anchorPosAndTextureSize, | |||
| int contextWidth, int contextHeight); | |||
| protected: | |||
| //============================================================================== | |||
| @@ -32,7 +32,7 @@ public: | |||
| width (width_), | |||
| height (height_), | |||
| textureID (0), | |||
| frameBufferHandle (0), | |||
| frameBufferID (0), | |||
| depthOrStencilBuffer (0), | |||
| hasDepthBuffer (false), | |||
| hasStencilBuffer (false), | |||
| @@ -47,8 +47,8 @@ public: | |||
| return; | |||
| #endif | |||
| context.extensions.glGenFramebuffers (1, &frameBufferHandle); | |||
| context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle); | |||
| context.extensions.glGenFramebuffers (1, &frameBufferID); | |||
| context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferID); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| glGenTextures (1, &textureID); | |||
| @@ -102,15 +102,15 @@ public: | |||
| if (depthOrStencilBuffer != 0) | |||
| context.extensions.glDeleteRenderbuffers (1, &depthOrStencilBuffer); | |||
| if (frameBufferHandle != 0) | |||
| context.extensions.glDeleteFramebuffers (1, &frameBufferHandle); | |||
| if (frameBufferID != 0) | |||
| context.extensions.glDeleteFramebuffers (1, &frameBufferID); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| } | |||
| void bind() | |||
| { | |||
| context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle); | |||
| context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferID); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| } | |||
| @@ -122,7 +122,7 @@ public: | |||
| OpenGLContext& context; | |||
| const int width, height; | |||
| GLuint textureID, frameBufferHandle, depthOrStencilBuffer; | |||
| GLuint textureID, frameBufferID, depthOrStencilBuffer; | |||
| bool hasDepthBuffer, hasStencilBuffer, ok; | |||
| private: | |||
| @@ -214,7 +214,7 @@ bool OpenGLFrameBuffer::initialise (OpenGLFrameBuffer& other) | |||
| glEnable (GL_TEXTURE_2D); | |||
| #endif | |||
| glBindTexture (GL_TEXTURE_2D, p->textureID); | |||
| pimpl->context.copyTexture (area, area); | |||
| pimpl->context.copyTexture (area, area, area.getWidth(), area.getHeight()); | |||
| glBindTexture (GL_TEXTURE_2D, 0); | |||
| JUCE_CHECK_OPENGL_ERROR | |||
| @@ -272,6 +272,11 @@ bool OpenGLFrameBuffer::makeCurrentRenderingTarget() | |||
| return true; | |||
| } | |||
| GLuint OpenGLFrameBuffer::getFrameBufferID() const | |||
| { | |||
| return pimpl != nullptr ? pimpl->frameBufferID : 0; | |||
| } | |||
| GLuint OpenGLFrameBuffer::getCurrentFrameBufferTarget() | |||
| { | |||
| GLint fb; | |||
| @@ -339,7 +344,7 @@ bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int> | |||
| glDrawTexiOES (area.getX(), area.getY(), 1, area.getWidth(), area.getHeight()); | |||
| glBindTexture (GL_TEXTURE_2D, 0); | |||
| #else | |||
| pimpl->context.copyTexture (area, area); | |||
| pimpl->context.copyTexture (area, area, pimpl->width, pimpl->height); | |||
| #endif | |||
| pimpl->context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, 0); | |||
| @@ -95,6 +95,9 @@ public: | |||
| /** Deselects this buffer as the current OpenGL rendering target. */ | |||
| void releaseAsRenderingTarget(); | |||
| /** Returns the ID of this framebuffer, or 0 if it isn't initialised. */ | |||
| GLuint getFrameBufferID() const; | |||
| /** Returns the current frame buffer ID for the current context. */ | |||
| static GLuint getCurrentFrameBufferTarget(); | |||
| @@ -28,59 +28,23 @@ | |||
| //============================================================================== | |||
| /** A LowLevelGraphicsContext for rendering into an OpenGL framebuffer or window. | |||
| /** Creates a graphics context object that will render into the given OpenGL target. | |||
| The caller is responsible for deleting this object when no longer needed. | |||
| */ | |||
| class JUCE_API OpenGLGraphicsContext : public LowLevelGraphicsContext | |||
| { | |||
| public: | |||
| explicit OpenGLGraphicsContext (OpenGLComponent& target); | |||
| OpenGLGraphicsContext (OpenGLContext& context, OpenGLFrameBuffer& target); | |||
| OpenGLGraphicsContext (OpenGLContext& context, unsigned int frameBufferID, int width, int height); | |||
| ~OpenGLGraphicsContext(); | |||
| LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLComponent& target); | |||
| bool isVectorDevice() const; | |||
| void setOrigin (int x, int y); | |||
| void addTransform (const AffineTransform&); | |||
| float getScaleFactor(); | |||
| bool clipToRectangle (const Rectangle<int>&); | |||
| bool clipToRectangleList (const RectangleList&); | |||
| void excludeClipRectangle (const Rectangle<int>&); | |||
| void clipToPath (const Path& path, const AffineTransform&); | |||
| void clipToImageAlpha (const Image& sourceImage, const AffineTransform&); | |||
| bool clipRegionIntersects (const Rectangle<int>&); | |||
| Rectangle<int> getClipBounds() const; | |||
| bool isClipEmpty() const; | |||
| void saveState(); | |||
| void restoreState(); | |||
| void beginTransparencyLayer (float opacity); | |||
| void endTransparencyLayer(); | |||
| void setFill (const FillType& fillType); | |||
| void setOpacity (float newOpacity); | |||
| void setInterpolationQuality (Graphics::ResamplingQuality); | |||
| void fillRect (const Rectangle<int>& r, bool replaceExistingContents); | |||
| void fillPath (const Path& path, const AffineTransform& transform); | |||
| void drawImage (const Image& sourceImage, const AffineTransform& transform); | |||
| void drawLine (const Line <float>& line); | |||
| void drawVerticalLine (int x, float top, float bottom); | |||
| void drawHorizontalLine (int y, float left, float right); | |||
| void setFont (const Font&); | |||
| const Font& getFont(); | |||
| void drawGlyph (int glyphNumber, const AffineTransform&); | |||
| /** Creates a graphics context object that will render into the given OpenGL target. | |||
| The caller is responsible for deleting this object when no longer needed. | |||
| */ | |||
| LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, | |||
| OpenGLFrameBuffer& target); | |||
| #ifndef DOXYGEN | |||
| class SavedState; | |||
| class GLState; | |||
| #endif | |||
| /** Creates a graphics context object that will render into the given OpenGL target. | |||
| The caller is responsible for deleting this object when no longer needed. | |||
| */ | |||
| LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, | |||
| unsigned int frameBufferID, | |||
| int width, int height); | |||
| private: | |||
| ScopedPointer<GLState> glState; | |||
| RenderingHelpers::SavedStateStack<SavedState> stack; | |||
| }; | |||
| #endif // __JUCE_OPENGLGRAPHICSCONTEXT_JUCEHEADER__ | |||
| @@ -38,10 +38,10 @@ public: | |||
| LowLevelGraphicsContext* createLowLevelContext() | |||
| { | |||
| return new OpenGLGraphicsContext (context, frameBuffer); | |||
| return createOpenGLGraphicsContext (context, frameBuffer); | |||
| } | |||
| ImageType* createType() const { return new OpenGLImageType(); } | |||
| ImageType* createType() const { return new OpenGLImageType(); } | |||
| ImagePixelData* clone() | |||
| { | |||