mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-25 02:04:23 +00:00
OpenGL development (OpenGLRenderer now more-or-less works)
This commit is contained in:
parent
0422e4ced9
commit
d1e4e9b9d0
9 changed files with 342 additions and 138 deletions
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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())];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -75,9 +75,11 @@ public:
|
|||
|
||||
#ifndef DOXYGEN
|
||||
class SavedState;
|
||||
class ScratchBufferManager;
|
||||
#endif
|
||||
|
||||
private:
|
||||
ScopedPointer<ScratchBufferManager> scratchBufferManager;
|
||||
RenderingHelpers::SavedStateStack<SavedState> stack;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue