Browse Source

OpenGL development (OpenGLRenderer now more-or-less works)

tags/2021-05-28
jules 13 years ago
parent
commit
d1e4e9b9d0
9 changed files with 342 additions and 138 deletions
  1. +18
    -7
      modules/juce_graphics/images/juce_Image.cpp
  2. +1
    -1
      modules/juce_graphics/native/juce_RenderingHelpers.h
  3. +4
    -0
      modules/juce_gui_basics/juce_gui_basics.cpp
  4. +116
    -12
      modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  5. +1
    -1
      modules/juce_opengl/native/juce_ios_OpenGLComponent.mm
  6. +19
    -2
      modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp
  7. +144
    -76
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
  8. +2
    -0
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
  9. +37
    -39
      modules/juce_opengl/opengl/juce_OpenGLTexture.cpp

+ 18
- 7
modules/juce_graphics/images/juce_Image.cpp View File

@@ -242,17 +242,28 @@ Image Image::convertedToFormat (PixelFormat newFormat) const
for (int y = 0; y < h; ++y)
{
const PixelARGB* src = (const PixelARGB*) srcData.getLinePointer(y);
uint8* dst = destData.getLinePointer (y);
const PixelARGB* const src = (const PixelARGB*) srcData.getLinePointer (y);
uint8* const dst = destData.getLinePointer (y);
for (int x = w; --x >= 0;)
{
*dst++ = src->getAlpha();
++src;
}
for (int x = 0; x < w; ++x)
dst[x] = src[x].getAlpha();
}
}
}
else if (image->format == SingleChannel && newFormat == Image::ARGB)
{
const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly);
const BitmapData srcData (*this, 0, 0, w, h);
for (int y = 0; y < h; ++y)
{
const PixelAlpha* const src = (const PixelAlpha*) srcData.getLinePointer (y);
PixelARGB* const dst = (PixelARGB*) destData.getLinePointer (y);
for (int x = 0; x < w; ++x)
dst[x].set (src[x]);
}
}
else
{
if (hasAlphaChannel())


+ 1
- 1
modules/juce_graphics/native/juce_RenderingHelpers.h View File

@@ -345,7 +345,7 @@ struct FloatRectangleRasterisingInfo
if (leftAlpha != 0) callback (totalLeft, totalTop, 1, totalBottom - totalTop, leftAlpha);
if (rightAlpha != 0) callback (right, totalTop, 1, totalBottom - totalTop, rightAlpha);
callback (left, top, 1, bottom - top, 255);
callback (left, top, right - left, bottom - top, 255);
}
inline bool isOnePixelWide() const noexcept { return right - left == 1 && leftAlpha + rightAlpha == 0; }


+ 4
- 0
modules/juce_gui_basics/juce_gui_basics.cpp View File

@@ -39,6 +39,10 @@
#include "../juce_core/native/juce_BasicNativeHeaders.h"
#include "juce_gui_basics.h"
#if JUCE_MODULE_AVAILABLE_juce_opengl
#include "../juce_opengl/juce_opengl.h"
#endif
//==============================================================================
#if JUCE_MAC
#import <WebKit/WebKit.h>


