| @@ -771,7 +771,7 @@ void InterProcessLock::exit() | |||||
| //============================================================================== | //============================================================================== | ||||
| void JUCE_API juce_threadEntryPoint (void*); | void JUCE_API juce_threadEntryPoint (void*); | ||||
| void* threadEntryProc (void* userData) | |||||
| extern "C" void* threadEntryProc (void* userData) | |||||
| { | { | ||||
| JUCE_AUTORELEASEPOOL | JUCE_AUTORELEASEPOOL | ||||
| @@ -77,7 +77,7 @@ public: | |||||
| { | { | ||||
| if (isOnlyTranslated | if (isOnlyTranslated | ||||
| && t.isOnlyTranslation() | && t.isOnlyTranslation() | ||||
| && isIntegerTranlation (t)) | |||||
| && isIntegerTranslation (t)) | |||||
| { | { | ||||
| xOffset += (int) t.getTranslationX(); | xOffset += (int) t.getTranslationX(); | ||||
| yOffset += (int) t.getTranslationY(); | yOffset += (int) t.getTranslationY(); | ||||
| @@ -126,7 +126,7 @@ public: | |||||
| bool isOnlyTranslated; | bool isOnlyTranslated; | ||||
| private: | private: | ||||
| static inline bool isIntegerTranlation (const AffineTransform& t) noexcept | |||||
| static inline bool isIntegerTranslation (const AffineTransform& t) noexcept | |||||
| { | { | ||||
| const int tx = (int) (t.getTranslationX() * 256.0f); | const int tx = (int) (t.getTranslationX() * 256.0f); | ||||
| const int ty = (int) (t.getTranslationY() * 256.0f); | const int ty = (int) (t.getTranslationY() * 256.0f); | ||||
| @@ -129,16 +129,16 @@ void ImageButton::paintButton (Graphics& g, | |||||
| const int ih = im.getHeight(); | const int ih = im.getHeight(); | ||||
| imageW = getWidth(); | imageW = getWidth(); | ||||
| imageH = getHeight(); | imageH = getHeight(); | ||||
| imageX = (imageW - iw) >> 1; | |||||
| imageY = (imageH - ih) >> 1; | |||||
| imageX = (imageW - iw) / 2; | |||||
| imageY = (imageH - ih) / 2; | |||||
| if (scaleImageToFit) | if (scaleImageToFit) | ||||
| { | { | ||||
| if (preserveProportions) | if (preserveProportions) | ||||
| { | { | ||||
| int newW, newH; | int newW, newH; | ||||
| const float imRatio = ih / (float)iw; | |||||
| const float destRatio = imageH / (float)imageW; | |||||
| const float imRatio = ih / (float) iw; | |||||
| const float destRatio = imageH / (float) imageW; | |||||
| if (imRatio > destRatio) | if (imRatio > destRatio) | ||||
| { | { | ||||
| @@ -169,11 +169,13 @@ void ImageButton::paintButton (Graphics& g, | |||||
| imageH = ih; | imageH = ih; | ||||
| } | } | ||||
| const bool useDownImage = isButtonDown || getToggleState(); | |||||
| getLookAndFeel().drawImageButton (g, &im, imageX, imageY, imageW, imageH, | getLookAndFeel().drawImageButton (g, &im, imageX, imageY, imageW, imageH, | ||||
| isButtonDown ? downOverlay | |||||
| useDownImage ? downOverlay | |||||
| : (isMouseOverButton ? overOverlay | : (isMouseOverButton ? overOverlay | ||||
| : normalOverlay), | : normalOverlay), | ||||
| isButtonDown ? downOpacity | |||||
| useDownImage ? downOpacity | |||||
| : (isMouseOverButton ? overOpacity | : (isMouseOverButton ? overOpacity | ||||
| : normalOpacity), | : normalOpacity), | ||||
| *this); | *this); | ||||
| @@ -39,3 +39,8 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* component, | |||||
| { | { | ||||
| } | } | ||||
| bool OpenGLHelpers::isContextActive() | |||||
| { | |||||
| return false; | |||||
| } | |||||
| @@ -234,3 +234,9 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/, | |||||
| OwnedArray <OpenGLPixelFormat>& /*results*/) | OwnedArray <OpenGLPixelFormat>& /*results*/) | ||||
| { | { | ||||
| } | } | ||||
| //============================================================================== | |||||
| bool OpenGLHelpers::isContextActive() | |||||
| { | |||||
| return [EAGLContext currentContext] != nil; | |||||
| } | |||||
| @@ -200,3 +200,10 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* component, OwnedArr | |||||
| { | { | ||||
| results.add (new OpenGLPixelFormat()); // xxx | results.add (new OpenGLPixelFormat()); // xxx | ||||
| } | } | ||||
| //============================================================================== | |||||
| bool OpenGLHelpers::isContextActive() | |||||
| { | |||||
| ScopedXLock xlock; | |||||
| return glXGetCurrentContext() != 0; | |||||
| } | |||||
| @@ -312,3 +312,9 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/, | |||||
| results.add (pf); | results.add (pf); | ||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | |||||
| bool OpenGLHelpers::isContextActive() | |||||
| { | |||||
| return [NSOpenGLContext currentContext] != nil; | |||||
| } | |||||
| @@ -509,3 +509,9 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* component, | |||||
| wc.findAlternativeOpenGLPixelFormats (results); | wc.findAlternativeOpenGLPixelFormats (results); | ||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | |||||
| bool OpenGLHelpers::isContextActive() | |||||
| { | |||||
| return wglGetCurrentContext() != 0; | |||||
| } | |||||
| @@ -145,6 +145,10 @@ public: | |||||
| hasStencilBuffer (false), | hasStencilBuffer (false), | ||||
| ok (false) | ok (false) | ||||
| { | { | ||||
| // Framebuffer objects can only be created when the current thread has an active OpenGL | |||||
| // context. You'll need to make an OpenGLComponent active before calling this. | |||||
| jassert (OpenGLHelpers::isContextActive()); | |||||
| #if JUCE_WINDOWS || JUCE_LINUX | #if JUCE_WINDOWS || JUCE_LINUX | ||||
| initialiseFrameBufferFunctions(); | initialiseFrameBufferFunctions(); | ||||
| @@ -155,17 +159,13 @@ public: | |||||
| OpenGLHelpers::resetErrorState(); | OpenGLHelpers::resetErrorState(); | ||||
| glGenFramebuffersEXT (1, &frameBufferHandle); | glGenFramebuffersEXT (1, &frameBufferHandle); | ||||
| glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, frameBufferHandle); | glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, frameBufferHandle); | ||||
| glGenTextures (1, &textureID); | glGenTextures (1, &textureID); | ||||
| glBindTexture (textureType, textureID); | glBindTexture (textureType, textureID); | ||||
| glTexImage2D (textureType, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | glTexImage2D (textureType, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | ||||
| glTexParameterf (textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
| glTexParameterf (textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
| glTexParameterf (textureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |||||
| glTexParameterf (textureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |||||
| glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textureType, textureID, 0); | glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textureType, textureID, 0); | ||||
| if (wantsDepthBuffer || wantsStencilBuffer) | if (wantsDepthBuffer || wantsStencilBuffer) | ||||
| @@ -174,37 +174,33 @@ public: | |||||
| glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | ||||
| jassert (glIsRenderbufferEXT (depthOrStencilBuffer)); | jassert (glIsRenderbufferEXT (depthOrStencilBuffer)); | ||||
| if (wantsDepthBuffer && wantsStencilBuffer) | |||||
| { | |||||
| glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, width, height); | |||||
| glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, | |||||
| (wantsDepthBuffer && wantsStencilBuffer) ? GL_DEPTH24_STENCIL8_EXT | |||||
| #if JUCE_OPENGL_ES | |||||
| : GL_DEPTH_COMPONENT16, | |||||
| #else | |||||
| : GL_DEPTH_COMPONENT, | |||||
| #endif | |||||
| width, height); | |||||
| GLint params = 0; | |||||
| glGetRenderbufferParameterivEXT (GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, ¶ms); | |||||
| GLint params = 0; | |||||
| glGetRenderbufferParameterivEXT (GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, ¶ms); | |||||
| glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | |||||
| glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | |||||
| if (wantsStencilBuffer) | |||||
| glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | ||||
| hasDepthBuffer = true; | |||||
| hasStencilBuffer = true; | |||||
| } | |||||
| else | |||||
| { | |||||
| #if JUCE_OPENGL_ES | |||||
| glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, width, height); | |||||
| #else | |||||
| glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); | |||||
| #endif | |||||
| GLint params = 0; | |||||
| glGetRenderbufferParameterivEXT (GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, ¶ms); | |||||
| glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthOrStencilBuffer); | |||||
| hasDepthBuffer = true; | |||||
| } | |||||
| hasDepthBuffer = wantsDepthBuffer; | |||||
| hasStencilBuffer = wantsStencilBuffer; | |||||
| } | } | ||||
| ok = checkStatus(); | ok = checkStatus(); | ||||
| glTexParameterf (textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
| glTexParameterf (textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
| glTexParameterf (textureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |||||
| glTexParameterf (textureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |||||
| glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); | glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); | ||||
| } | } | ||||
| @@ -438,7 +434,7 @@ bool OpenGLFrameBuffer::writePixels (const void* data, int pixelStride, const Re | |||||
| glBindTexture (GL_TEXTURE_2D, temporaryTexture); | glBindTexture (GL_TEXTURE_2D, temporaryTexture); | ||||
| glPixelStorei (GL_UNPACK_ALIGNMENT, pixelStride); | glPixelStorei (GL_UNPACK_ALIGNMENT, pixelStride); | ||||
| glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, area.getWidth(), area.getHeight(), 0, | |||||
| glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, area.getWidth(), area.getHeight(), 0, | |||||
| format, GL_UNSIGNED_BYTE, data); | format, GL_UNSIGNED_BYTE, data); | ||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||
| @@ -522,24 +518,5 @@ void OpenGLFrameBuffer::drawAt (float x1, float y1) const | |||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | |||||
| void OpenGLFrameBuffer::createAlphaChannelFromPath (const Path& path, const AffineTransform& transform, | |||||
| const int oversamplingLevel) | |||||
| { | |||||
| makeCurrentRenderingTarget(); | |||||
| glEnableClientState (GL_VERTEX_ARRAY); | |||||
| glEnableClientState (GL_TEXTURE_COORD_ARRAY); | |||||
| glDisableClientState (GL_COLOR_ARRAY); | |||||
| glDisableClientState (GL_NORMAL_ARRAY); | |||||
| glDisable (GL_TEXTURE_2D); | |||||
| glDisable (GL_DEPTH_TEST); | |||||
| glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||||
| glEnable (GL_BLEND); | |||||
| glBlendFunc (GL_ONE, GL_ONE); | |||||
| prepareFor2D(); | |||||
| TriangulatedPath (path, transform).draw (oversamplingLevel); | |||||
| } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -134,19 +134,6 @@ public: | |||||
| bool writePixels (const void* srcData, int srcPixelStride, | bool writePixels (const void* srcData, int srcPixelStride, | ||||
| const Rectangle<int>& targetArea); | const Rectangle<int>& targetArea); | ||||
| /** This will render an anti-aliased path into just the alpha channel of this framebuffer. | |||||
| The idea here is that you can clear a framebuffer, use this to set its alpha channel, then | |||||
| fill the RGB channels with some kind of fill-pattern, and then copy the whole thing onto | |||||
| a target, to produce a filled path with some kind of texture. | |||||
| Calling this will make changes to a lot of openGL state, including colour masks, blend | |||||
| functions, etc | |||||
| */ | |||||
| void createAlphaChannelFromPath (const Path& path, | |||||
| const AffineTransform& transform, | |||||
| int oversamplingLevel = 4); | |||||
| private: | private: | ||||
| class Pimpl; | class Pimpl; | ||||
| friend class ScopedPointer<Pimpl>; | friend class ScopedPointer<Pimpl>; | ||||
| @@ -51,7 +51,7 @@ void OpenGLHelpers::prepareFor2D (const int width, const int height) | |||||
| glLoadIdentity(); | glLoadIdentity(); | ||||
| #if JUCE_OPENGL_ES | #if JUCE_OPENGL_ES | ||||
| glOrthof (0.0f, (float) width, 0.0f, (float) height, 0.0f, 1.0f); | |||||
| glOrthof (0.0f, (GLfloat) width, 0.0f, (GLfloat) height, 0.0f, 1.0f); | |||||
| #else | #else | ||||
| glOrtho (0.0, width, 0.0, height, 0, 1); | glOrtho (0.0, width, 0.0, height, 0, 1); | ||||
| #endif | #endif | ||||
| @@ -64,10 +64,10 @@ void OpenGLHelpers::setPerspective (double fovy, double aspect, double zNear, do | |||||
| glLoadIdentity(); | glLoadIdentity(); | ||||
| #if JUCE_OPENGL_ES | #if JUCE_OPENGL_ES | ||||
| const float ymax = (float) (zNear * tan (fovy * double_Pi / 360.0)); | |||||
| const float ymin = -ymax; | |||||
| const GLfloat ymax = (GLfloat) (zNear * tan (fovy * double_Pi / 360.0)); | |||||
| const GLfloat ymin = -ymax; | |||||
| glFrustumf (ymin * (float) aspect, ymax * (float) aspect, ymin, ymax, (float) zNear, (float) zFar); | |||||
| glFrustumf (ymin * (GLfloat) aspect, ymax * (GLfloat) aspect, ymin, ymax, (GLfloat) zNear, (GLfloat) zFar); | |||||
| #else | #else | ||||
| const double ymax = zNear * tan (fovy * double_Pi / 360.0); | const double ymax = zNear * tan (fovy * double_Pi / 360.0); | ||||
| const double ymin = -ymax; | const double ymin = -ymax; | ||||
| @@ -136,7 +136,6 @@ namespace OpenGLGradientHelpers | |||||
| { | { | ||||
| void drawTriangles (GLenum mode, const GLfloat* vertices, const GLfloat* textureCoords, const int numElements) | void drawTriangles (GLenum mode, const GLfloat* vertices, const GLfloat* textureCoords, const int numElements) | ||||
| { | { | ||||
| glEnable (GL_BLEND); | |||||
| glEnable (GL_TEXTURE_2D); | glEnable (GL_TEXTURE_2D); | ||||
| glEnableClientState (GL_VERTEX_ARRAY); | glEnableClientState (GL_VERTEX_ARRAY); | ||||
| glEnableClientState (GL_TEXTURE_COORD_ARRAY); | glEnableClientState (GL_TEXTURE_COORD_ARRAY); | ||||
| @@ -164,10 +163,10 @@ namespace OpenGLGradientHelpers | |||||
| p2.getX(), p2.getY(), 1.0f, 0.0f, | p2.getX(), p2.getY(), 1.0f, 0.0f, | ||||
| p3.getX(), p3.getY(), 0.0f, 1.0f)); | p3.getX(), p3.getY(), 0.0f, 1.0f)); | ||||
| const float l = (float) rect.getX(); | |||||
| const float r = (float) rect.getRight(); | |||||
| const float t = (float) rect.getY(); | |||||
| const float b = (float) rect.getBottom(); | |||||
| const GLfloat l = (GLfloat) rect.getX(); | |||||
| const GLfloat r = (GLfloat) rect.getRight(); | |||||
| const GLfloat t = (GLfloat) rect.getY(); | |||||
| const GLfloat b = (GLfloat) rect.getBottom(); | |||||
| const GLfloat vertices[] = { l, t, r, t, l, b, r, b }; | const GLfloat vertices[] = { l, t, r, t, l, b, r, b }; | ||||
| GLfloat textureCoords[] = { l, t, r, t, l, b, r, b }; | GLfloat textureCoords[] = { l, t, r, t, l, b, r, b }; | ||||
| @@ -202,8 +201,7 @@ namespace OpenGLGradientHelpers | |||||
| *t++ = 0.0f; | *t++ = 0.0f; | ||||
| *t++ = 0.0f; | *t++ = 0.0f; | ||||
| const float originalRadius = grad.point1.getDistanceFrom (grad.point2); | |||||
| const float texturePos = sourceRadius / originalRadius; | |||||
| const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2); | |||||
| for (int i = numDivisions + 1; --i >= 0;) | for (int i = numDivisions + 1; --i >= 0;) | ||||
| { | { | ||||
| @@ -280,15 +278,54 @@ void OpenGLHelpers::fillRectWithColour (const Rectangle<int>& rect, const Colour | |||||
| void OpenGLHelpers::fillRect (const Rectangle<int>& rect) | void OpenGLHelpers::fillRect (const Rectangle<int>& rect) | ||||
| { | { | ||||
| const GLfloat vertices[] = { (float) rect.getX(), (float) rect.getY(), | |||||
| (float) rect.getRight(), (float) rect.getY(), | |||||
| (float) rect.getX(), (float) rect.getBottom(), | |||||
| (float) rect.getRight(), (float) rect.getBottom() }; | |||||
| const GLfloat vertices[] = { (GLfloat) rect.getX(), (GLfloat) rect.getY(), | |||||
| (GLfloat) rect.getRight(), (GLfloat) rect.getY(), | |||||
| (GLfloat) rect.getX(), (GLfloat) rect.getBottom(), | |||||
| (GLfloat) rect.getRight(), (GLfloat) rect.getBottom() }; | |||||
| glVertexPointer (2, GL_FLOAT, 0, vertices); | glVertexPointer (2, GL_FLOAT, 0, vertices); | ||||
| glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | ||||
| } | } | ||||
| void OpenGLHelpers::fillRectWithTiledTexture (int textureWidth, int textureHeight, | |||||
| const Rectangle<int>& clip, | |||||
| const AffineTransform& transform, | |||||
| float alpha) | |||||
| { | |||||
| glEnable (GL_TEXTURE_2D); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
| glEnableClientState (GL_VERTEX_ARRAY); | |||||
| glEnableClientState (GL_TEXTURE_COORD_ARRAY); | |||||
| glDisableClientState (GL_COLOR_ARRAY); | |||||
| glDisableClientState (GL_NORMAL_ARRAY); | |||||
| glColor4f (1.0f, 1.0f, 1.0f, alpha); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |||||
| const GLfloat clipX = (GLfloat) clip.getX(); | |||||
| const GLfloat clipY = (GLfloat) clip.getY(); | |||||
| const GLfloat clipR = (GLfloat) clip.getRight(); | |||||
| const GLfloat clipB = (GLfloat) clip.getBottom(); | |||||
| const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB }; | |||||
| GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB }; | |||||
| { | |||||
| const AffineTransform t (transform.inverted().scaled (1.0f / textureWidth, | |||||
| 1.0f / textureHeight)); | |||||
| t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]); | |||||
| t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]); | |||||
| } | |||||
| glVertexPointer (2, GL_FLOAT, 0, vertices); | |||||
| glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); | |||||
| glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| // This breaks down a path into a series of horizontal strips of trapezoids.. | // This breaks down a path into a series of horizontal strips of trapezoids.. | ||||
| class TriangulatedPath::TrapezoidedPath | class TriangulatedPath::TrapezoidedPath | ||||
| @@ -575,6 +612,8 @@ TriangulatedPath::TriangulatedPath (const Path& path, const AffineTransform& tra | |||||
| TrapezoidedPath (path, transform).iterate (*this); | TrapezoidedPath (path, transform).iterate (*this); | ||||
| } | } | ||||
| TriangulatedPath::~TriangulatedPath() {} | |||||
| void TriangulatedPath::draw (const int oversamplingLevel) const | void TriangulatedPath::draw (const int oversamplingLevel) const | ||||
| { | { | ||||
| glColor4f (1.0f, 1.0f, 1.0f, 1.0f / (oversamplingLevel * oversamplingLevel)); | glColor4f (1.0f, 1.0f, 1.0f, 1.0f / (oversamplingLevel * oversamplingLevel)); | ||||
| @@ -670,214 +709,5 @@ void OpenGLRenderingTarget::prepareFor2D() | |||||
| getRenderingTargetHeight()); | getRenderingTargetHeight()); | ||||
| } | } | ||||
| namespace GLPathRendering | |||||
| { | |||||
| void clipToPath (OpenGLRenderingTarget& target, | |||||
| const Path& path, const AffineTransform& transform) | |||||
| { | |||||
| const int w = target.getRenderingTargetWidth(); | |||||
| const int h = target.getRenderingTargetHeight(); | |||||
| OpenGLFrameBuffer fb; | |||||
| fb.initialise (w, h); | |||||
| fb.makeCurrentAndClear(); | |||||
| fb.createAlphaChannelFromPath (path, transform); | |||||
| target.makeCurrentRenderingTarget(); | |||||
| target.prepareFor2D(); | |||||
| glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); | |||||
| glBlendFunc (GL_DST_ALPHA, GL_ZERO); | |||||
| glColor4f (1.0f, 1.0f, 1.0f, 1.0f); | |||||
| fb.drawAt (0, 0); | |||||
| } | |||||
| void fillPathWithColour (OpenGLRenderingTarget& target, | |||||
| const Rectangle<int>& clip, const Path& path, | |||||
| const AffineTransform& pathTransform, | |||||
| const Colour& colour) | |||||
| { | |||||
| OpenGLFrameBuffer f; | |||||
| f.initialise (clip.getWidth(), clip.getHeight()); | |||||
| f.makeCurrentAndClear(); | |||||
| f.createAlphaChannelFromPath (path, pathTransform.translated ((float) -clip.getX(), (float) -clip.getY()) | |||||
| .followedBy (AffineTransform::verticalFlip ((float) clip.getHeight()))); | |||||
| f.releaseAsRenderingTarget(); | |||||
| target.makeCurrentRenderingTarget(); | |||||
| glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||||
| glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
| OpenGLHelpers::setColour (colour); | |||||
| target.prepareFor2D(); | |||||
| f.drawAt ((float) clip.getX(), (float) (target.getRenderingTargetHeight() - clip.getBottom())); | |||||
| } | |||||
| void fillPathWithGradient (OpenGLRenderingTarget& target, | |||||
| const Rectangle<int>& clip, const Path& path, | |||||
| const AffineTransform& pathTransform, | |||||
| const ColourGradient& grad, | |||||
| const AffineTransform& gradientTransform, | |||||
| const GLfloat alpha) | |||||
| { | |||||
| const int targetHeight = target.getRenderingTargetHeight(); | |||||
| OpenGLFrameBuffer f; | |||||
| f.initialise (clip.getWidth(), clip.getHeight()); | |||||
| f.makeCurrentAndClear(); | |||||
| const AffineTransform correction (AffineTransform::translation ((float) -clip.getX(), (float) -clip.getY()) | |||||
| .followedBy (AffineTransform::verticalFlip ((float) clip.getHeight()))); | |||||
| f.createAlphaChannelFromPath (path, pathTransform.followedBy (correction)); | |||||
| f.makeCurrentRenderingTarget(); | |||||
| f.prepareFor2D(); | |||||
| glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||||
| glBlendFunc (GL_DST_ALPHA, GL_ZERO); | |||||
| OpenGLHelpers::fillRectWithColourGradient (Rectangle<int> (0, 0, clip.getWidth(), clip.getHeight()), | |||||
| grad, gradientTransform.followedBy (correction)); | |||||
| f.releaseAsRenderingTarget(); | |||||
| target.makeCurrentRenderingTarget(); | |||||
| glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||||
| glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); | |||||
| glColor4f (alpha, alpha, alpha, alpha); | |||||
| target.prepareFor2D(); | |||||
| f.drawAt ((float) clip.getX(), (float) (targetHeight - clip.getBottom())); | |||||
| } | |||||
| void fillPathWithImage (OpenGLRenderingTarget& target, | |||||
| const Rectangle<int>& clip, const Path& path, | |||||
| const AffineTransform& transform, | |||||
| GLuint textureID, GLfloat textureWidth, GLfloat textureHeight, | |||||
| const AffineTransform& textureTransform, | |||||
| const bool tiled, | |||||
| const GLfloat alpha) | |||||
| { | |||||
| const int targetHeight = target.getRenderingTargetHeight(); | |||||
| OpenGLFrameBuffer f; | |||||
| f.initialise (clip.getWidth(), clip.getHeight()); | |||||
| f.makeCurrentRenderingTarget(); | |||||
| f.prepareFor2D(); | |||||
| glDisable (GL_BLEND); | |||||
| glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||||
| glColor4f (1.0f, 1.0f, 1.0f, 1.0f); | |||||
| const GLfloat clipX = (GLfloat) clip.getX(); | |||||
| const GLfloat clipY = (GLfloat) clip.getY(); | |||||
| const GLfloat clipH = (GLfloat) clip.getHeight(); | |||||
| const GLfloat clipB = (GLfloat) clip.getBottom(); | |||||
| const AffineTransform correction (AffineTransform::translation (-clipX, -clipY) | |||||
| .followedBy (AffineTransform::verticalFlip (clipH))); | |||||
| glBindTexture (GL_TEXTURE_2D, textureID); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
| glEnableClientState (GL_VERTEX_ARRAY); | |||||
| glEnableClientState (GL_TEXTURE_COORD_ARRAY); | |||||
| glDisableClientState (GL_COLOR_ARRAY); | |||||
| glDisableClientState (GL_NORMAL_ARRAY); | |||||
| glColor4f (1.0f, 1.0f, 1.0f, 1.0f); | |||||
| if (tiled) | |||||
| { | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |||||
| const GLfloat clipW = (GLfloat) clip.getWidth(); | |||||
| const GLfloat clipR = (GLfloat) clip.getRight(); | |||||
| const GLfloat vertices[] = { 0, clipH, clipW, clipH, 0, 0, clipW, 0 }; | |||||
| GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB }; | |||||
| { | |||||
| const AffineTransform t (textureTransform.inverted().scaled (1.0f / textureWidth, | |||||
| 1.0f / textureHeight)); | |||||
| t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]); | |||||
| t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]); | |||||
| } | |||||
| glVertexPointer (2, GL_FLOAT, 0, vertices); | |||||
| glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); | |||||
| glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | |||||
| } | |||||
| else | |||||
| { | |||||
| glClearColor (0, 0, 0, 0); | |||||
| glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |||||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |||||
| GLfloat vertices[] = { 0, 0, textureWidth, 0, 0, textureHeight, textureWidth, textureHeight }; | |||||
| const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f }; | |||||
| { | |||||
| const AffineTransform t (textureTransform.followedBy (correction)); | |||||
| t.transformPoints (vertices[0], vertices[1], vertices[2], vertices[3]); | |||||
| t.transformPoints (vertices[4], vertices[5], vertices[6], vertices[7]); | |||||
| } | |||||
| glVertexPointer (2, GL_FLOAT, 0, vertices); | |||||
| glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); | |||||
| glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | |||||
| } | |||||
| glBindTexture (GL_TEXTURE_2D, 0); | |||||
| clipToPath (f, path, transform.followedBy (correction)); | |||||
| f.releaseAsRenderingTarget(); | |||||
| target.makeCurrentRenderingTarget(); | |||||
| glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||||
| glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
| glColor4f (1.0f, 1.0f, 1.0f, alpha); | |||||
| target.prepareFor2D(); | |||||
| f.drawAt (clipX, targetHeight - clipB); | |||||
| } | |||||
| } | |||||
| void OpenGLRenderingTarget::fillPath (const Rectangle<int>& clip, | |||||
| const Path& path, const AffineTransform& transform, | |||||
| const FillType& fill) | |||||
| { | |||||
| if (! fill.isInvisible()) | |||||
| { | |||||
| if (fill.isColour()) | |||||
| { | |||||
| GLPathRendering::fillPathWithColour (*this, clip, path, transform, fill.colour); | |||||
| } | |||||
| else if (fill.isGradient()) | |||||
| { | |||||
| GLPathRendering::fillPathWithGradient (*this, clip, path, transform, | |||||
| *(fill.gradient), fill.transform, | |||||
| fill.colour.getFloatAlpha()); | |||||
| } | |||||
| else if (fill.isTiledImage()) | |||||
| { | |||||
| OpenGLTextureFromImage t (fill.image); | |||||
| GLPathRendering::fillPathWithImage (*this, clip, path, transform, | |||||
| t.textureID, (GLfloat) t.width, (GLfloat) t.height, | |||||
| fill.transform, true, | |||||
| fill.colour.getFloatAlpha()); | |||||
| } | |||||
| } | |||||
| } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -40,6 +40,9 @@ public: | |||||
| /** Clears the GL error state. */ | /** Clears the GL error state. */ | ||||
| static void resetErrorState(); | static void resetErrorState(); | ||||
| /** Returns true if the current thread has an active OpenGL context. */ | |||||
| static bool isContextActive(); | |||||
| /** Clears the current context using the given colour. */ | /** Clears the current context using the given colour. */ | ||||
| static void clear (const Colour& colour); | static void clear (const Colour& colour); | ||||
| @@ -78,6 +81,11 @@ public: | |||||
| static void fillRectWithColourGradient (const Rectangle<int>& rect, | static void fillRectWithColourGradient (const Rectangle<int>& rect, | ||||
| const ColourGradient& gradient, | const ColourGradient& gradient, | ||||
| const AffineTransform& transform); | const AffineTransform& transform); | ||||
| static void fillRectWithTiledTexture (int textureWidth, int textureHeight, | |||||
| const Rectangle<int>& targetArea, | |||||
| const AffineTransform& transform, | |||||
| float alpha); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -88,6 +96,9 @@ class JUCE_API TriangulatedPath | |||||
| public: | public: | ||||
| TriangulatedPath (const Path& path, const AffineTransform& transform); | TriangulatedPath (const Path& path, const AffineTransform& transform); | ||||
| /** Destructor. */ | |||||
| ~TriangulatedPath(); | |||||
| /** Renders the path, using a jittered oversampling method. | /** Renders the path, using a jittered oversampling method. | ||||
| The oversampling level is the square root of the number of times it | The oversampling level is the square root of the number of times it | ||||
| should be oversampled, so 3 or 4 might be reasonable. | should be oversampled, so 3 or 4 might be reasonable. | ||||
| @@ -102,7 +113,7 @@ private: | |||||
| friend class TrapezoidedPath; | friend class TrapezoidedPath; | ||||
| void startNewBlock(); | void startNewBlock(); | ||||
| void addTriangle (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3); | |||||
| void addTriangle (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3); | |||||
| void addTrapezoid (GLfloat y1, GLfloat y2, GLfloat x1, GLfloat x2, GLfloat x3, GLfloat x4); | void addTrapezoid (GLfloat y1, GLfloat y2, GLfloat x1, GLfloat x2, GLfloat x3, GLfloat x4); | ||||
| struct TriangleBlock; | struct TriangleBlock; | ||||
| @@ -51,11 +51,6 @@ public: | |||||
| @see OpenGLHelpers::prepareFor2D | @see OpenGLHelpers::prepareFor2D | ||||
| */ | */ | ||||
| void prepareFor2D(); | void prepareFor2D(); | ||||
| /** Fills a path with a custom FillType. */ | |||||
| void fillPath (const Rectangle<int>& clipArea, | |||||
| const Path& path, const AffineTransform& pathTransform, | |||||
| const FillType& fill); | |||||
| }; | }; | ||||
| @@ -49,6 +49,10 @@ bool OpenGLTexture::isValidSize (int width, int height) | |||||
| void OpenGLTexture::create (const int w, const int h) | void OpenGLTexture::create (const int w, const int h) | ||||
| { | { | ||||
| // Texture objects can only be created when the current thread has an active OpenGL | |||||
| // context. You'll need to make an OpenGLComponent active before calling this. | |||||
| jassert (OpenGLHelpers::isContextActive()); | |||||
| jassert (isValidSize (w, h)); // Perhaps these dimensions must be a power-of-two? | jassert (isValidSize (w, h)); // Perhaps these dimensions must be a power-of-two? | ||||
| release(); | release(); | ||||