+ 116
- 12
modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -30,6 +30,10 @@ extern AppFocusChangeCallback appFocusChangeCallback;
typedef bool (*CheckEventBlockedByModalComps) (NSEvent*);
extern CheckEventBlockedByModalComps isEventBlockedByModalComps;
#if JUCE_MODULE_AVAILABLE_juce_opengl && ! defined (JUCE_OSX_OPENGL_RENDERER)
//#define JUCE_OSX_OPENGL_RENDERER 1
#endif
//==============================================================================
END_JUCE_NAMESPACE
@@ -100,8 +104,6 @@ END_JUCE_NAMESPACE
- (BOOL) resignFirstResponder;
- (BOOL) acceptsFirstResponder;
- (void) asyncRepaint: (id) rect;
- (NSArray*) getSupportedDragTypes;
- (BOOL) sendDragCallback: (int) type sender: (id <NSDraggingInfo>) sender;
- (NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender;
@@ -210,6 +212,10 @@ public:
virtual bool isOpaque();
virtual void drawRect (NSRect r);
#if JUCE_OSX_OPENGL_RENDERER
virtual void drawOpenGL();
#endif
virtual bool canBecomeKeyWindow();
virtual void becomeKeyWindow();
virtual bool windowShouldClose();
@@ -298,7 +304,7 @@ public:
//==============================================================================
NSWindow* window;
JuceNSView* view;
bool isSharedWindow, fullScreen, insideDrawRect, usingCoreGraphics, recursiveToFrontCall;
bool isSharedWindow, fullScreen, insideDrawRect, usingCoreGraphics, usingOpenGL, recursiveToFrontCall;
static ModifierKeys currentModifiers;
static ComponentPeer* currentlyFocusedPeer;
@@ -532,12 +538,6 @@ END_JUCE_NAMESPACE
owner->viewMovedToWindow();
}
- (void) asyncRepaint: (id) rect
{
NSRect* r = (NSRect*) [((NSData*) rect) bytes];
[self setNeedsDisplayInRect: *r];
}
//==============================================================================
- (void) keyDown: (NSEvent*) ev
{
@@ -849,6 +849,49 @@ END_JUCE_NAMESPACE
@end
//==============================================================================
#if JUCE_OSX_OPENGL_RENDERER
@interface JuceOpenGLLayer : CAOpenGLLayer
{
NSViewComponentPeer* owner;
}
- (JuceOpenGLLayer*) initWithPeer: (NSViewComponentPeer*) owner;
- (void) dealloc;
- (void) drawInCGLContext: (CGLContextObj) glContext
pixelFormat: (CGLPixelFormatObj) pixelFormat
forLayerTime: (CFTimeInterval) timeInterval
displayTime: (const CVTimeStamp*) timeStamp;
@end
@implementation JuceOpenGLLayer
- (JuceOpenGLLayer*) initWithPeer: (NSViewComponentPeer*) owner_
{
[super init];
owner = owner_;
return self;
}
- (void) dealloc
{
[super dealloc];
}
- (void) drawInCGLContext: (CGLContextObj) glContext
pixelFormat: (CGLPixelFormatObj) pixelFormat
forLayerTime: (CFTimeInterval) timeInterval
displayTime: (const CVTimeStamp*) timeStamp
{
owner->drawOpenGL();
}
@end
#endif
//==============================================================================
//==============================================================================
BEGIN_JUCE_NAMESPACE
@@ -926,6 +969,7 @@ NSViewComponentPeer::NSViewComponentPeer (Component* const component_,
#else
usingCoreGraphics (false),
#endif
usingOpenGL (false),
recursiveToFrontCall (false)
{
appFocusChangeCallback = appFocusChanged;
@@ -1051,7 +1095,13 @@ void NSViewComponentPeer::setBounds (int x, int y, int w, int h, bool isNowFullS
if ([view frame].size.width != r.size.width
|| [view frame].size.height != r.size.height)
[view setNeedsDisplay: true];
{
#if JUCE_OSX_OPENGL_RENDERER
if (usingOpenGL)
[[view layer] setNeedsDisplay: true];
#endif
[view setNeedsDisplay: true];
}
[view setFrame: r];
}
@@ -1061,6 +1111,11 @@ void NSViewComponentPeer::setBounds (int x, int y, int w, int h, bool isNowFullS
[window setFrame: [window frameRectForContentRect: r]
display: true];
#if JUCE_OSX_OPENGL_RENDERER
if (usingOpenGL)
[[view layer] setFrame: CGRectMake (0, 0, [view frame].size.width, [view frame].size.height)];
#endif
}
}
@@ -1611,6 +1666,21 @@ static void getClipRects (RectangleList& clip, NSView* view,
roundToInt (rects[i].size.height))));
}
#if JUCE_OSX_OPENGL_RENDERER
void NSViewComponentPeer::drawOpenGL()
{
if (! component->isOpaque())
OpenGLHelpers::clear (Colours::transparentBlack);
OpenGLRenderer context (OpenGLFrameBuffer::getCurrentFrameBufferTarget(),
component->getWidth(), component->getHeight());
insideDrawRect = true;
handlePaint (context);
insideDrawRect = false;
}
#endif
void NSViewComponentPeer::drawRect (NSRect r)
{
if (r.size.width < 1.0f || r.size.height < 1.0f)
@@ -1672,16 +1742,44 @@ StringArray NSViewComponentPeer::getAvailableRenderingEngines()
s.add ("CoreGraphics Renderer");
#endif
#if JUCE_OSX_OPENGL_RENDERER
s.add ("OpenGL Renderer");
#endif
return s;
}
int NSViewComponentPeer::getCurrentRenderingEngine() const
{
#if JUCE_OSX_OPENGL_RENDERER
if (usingOpenGL) return 2;
#endif
return usingCoreGraphics ? 1 : 0;
}
void NSViewComponentPeer::setCurrentRenderingEngine (int index)
{
#if JUCE_OSX_OPENGL_RENDERER
if (index == 2)
{
usingCoreGraphics = false;
usingOpenGL = true;
JuceOpenGLLayer* glLayer = [[JuceOpenGLLayer alloc] initWithPeer: this];
[view setLayer: glLayer];
[view setWantsLayer: YES];
[glLayer release];
}
else
{
usingOpenGL = false;
[view setLayer: nil];
[view setWantsLayer: NO];
}
#endif
#if USE_COREGRAPHICS_RENDERING
if (usingCoreGraphics != (index > 0))
{
@@ -1802,8 +1900,14 @@ void NSViewComponentPeer::repaint (const Rectangle<int>& area)
}
else
{
[view setNeedsDisplayInRect: NSMakeRect ((CGFloat) area.getX(), [view frame].size.height - (CGFloat) area.getBottom(),
(CGFloat) area.getWidth(), (CGFloat) area.getHeight())];
#if JUCE_OSX_OPENGL_RENDERER
if (usingOpenGL)
[[view layer] setNeedsDisplayInRect: CGRectMake ((CGFloat) area.getX(), [view frame].size.height - (CGFloat) area.getBottom(),
(CGFloat) area.getWidth(), (CGFloat) area.getHeight())];
else
#endif
[view setNeedsDisplayInRect: NSMakeRect ((CGFloat) area.getX(), [view frame].size.height - (CGFloat) area.getBottom(),
(CGFloat) area.getWidth(), (CGFloat) area.getHeight())];
}
}


+ 1
- 1
modules/juce_opengl/native/juce_ios_OpenGLComponent.mm View File

@@ -50,7 +50,7 @@ public:
const GLESContext* const sharedContext,
NSUInteger apiType)
: component (component_), glLayer (nil), context (nil),
useDepthBuffer (pixelFormat_.depthBufferBits > 0),
useDepthBuffer (pixelFormat.depthBufferBits > 0),
frameBufferHandle (0), colorBufferHandle (0),
depthBufferHandle (0), lastWidth (0), lastHeight (0)
{


+ 19
- 2
modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp View File

@@ -30,6 +30,7 @@ enum
{
GL_FRAMEBUFFER_EXT = 0x8D40,
GL_RENDERBUFFER_EXT = 0x8D41,
GL_FRAMEBUFFER_BINDING_EXT = 0x8CA6,
GL_COLOR_ATTACHMENT0_EXT = 0x8CE0,
GL_DEPTH_ATTACHMENT_EXT = 0x8D00,
GL_STENCIL_ATTACHMENT_EXT = 0x8D20,
@@ -100,6 +101,7 @@ static void initialiseFrameBufferFunctions()
#define glGenerateMipmapEXT glGenerateMipmapOES
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_OES
#define GL_RGBA8 GL_RGBA
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER_OES
@@ -398,7 +400,6 @@ bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int>
#if JUCE_OPENGL_ES
{
// GLES has no glDrawPixels function, so we have to create a texture and draw it..
glEnable (GL_TEXTURE_2D);
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
@@ -417,7 +418,23 @@ bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int>
OpenGLTexture tex;
tex.load (data, area.getWidth(), area.getHeight());
OpenGLHelpers::fillRectWithTexture (area.withSize (tex.getWidth(), tex.getHeight()), tex.getTextureID(), 1.0f);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
const int x = area.getX();
const int texH = tex.getHeight();
const int y = area.getY() - (texH - area.getHeight());
const GLfloat x1 = (GLfloat) x;
const GLfloat y1 = (GLfloat) y;
const GLfloat x2 = (GLfloat) (x + tex.getWidth());
const GLfloat y2 = (GLfloat) (y + texH);
const GLfloat vertices[] = { x1, y1, x2, y1, x1, y2, x2, y2 };
const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f };
OpenGLHelpers::drawTriangleStrip (vertices, textureCoords, 4, tex.getTextureID());
}
#endif


+ 144
- 76
modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp View File

@@ -25,16 +25,6 @@
BEGIN_JUCE_NAMESPACE
namespace
{
void applyFlippedMatrix (int x, int y, int width, int height)
{
OpenGLHelpers::prepareFor2D (width, height);
OpenGLHelpers::applyTransform (AffineTransform::translation ((float) -x, (float) -y)
.followedBy (AffineTransform::verticalFlip ((float) height)));
}
}
struct OpenGLTarget
{
OpenGLTarget (GLuint frameBufferID_, int width_, int height_) noexcept
@@ -69,6 +59,20 @@ struct OpenGLTarget
OpenGLHelpers::enableScissorTest (r.withY (height - r.getBottom()));
}
static void applyFlippedMatrix (const int x, const int y, const int width, const int height)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
#if JUCE_OPENGL_ES
glOrthof ((GLfloat) x, (GLfloat) (x + width), (GLfloat) (y + height), (GLfloat) y, 0.0f, 1.0f);
#else
glOrtho (x, x + width, y + height, y, 0, 1);
#endif
glViewport (0, 0, width, height);
}
OpenGLFrameBuffer* frameBuffer;
GLuint frameBufferID;
int x, y, width, height;
@@ -170,6 +174,11 @@ namespace
1.0f / textureHeight));
t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
textureCoords[1] = 1.0f - textureCoords[1];
textureCoords[3] = 1.0f - textureCoords[3];
textureCoords[5] = 1.0f - textureCoords[5];
textureCoords[7] = 1.0f - textureCoords[7];
}
glVertexPointer (2, GL_FLOAT, 0, vertices);
@@ -342,9 +351,6 @@ namespace
void fillRectWithFillType (const OpenGLTarget& target, const Rectangle<int>& rect,
const FillType& fill, const bool replaceExistingContents)
{
jassert (! fill.isInvisible());
jassert (! fill.isColour());
if (fill.isGradient())
{
target.makeActiveFor2D();
@@ -370,13 +376,48 @@ namespace
}
}
//==============================================================================
class OpenGLRenderer::ScratchBufferManager
{
public:
ScratchBufferManager() {}
OpenGLFrameBuffer* get (int width, int height)
{
for (int i = 0; i < buffers.size(); ++i)
{
OpenGLFrameBuffer* b = buffers.getUnchecked(i);
if (width <= b->getWidth() && height <= b->getHeight())
return buffers.removeAndReturn (i);
}
OpenGLFrameBuffer* b = new OpenGLFrameBuffer();
b->initialise (width, height);
return b;
}
void release (OpenGLFrameBuffer* buffer)
{
buffers.add (buffer);
if (buffers.size() > 10)
buffers.remove (0);
}
private:
OwnedArray<OpenGLFrameBuffer> buffers;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScratchBufferManager);
};
class ClipRegion_Mask;
//==============================================================================
class ClipRegionBase : public SingleThreadedReferenceCountedObject
{
public:
ClipRegionBase() noexcept {}
ClipRegionBase (OpenGLRenderer::ScratchBufferManager& scratchBuffer_) noexcept : scratchBuffer (scratchBuffer_) {}
virtual ~ClipRegionBase() {}
typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
@@ -394,6 +435,11 @@ public:
virtual void fillAll (const OpenGLTarget&, const FillType& fill, bool replaceContents) = 0;
virtual void fillRect (const OpenGLTarget&, const Rectangle<int>& area, const FillType& fill, bool replaceContents) = 0;
virtual void drawImage (const OpenGLTarget&, const OpenGLTextureFromImage&, float alpha, const Rectangle<int>& targetArea) = 0;
OpenGLRenderer::ScratchBufferManager& scratchBuffer;
private:
JUCE_DECLARE_NON_COPYABLE (ClipRegionBase);
};
//==============================================================================
@@ -401,24 +447,31 @@ class ClipRegion_Mask : public ClipRegionBase
{
public:
ClipRegion_Mask (const ClipRegion_Mask& other)
: clip (other.clip),
maskOrigin (other.maskOrigin)
: ClipRegionBase (other.scratchBuffer),
clip (other.clip),
maskOrigin (other.clip.getPosition())
{
const bool ok = mask.initialise (other.mask);
(void) ok; jassert (ok);
mask = scratchBuffer.get (clip.getWidth(), clip.getHeight());
OpenGLTarget m (*mask, maskOrigin);
m.makeActiveFor2D();
glDisable (GL_BLEND);
setColour (1.0f);
drawFrameBuffer (*(other.mask), other.maskOrigin);
}
explicit ClipRegion_Mask (const Rectangle<int>& r)
: clip (r),
explicit ClipRegion_Mask (const Rectangle<int>& r, OpenGLRenderer::ScratchBufferManager& scratchBuffer_)
: ClipRegionBase (scratchBuffer_),
clip (r),
maskOrigin (r.getPosition())
{
const bool ok = mask.initialise (r.getWidth(), r.getHeight());
(void) ok; jassert (ok);
mask.clear (Colours::white);
mask = scratchBuffer_.get (r.getWidth(), r.getHeight());
mask->clear (Colours::white);
}
explicit ClipRegion_Mask (const Rectangle<float>& r)
: clip (r.getSmallestIntegerContainer()),
explicit ClipRegion_Mask (const Rectangle<float>& r, OpenGLRenderer::ScratchBufferManager& scratchBuffer_)
: ClipRegionBase (scratchBuffer_),
clip (r.getSmallestIntegerContainer()),
maskOrigin (clip.getPosition())
{
initialiseClear();
@@ -431,27 +484,36 @@ public:
fr.iterate (callback);
}
explicit ClipRegion_Mask (const EdgeTable& e)
: clip (e.getMaximumBounds()),
explicit ClipRegion_Mask (const EdgeTable& e, OpenGLRenderer::ScratchBufferManager& scratchBuffer_)
: ClipRegionBase (scratchBuffer_),
clip (e.getMaximumBounds()),
maskOrigin (clip.getPosition())
{
initialiseClear();
OpenGLHelpers::fillEdgeTable (e);
}
ClipRegion_Mask (const Rectangle<int>& bounds, const Path& p, const AffineTransform& transform, int oversamplingLevel)
: clip (bounds), maskOrigin (clip.getPosition())
ClipRegion_Mask (OpenGLRenderer::ScratchBufferManager& scratchBuffer_, const Rectangle<int>& bounds,
const Path& p, const AffineTransform& transform, int oversamplingLevel)
: ClipRegionBase (scratchBuffer_),
clip (bounds), maskOrigin (clip.getPosition())
{
initialiseClear();
renderPath (p, transform, oversamplingLevel);
}
static ClipRegion_Mask* createFromPath (Rectangle<int> bounds, const Path& p, const AffineTransform& transform)
~ClipRegion_Mask()
{
scratchBuffer.release (mask);
}
static ClipRegion_Mask* createFromPath (OpenGLRenderer::ScratchBufferManager& scratchBuffer, Rectangle<int> bounds,
const Path& p, const AffineTransform& transform)
{
bounds = bounds.getIntersection (p.getBoundsTransformed (transform).getSmallestIntegerContainer());
return bounds.isEmpty() ? nullptr
: new ClipRegion_Mask (bounds, p, transform, (int) defaultOversamplingLevel);
: new ClipRegion_Mask (scratchBuffer, bounds, p, transform, (int) defaultOversamplingLevel);
}
Ptr clone() const { return new ClipRegion_Mask (*this); }
@@ -500,14 +562,14 @@ public:
Ptr clipToPath (const Path& p, const AffineTransform& t)
{
ClipRegion_Mask* tempMask = createFromPath (clip, p, t);
ClipRegion_Mask* tempMask = createFromPath (scratchBuffer, clip, p, t);
const Ptr tempMaskPtr (tempMask);
return tempMask == nullptr ? nullptr : clipToMask (tempMask);
}
Ptr clipToEdgeTable (const EdgeTable& et)
{
ClipRegion_Mask* const tempMask = new ClipRegion_Mask (et);
ClipRegion_Mask* const tempMask = new ClipRegion_Mask (et, scratchBuffer);
const Ptr tempMaskPtr (tempMask);
return clipToMask (tempMask);
}
@@ -520,7 +582,7 @@ public:
if (clip.isEmpty())
return nullptr;
clipFrameBuffers (OpenGLTarget (mask, maskOrigin), m->mask, m->maskOrigin);
clipFrameBuffers (OpenGLTarget (*mask, maskOrigin), *(m->mask), m->maskOrigin);
return this;
}
@@ -529,9 +591,7 @@ public:
makeMaskActive();
glEnable (GL_BLEND);
glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
fillMaskWithSourceImage (image, transform);
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
return this;
}
@@ -555,21 +615,22 @@ public:
if (fill.isColour())
{
target.makeActiveFor2D();
setBlendMode (replaceContents);
OpenGLHelpers::setColour (fill.colour);
PixelARGB p (fill.colour.getARGB());
p.premultiply();
OpenGLHelpers::setColour (Colour (p.getARGB()));
target.scissor (area);
drawFrameBuffer (mask, maskOrigin);
drawFrameBuffer (*mask, maskOrigin);
glDisable (GL_SCISSOR_TEST);
}
else
{
OpenGLFrameBuffer patternBuffer;
bool ok = patternBuffer.initialise (area.getWidth(), area.getHeight());
(void) ok; jassert (ok);
OpenGLFrameBuffer* patternBuffer = scratchBuffer.get (area.getWidth(), area.getHeight());
fillRectWithFillType (OpenGLTarget (patternBuffer, area.getPosition()), area, fill, true);
clipAndDraw (target, OpenGLTarget (patternBuffer, area.getPosition()));
fillRectWithFillType (OpenGLTarget (*patternBuffer, area.getPosition()), area, fill, true);
clipAndDraw (target, OpenGLTarget (*patternBuffer, area.getPosition()), area);
scratchBuffer.release (patternBuffer);
}
}
@@ -579,16 +640,16 @@ public:
if (! bufferArea.isEmpty())
{
OpenGLFrameBuffer buffer;
bool ok = buffer.initialise (bufferArea.getWidth(), bufferArea.getHeight());
(void) ok; jassert (ok);
OpenGLFrameBuffer* buffer = scratchBuffer.get (bufferArea.getWidth(), bufferArea.getHeight());
OpenGLTarget bufferTarget (buffer, bufferArea.getPosition());
OpenGLTarget bufferTarget (*buffer, bufferArea.getPosition());
bufferTarget.makeActiveFor2D();
glDisable (GL_BLEND);
OpenGLHelpers::fillRectWithTexture (targetArea, source.textureID, alpha);
clipAndDraw (target, bufferTarget);
clipAndDraw (target, bufferTarget, bufferArea);
scratchBuffer.release (buffer);
}
}
@@ -603,22 +664,24 @@ public:
target.makeActiveFor2D();
setColour (alpha);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawFrameBuffer (mask, maskOrigin);
target.scissor (clip);
drawFrameBuffer (*mask, maskOrigin);
glDisable (GL_SCISSOR_TEST);
}
private:
OpenGLFrameBuffer mask;
OpenGLFrameBuffer* mask;
Rectangle<int> clip;
Point<int> maskOrigin;
void prepareFor2D() const
{
applyFlippedMatrix (maskOrigin.getX(), maskOrigin.getY(), mask.getWidth(), mask.getHeight());
OpenGLTarget::applyFlippedMatrix (maskOrigin.getX(), maskOrigin.getY(), mask->getWidth(), mask->getHeight());
}
void makeMaskActive()
{
const bool b = mask.makeCurrentRenderingTarget();
const bool b = mask->makeCurrentRenderingTarget();
(void) b; jassert (b);
prepareFor2D();
}
@@ -626,9 +689,8 @@ private:
void initialiseClear()
{
jassert (! clip.isEmpty());
bool ok = mask.initialise (clip.getWidth(), clip.getHeight());
mask.makeCurrentAndClear();
(void) ok; jassert (ok);
mask = scratchBuffer.get (clip.getWidth(), clip.getHeight());
mask->makeCurrentAndClear();
glDisable (GL_TEXTURE_2D);
glDisable (GL_BLEND);
prepareFor2D();
@@ -650,16 +712,18 @@ private:
}
};
void clipAndDraw (const OpenGLTarget& target, const OpenGLTarget& buffer)
void clipAndDraw (const OpenGLTarget& target, const OpenGLTarget& buffer, const Rectangle<int>& clip)
{
clipFrameBuffers (buffer, mask, maskOrigin);
clipFrameBuffers (buffer, *mask, maskOrigin);
target.makeActiveFor2D();
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
setColour (1.0f);
target.scissor (clip);
drawFrameBuffer (*buffer.frameBuffer, Point<int> (buffer.x, buffer.y));
glDisable (GL_SCISSOR_TEST);
}
void drawFrameBuffer (const OpenGLFrameBuffer& buffer, const Point<int>& topLeft)
@@ -679,8 +743,8 @@ private:
const GLfloat l = (GLfloat) maskOrigin.getX();
const GLfloat t = (GLfloat) maskOrigin.getY();
const GLfloat r = (GLfloat) (maskOrigin.getX() + mask.getWidth());
const GLfloat b = (GLfloat) (maskOrigin.getY() + mask.getHeight());
const GLfloat r = (GLfloat) (maskOrigin.getX() + mask->getWidth());
const GLfloat b = (GLfloat) (maskOrigin.getY() + mask->getHeight());
const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
@@ -706,11 +770,12 @@ private:
class ClipRegion_Rectangle : public ClipRegionBase
{
public:
explicit ClipRegion_Rectangle (const Rectangle<int>& r) noexcept
: clip (r)
explicit ClipRegion_Rectangle (const Rectangle<int>& r, OpenGLRenderer::ScratchBufferManager& scratchBuffer_) noexcept
: ClipRegionBase (scratchBuffer_),
clip (r)
{}
Ptr clone() const { return new ClipRegion_Rectangle (clip); }
Ptr clone() const { return new ClipRegion_Rectangle (clip, scratchBuffer); }
const Rectangle<int>& getClipBounds() const { return clip; }
Ptr applyClipTo (const Ptr& target) { return target->clipToRectangle (clip); }
@@ -784,7 +849,7 @@ private:
Ptr toMask() const
{
return new ClipRegion_Mask (clip);
return new ClipRegion_Mask (clip, scratchBuffer);
}
ClipRegion_Rectangle& operator= (const ClipRegion_Rectangle&);
@@ -795,8 +860,8 @@ private:
class OpenGLRenderer::SavedState
{
public:
SavedState (const OpenGLTarget& target_)
: clip (new ClipRegion_Rectangle (Rectangle<int> (target_.width, target_.height))),
SavedState (const OpenGLTarget& target_, ScratchBufferManager& scratchBuffer)
: clip (new ClipRegion_Rectangle (Rectangle<int> (target_.width, target_.height), scratchBuffer)),
transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
target (target_), transparencyLayerAlpha (1.0f)
{
@@ -965,7 +1030,7 @@ public:
if (transform.isOnlyTranslated)
{
fillShape (new ClipRegion_Mask (r.translated ((float) transform.xOffset,
(float) transform.yOffset)), false);
(float) transform.yOffset), clip->scratchBuffer), false);
}
else
{
@@ -980,7 +1045,7 @@ public:
{
if (clip != nullptr)
{
ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->getClipBounds(), path,
ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->scratchBuffer, clip->getClipBounds(), path,
transform.getTransformWith (t));
if (m != nullptr)
@@ -1008,7 +1073,7 @@ public:
.followedBy (t))));
if (et != nullptr)
fillShape (new ClipRegion_Mask (*et), false);
fillShape (new ClipRegion_Mask (*et, clip->scratchBuffer), false);
}
}
}
@@ -1017,7 +1082,7 @@ public:
{
EdgeTable et2 (et);
et2.translate (x, y);
fillShape (new ClipRegion_Mask (et2), false);
fillShape (new ClipRegion_Mask (et2, clip->scratchBuffer), false);
}
void drawLine (const Line <float>& line)
@@ -1069,7 +1134,7 @@ public:
Path p;
p.addRectangle (image.getBounds());
ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->getClipBounds(), p, t);
ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->scratchBuffer, clip->getClipBounds(), p, t);
if (m != nullptr)
{
@@ -1152,20 +1217,23 @@ private:
//==============================================================================
OpenGLRenderer::OpenGLRenderer (OpenGLComponent& target)
: stack (new SavedState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight())))
: scratchBufferManager (new ScratchBufferManager()),
stack (new SavedState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight()), *scratchBufferManager))
{
target.makeCurrentRenderingTarget();
}
OpenGLRenderer::OpenGLRenderer (OpenGLFrameBuffer& target)
: stack (new SavedState (OpenGLTarget (target, Point<int>())))
: scratchBufferManager (new ScratchBufferManager()),
stack (new SavedState (OpenGLTarget (target, Point<int>()), *scratchBufferManager))
{
// This object can only be created and used when the current thread has an active OpenGL context.
jassert (OpenGLHelpers::isContextActive());
}
OpenGLRenderer::OpenGLRenderer (unsigned int frameBufferID, int width, int height)
: stack (new SavedState (OpenGLTarget (frameBufferID, width, height)))
: scratchBufferManager (new ScratchBufferManager()),
stack (new SavedState (OpenGLTarget (frameBufferID, width, height), *scratchBufferManager))
{
// This object can only be created and used when the current thread has an active OpenGL context.
jassert (OpenGLHelpers::isContextActive());
@@ -1195,8 +1263,8 @@ void OpenGLRenderer::setInterpolationQuality (Graphics::ResamplingQuality qualit
void OpenGLRenderer::fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
void OpenGLRenderer::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
void OpenGLRenderer::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
void OpenGLRenderer::drawVerticalLine (int x, float top, float bottom) { stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
void OpenGLRenderer::drawHorizontalLine (int y, float left, float right) { stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
void OpenGLRenderer::drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
void OpenGLRenderer::drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
void OpenGLRenderer::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
void OpenGLRenderer::drawLine (const Line <float>& line) { stack->drawLine (line); }
void OpenGLRenderer::setFont (const Font& newFont) { stack->font = newFont; }


+ 2
- 0
modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h View File

@@ -75,9 +75,11 @@ public:
#ifndef DOXYGEN
class SavedState;
class ScratchBufferManager;
#endif
private:
ScopedPointer<ScratchBufferManager> scratchBufferManager;
RenderingHelpers::SavedStateStack<SavedState> stack;
};


+ 37
- 39
modules/juce_opengl/opengl/juce_OpenGLTexture.cpp View File

@@ -75,6 +75,27 @@ void OpenGLTexture::create (const int w, const int h, const void* pixels)
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
}
template <class PixelType>
struct Flipper
{
static void flip (HeapBlock<PixelARGB>& dataCopy, const uint8* srcData, const int lineStride,
const int w, const int h, const int textureW, const int textureH)
{
dataCopy.malloc (textureW * textureH);
for (int y = 0; y < h; ++y)
{
const PixelType* src = (const PixelType*) srcData;
PixelARGB* const dst = (PixelARGB*) (dataCopy + textureW * (textureH - 1 - y));
for (int x = 0; x < w; ++x)
dst[x].set (src[x]);
srcData += lineStride;
}
}
};
void OpenGLTexture::load (const Image& image)
{
const int imageW = image.getWidth();
@@ -82,59 +103,36 @@ void OpenGLTexture::load (const Image& image)
const int textureW = nextPowerOfTwo (imageW);
const int textureH = nextPowerOfTwo (imageH);
Image::BitmapData srcData (image, Image::BitmapData::readOnly);
const PixelARGB* data = (const PixelARGB*) srcData.data;
HeapBlock<PixelARGB> dataCopy;
Image::BitmapData srcData (image, Image::BitmapData::readOnly);
if (srcData.pixelFormat != Image::ARGB
|| textureW != imageW
|| textureH != imageH
|| srcData.lineStride != imageW * srcData.pixelStride)
switch (srcData.pixelFormat)
{
const int srcLineStride = (srcData.pixelStride * imageW + 3) & ~3;
dataCopy.malloc (textureW * textureH);
data = dataCopy;
const int yOffset = textureH - imageH;
if (srcData.pixelFormat == Image::RGB)
{
for (int y = 0; y < imageH; ++y)
{
const PixelRGB* const src = (const PixelRGB*) addBytesToPointer (srcData.data, srcLineStride * y);
PixelARGB* const dst = (PixelARGB*) (dataCopy + textureW * (y + yOffset));
for (int x = 0; x < imageW; ++x)
dst[x].set (src[x]);
}
}
else if (srcData.pixelFormat == Image::ARGB)
{
for (int y = 0; y < imageH; ++y)
memcpy (dataCopy + textureW * (y + yOffset), addBytesToPointer (srcData.data, srcLineStride * y), srcLineStride);
}
case Image::ARGB: Flipper<PixelARGB> ::flip (dataCopy, srcData.data, srcData.lineStride, imageW, imageH, textureW, textureH); break;
case Image::RGB: Flipper<PixelRGB> ::flip (dataCopy, srcData.data, srcData.lineStride, imageW, imageH, textureW, textureH); break;
case Image::SingleChannel: Flipper<PixelAlpha>::flip (dataCopy, srcData.data, srcData.lineStride, imageW, imageH, textureW, textureH); break;
default: break;
}
create (textureW, textureH, data);
create (textureW, textureH, dataCopy);
}
void OpenGLTexture::load (const PixelARGB* pixels, const int w, const int h)
{
const int textureW = nextPowerOfTwo (w);
const int textureH = nextPowerOfTwo (h);
HeapBlock<PixelARGB> dataCopy;
if (textureW != w || textureH != h)
if (h == 1 && textureW == w)
{
dataCopy.malloc (textureW * textureH);
for (int y = 0; y < h; ++y)
memcpy (dataCopy + textureW * (y + textureH - h), pixels + w * y, w * 4);
pixels = dataCopy;
create (w, 1, pixels);
}
else
{
const int textureH = nextPowerOfTwo (h);
create (textureW, textureH, pixels);
HeapBlock<PixelARGB> dataCopy;
Flipper<PixelARGB>::flip (dataCopy, (const uint8*) pixels, 4 * w, w, h, textureW, textureH);
create (textureW, textureH, dataCopy);
}
}
void OpenGLTexture::release()


Loading…
Cancel
Save