mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-30 02:50:05 +00:00
More OpenGL work.
This commit is contained in:
parent
61f5ca11ab
commit
f31dca5f2f
30 changed files with 562 additions and 101 deletions
|
|
@ -415,6 +415,15 @@ inline int roundFloatToInt (const float value) noexcept
|
|||
return roundToInt (value);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the specified integer is a power-of-two.
|
||||
*/
|
||||
template <typename IntegerType>
|
||||
bool isPowerOfTwo (IntegerType value)
|
||||
{
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN)
|
||||
/** This macro can be applied to a float variable to check whether it contains a denormalised
|
||||
|
|
|
|||
|
|
@ -157,14 +157,14 @@ AffineTransform AffineTransform::scale (const float factorX, const float factorY
|
|||
}
|
||||
|
||||
AffineTransform AffineTransform::scaled (const float factorX, const float factorY,
|
||||
const float pivotX, const float pivotY) const noexcept
|
||||
const float pivotX, const float pivotY) const noexcept
|
||||
{
|
||||
return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02 + pivotX * (1.0f - factorX),
|
||||
factorY * mat10, factorY * mat11, factorY * mat12 + pivotY * (1.0f - factorY));
|
||||
}
|
||||
|
||||
AffineTransform AffineTransform::scale (const float factorX, const float factorY,
|
||||
const float pivotX, const float pivotY) noexcept
|
||||
const float pivotX, const float pivotY) noexcept
|
||||
{
|
||||
return AffineTransform (factorX, 0, pivotX * (1.0f - factorX),
|
||||
0, factorY, pivotY * (1.0f - factorY));
|
||||
|
|
@ -186,6 +186,11 @@ AffineTransform AffineTransform::sheared (const float shearX, const float shearY
|
|||
shearY * mat02 + mat12);
|
||||
}
|
||||
|
||||
AffineTransform AffineTransform::verticalFlip (const float height) noexcept
|
||||
{
|
||||
return AffineTransform (1.0f, 0, 0, 0, -1.0f, height);
|
||||
}
|
||||
|
||||
AffineTransform AffineTransform::inverted() const noexcept
|
||||
{
|
||||
double determinant = (mat00 * mat11 - mat10 * mat01);
|
||||
|
|
|
|||
|
|
@ -185,6 +185,11 @@ public:
|
|||
/** Returns a shear transform, centred around the origin (0, 0). */
|
||||
static AffineTransform shear (float shearX, float shearY) noexcept;
|
||||
|
||||
/** Returns a transform that will flip co-ordinates vertically within a window of the given height.
|
||||
This is handy for converting between upside-down coordinate systems such as OpenGL or CoreGraphics.
|
||||
*/
|
||||
static AffineTransform verticalFlip (float height) noexcept;
|
||||
|
||||
/** Returns a matrix which is the inverse operation of this one.
|
||||
|
||||
Some matrices don't have an inverse - in this case, the method will just return
|
||||
|
|
|
|||
|
|
@ -116,7 +116,16 @@ public:
|
|||
|
||||
Image::SharedImage* clone()
|
||||
{
|
||||
return new SubsectionSharedImage (image->clone(), area);
|
||||
Image newImage (format, area.getWidth(), area.getHeight(),
|
||||
format != Image::RGB, image->getType());
|
||||
|
||||
{
|
||||
Graphics g (newImage);
|
||||
g.drawImageAt (Image (this), 0, 0);
|
||||
}
|
||||
|
||||
newImage.getSharedImage()->incReferenceCount();
|
||||
return newImage.getSharedImage();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -169,8 +169,7 @@ void CoreGraphicsContext::setOrigin (int x, int y)
|
|||
|
||||
void CoreGraphicsContext::addTransform (const AffineTransform& transform)
|
||||
{
|
||||
applyTransform (AffineTransform::scale (1.0f, -1.0f)
|
||||
.translated (0, flipHeight)
|
||||
applyTransform (AffineTransform::verticalFlip (flipHeight)
|
||||
.followedBy (transform)
|
||||
.translated (0, -flipHeight)
|
||||
.scaled (1.0f, -1.0f));
|
||||
|
|
@ -253,7 +252,7 @@ void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const Affi
|
|||
CGImageRef image = CoreGraphicsImage::createImage (singleChannelImage, true, greyColourSpace, true);
|
||||
|
||||
flip();
|
||||
AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform));
|
||||
AffineTransform t (AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform));
|
||||
applyTransform (t);
|
||||
|
||||
CGRect r = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight());
|
||||
|
|
@ -447,7 +446,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
|
|||
CGContextSetAlpha (context, state->fillType.getOpacity());
|
||||
|
||||
flip();
|
||||
applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, ih).followedBy (transform));
|
||||
applyTransform (AffineTransform::verticalFlip (ih).followedBy (transform));
|
||||
CGRect imageRect = CGRectMake (0, 0, iw, ih);
|
||||
|
||||
if (fillEntireClipAsTiles)
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
|
||||
//=============================================================================
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
#include "opengl/juce_OpenGLRenderingTarget.h"
|
||||
|
||||
// START_AUTOINCLUDE opengl
|
||||
#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__
|
||||
|
|
@ -101,6 +102,9 @@ BEGIN_JUCE_NAMESPACE
|
|||
#ifndef __JUCE_OPENGLPIXELFORMAT_JUCEHEADER__
|
||||
#include "opengl/juce_OpenGLPixelFormat.h"
|
||||
#endif
|
||||
#ifndef __JUCE_OPENGLRENDERINGTARGET_JUCEHEADER__
|
||||
#include "opengl/juce_OpenGLRenderingTarget.h"
|
||||
#endif
|
||||
#ifndef __JUCE_OPENGLTEXTURE_JUCEHEADER__
|
||||
#include "opengl/juce_OpenGLTexture.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ OpenGLContext* OpenGLContext::getCurrentContext()
|
|||
class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
OpenGLComponentWatcher (OpenGLComponent* const owner_)
|
||||
: ComponentMovementWatcher (owner_),
|
||||
owner (owner_)
|
||||
|
|
@ -145,7 +144,6 @@ public:
|
|||
owner->stopBackgroundThread();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
OpenGLComponent* const owner;
|
||||
|
||||
|
|
@ -276,22 +274,17 @@ void OpenGLComponent::recreateContextAsync()
|
|||
repaint();
|
||||
}
|
||||
|
||||
bool OpenGLComponent::makeCurrentContextActive()
|
||||
bool OpenGLComponent::makeCurrentRenderingTarget()
|
||||
{
|
||||
return context != nullptr && context->makeActive();
|
||||
}
|
||||
|
||||
void OpenGLComponent::makeCurrentContextInactive()
|
||||
void OpenGLComponent::releaseAsRenderingTarget()
|
||||
{
|
||||
if (context != nullptr)
|
||||
context->makeInactive();
|
||||
}
|
||||
|
||||
bool OpenGLComponent::isActiveContext() const noexcept
|
||||
{
|
||||
return context != nullptr && context->isActive();
|
||||
}
|
||||
|
||||
void OpenGLComponent::swapBuffers()
|
||||
{
|
||||
if (context != nullptr)
|
||||
|
|
@ -416,7 +409,7 @@ bool OpenGLComponent::renderAndSwapBuffers()
|
|||
|
||||
if (context != nullptr)
|
||||
{
|
||||
if (! makeCurrentContextActive())
|
||||
if (! makeCurrentRenderingTarget())
|
||||
return false;
|
||||
|
||||
if (needToUpdateViewport)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
method to draw its contents.
|
||||
|
||||
*/
|
||||
class JUCE_API OpenGLComponent : public OpenGLBaseType
|
||||
class JUCE_API OpenGLComponent : public OpenGLBaseType,
|
||||
public OpenGLRenderingTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -160,10 +161,7 @@ public:
|
|||
*/
|
||||
OpenGLContext* getCurrentContext() const noexcept { return context; }
|
||||
|
||||
/** Makes this component the current openGL context.
|
||||
|
||||
You might want to use this in things like your resize() method, before calling
|
||||
GL commands.
|
||||
/** Makes this component the currently active openGL context.
|
||||
|
||||
If this returns false, then the context isn't active, so you should avoid
|
||||
making any calls.
|
||||
|
|
@ -172,25 +170,18 @@ public:
|
|||
it does this, it will also synchronously call the newOpenGLContextCreated()
|
||||
method to let you initialise it as necessary.
|
||||
|
||||
@see OpenGLContext::makeActive
|
||||
@see releaseAsRenderingTarget
|
||||
*/
|
||||
bool makeCurrentContextActive();
|
||||
bool makeCurrentRenderingTarget();
|
||||
|
||||
/** Stops the current component being the active OpenGL context.
|
||||
|
||||
This is the opposite of makeCurrentContextActive()
|
||||
|
||||
@see OpenGLContext::makeInactive
|
||||
This is the opposite of makeCurrentRenderingTarget()
|
||||
@see makeCurrentRenderingTarget
|
||||
*/
|
||||
void makeCurrentContextInactive();
|
||||
|
||||
/** Returns true if this component's context is the active openGL context for the
|
||||
current thread.
|
||||
|
||||
@see OpenGLContext::isActive
|
||||
*/
|
||||
bool isActiveContext() const noexcept;
|
||||
void releaseAsRenderingTarget();
|
||||
|
||||
int getRenderingTargetWidth() const { return getWidth(); }
|
||||
int getRenderingTargetHeight() const { return getHeight(); }
|
||||
|
||||
//==============================================================================
|
||||
/** Calls the rendering callback, and swaps the buffers afterwards.
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public:
|
|||
|
||||
/** Returns an OS-dependent handle to the raw GL context.
|
||||
|
||||
On win32, this will be a HGLRC; on the Mac, an AGLContext; on Linux,
|
||||
On win32, this will be a HGLRC; on the Mac, an NSOpenGLContext; on Linux,
|
||||
a GLXContext.
|
||||
*/
|
||||
virtual void* getRawContext() const noexcept = 0;
|
||||
|
|
|
|||
|
|
@ -258,14 +258,14 @@ public:
|
|||
: width (w), height (h),
|
||||
data (w * h)
|
||||
{
|
||||
buffer.readPixels (data, 0, Rectangle<int> (0, 0, w, h));
|
||||
buffer.readPixels (data, Rectangle<int> (0, 0, w, h));
|
||||
}
|
||||
|
||||
bool restore (OpenGLFrameBuffer& buffer)
|
||||
{
|
||||
if (buffer.initialise (width, height))
|
||||
{
|
||||
buffer.writePixels (data, 0, 4, Rectangle<int> (0, 0, width, height));
|
||||
buffer.writePixels (data, 4, Rectangle<int> (0, 0, width, height));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -294,13 +294,18 @@ bool OpenGLFrameBuffer::initialise (int width, int height)
|
|||
return pimpl != nullptr;
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::initialise (const Image& content)
|
||||
bool OpenGLFrameBuffer::initialise (const Image& image)
|
||||
{
|
||||
if (initialise (content.getWidth(), content.getHeight()))
|
||||
if (initialise (image.getWidth(), image.getHeight()))
|
||||
{
|
||||
Image::BitmapData bitmap (content, Image::BitmapData::readOnly);
|
||||
return writePixels (bitmap.data, bitmap.lineStride / bitmap.pixelStride,
|
||||
bitmap.pixelStride, content.getBounds());
|
||||
{
|
||||
Image::BitmapData bitmap (image, Image::BitmapData::readOnly);
|
||||
|
||||
if (bitmap.lineStride == image.getWidth() * bitmap.pixelStride)
|
||||
return writePixels (bitmap.data, bitmap.pixelStride, image.getBounds());
|
||||
}
|
||||
|
||||
return initialise (Image (image.getSharedImage()->clone()));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -340,7 +345,7 @@ int OpenGLFrameBuffer::getWidth() const noexcept { return pimpl != nu
|
|||
int OpenGLFrameBuffer::getHeight() const noexcept { return pimpl != nullptr ? pimpl->height : 0; }
|
||||
GLuint OpenGLFrameBuffer::getTextureID() const noexcept { return pimpl != nullptr ? pimpl->textureID : 0; }
|
||||
|
||||
bool OpenGLFrameBuffer::makeCurrentTarget()
|
||||
bool OpenGLFrameBuffer::makeCurrentRenderingTarget()
|
||||
{
|
||||
// trying to use a framebuffer after saving it with saveAndRelease()! Be sure to call
|
||||
// reloadSavedCopy() to put it back into GPU memory before using it..
|
||||
|
|
@ -349,7 +354,7 @@ bool OpenGLFrameBuffer::makeCurrentTarget()
|
|||
return pimpl != nullptr && pimpl->bind();
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::releaseCurrentTarget()
|
||||
void OpenGLFrameBuffer::releaseAsRenderingTarget()
|
||||
{
|
||||
if (pimpl != nullptr)
|
||||
pimpl->unbind();
|
||||
|
|
@ -357,22 +362,28 @@ void OpenGLFrameBuffer::releaseCurrentTarget()
|
|||
|
||||
void OpenGLFrameBuffer::clear (const Colour& colour)
|
||||
{
|
||||
if (makeCurrentTarget())
|
||||
if (makeCurrentRenderingTarget())
|
||||
{
|
||||
OpenGLHelpers::clear (colour);
|
||||
releaseCurrentTarget();
|
||||
releaseAsRenderingTarget();
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::readPixels (void* target, int lineStride, const Rectangle<int>& area)
|
||||
void OpenGLFrameBuffer::makeCurrentAndClear()
|
||||
{
|
||||
if (! makeCurrentTarget())
|
||||
if (makeCurrentRenderingTarget())
|
||||
{
|
||||
glClearColor (0, 0, 0, 0);
|
||||
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::readPixels (void* target, const Rectangle<int>& area)
|
||||
{
|
||||
if (! makeCurrentRenderingTarget())
|
||||
return false;
|
||||
|
||||
OpenGLHelpers::prepareFor2D (pimpl->width, pimpl->height);
|
||||
|
||||
glPixelStorei (GL_PACK_ALIGNMENT, 4);
|
||||
glPixelStorei (GL_PACK_ROW_LENGTH, lineStride);
|
||||
glReadPixels (area.getX(), area.getY(), area.getWidth(), area.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, target);
|
||||
|
||||
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
|
||||
|
|
@ -380,16 +391,16 @@ bool OpenGLFrameBuffer::readPixels (void* target, int lineStride, const Rectangl
|
|||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::writePixels (const void* data, int lineStride, int pixelStride, const Rectangle<int>& area)
|
||||
bool OpenGLFrameBuffer::writePixels (const void* data, int pixelStride, const Rectangle<int>& area)
|
||||
{
|
||||
if (! makeCurrentTarget())
|
||||
if (! makeCurrentRenderingTarget())
|
||||
return false;
|
||||
|
||||
OpenGLHelpers::prepareFor2D (pimpl->width, pimpl->height);
|
||||
|
||||
jassert (pixelStride == 3 || pixelStride == 4); // can only handle RGB or ARGB
|
||||
const int format = pixelStride == 3 ? GL_RGB : GL_BGRA_EXT;
|
||||
const int invertedY = pimpl->height - area.getBottom();
|
||||
|
||||
OpenGLHelpers::prepareFor2D (pimpl->width, pimpl->height);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glDisable (GL_BLEND);
|
||||
|
||||
|
|
@ -405,7 +416,6 @@ bool OpenGLFrameBuffer::writePixels (const void* data, int lineStride, int pixel
|
|||
glBindTexture (GL_TEXTURE_2D, temporaryTexture);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, pixelStride);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, lineStride);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, area.getWidth(), area.getHeight(), 0,
|
||||
format, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
|
|
@ -415,19 +425,19 @@ bool OpenGLFrameBuffer::writePixels (const void* data, int lineStride, int pixel
|
|||
const int cropRect[4] = { 0, 0, area.getWidth(), area.getHeight() };
|
||||
glTexParameteriv (GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
|
||||
|
||||
glDrawTexiOES (area.getX(), area.getY(), 1, area.getWidth(), area.getHeight());
|
||||
glDrawTexiOES (area.getX(), invertedY, 1, area.getWidth(), area.getHeight());
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
glDeleteTextures (1, &temporaryTexture);
|
||||
}
|
||||
|
||||
#else
|
||||
glRasterPos2i (area.getX(), area.getY());
|
||||
glRasterPos2i (area.getX(), invertedY);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, pixelStride);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, lineStride);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
glDrawPixels (area.getWidth(), area.getHeight(), format, GL_UNSIGNED_BYTE, data);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
|
|
@ -462,10 +472,39 @@ void OpenGLFrameBuffer::draw3D (float x1, float y1, float z1,
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void OpenGLFrameBuffer::createAlphaChannelFromPath (const Path& path, const int oversamplingLevel)
|
||||
void OpenGLFrameBuffer::drawAt (float x1, float y1) const
|
||||
{
|
||||
makeCurrentTarget();
|
||||
if (pimpl != nullptr)
|
||||
{
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glBindTexture (GL_TEXTURE_2D, pimpl->textureID);
|
||||
|
||||
glDisableClientState (GL_COLOR_ARRAY);
|
||||
glDisableClientState (GL_NORMAL_ARRAY);
|
||||
|
||||
const GLfloat vertices[] = { x1, y1,
|
||||
x1 + pimpl->width, y1,
|
||||
x1, y1 + pimpl->height,
|
||||
x1 + pimpl->width, y1 + pimpl->height };
|
||||
|
||||
const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glVertexPointer (2, GL_FLOAT, 0, vertices);
|
||||
|
||||
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
|
||||
|
||||
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void OpenGLFrameBuffer::createAlphaChannelFromPath (const Path& path, const AffineTransform& transform,
|
||||
const int oversamplingLevel)
|
||||
{
|
||||
makeCurrentRenderingTarget();
|
||||
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
||||
|
|
@ -473,13 +512,12 @@ void OpenGLFrameBuffer::createAlphaChannelFromPath (const Path& path, const int
|
|||
glDisableClientState (GL_NORMAL_ARRAY);
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
||||
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_ONE, GL_ONE);
|
||||
|
||||
OpenGLHelpers::prepareFor2D (getWidth(), getHeight());
|
||||
|
||||
TriangulatedPath (path).draw (oversamplingLevel);
|
||||
prepareFor2D();
|
||||
TriangulatedPath (path, transform).draw (oversamplingLevel);
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
/**
|
||||
Creates an openGL frame buffer.
|
||||
*/
|
||||
class JUCE_API OpenGLFrameBuffer
|
||||
class JUCE_API OpenGLFrameBuffer : public OpenGLRenderingTarget
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised buffer.
|
||||
|
|
@ -81,19 +81,25 @@ public:
|
|||
/** Returns the height of the buffer. */
|
||||
int getHeight() const noexcept;
|
||||
|
||||
int getRenderingTargetWidth() const { return getWidth(); }
|
||||
int getRenderingTargetHeight() const { return getHeight(); }
|
||||
|
||||
/** Returns the texture ID number for using this buffer as a texture. */
|
||||
unsigned int getTextureID() const noexcept;
|
||||
GLuint getTextureID() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Selects this buffer as the current OpenGL rendering target. */
|
||||
bool makeCurrentTarget();
|
||||
bool makeCurrentRenderingTarget();
|
||||
|
||||
/** Deselects this buffer as the current OpenGL rendering target. */
|
||||
void releaseCurrentTarget();
|
||||
void releaseAsRenderingTarget();
|
||||
|
||||
/** Clears the framebuffer with the specified colour. */
|
||||
void clear (const Colour& colour);
|
||||
|
||||
/** Selects the framebuffer as the current target, and clears it to transparent. */
|
||||
void makeCurrentAndClear();
|
||||
|
||||
/** Draws this framebuffer onto the current context, with the specified corner positions. */
|
||||
void draw2D (float x1, float y1,
|
||||
float x2, float y2,
|
||||
|
|
@ -108,18 +114,20 @@ public:
|
|||
float x4, float y4, float z4,
|
||||
const Colour& colour) const;
|
||||
|
||||
/** Draws the framebuffer at a given position. */
|
||||
void drawAt (float x1, float y1) const;
|
||||
|
||||
/** Reads an area of pixels from the framebuffer into a 32-bit ARGB pixel array.
|
||||
The lineStride is measured as a number of pixels, not bytes - pass a stride
|
||||
of 0 to indicate a packed array.
|
||||
*/
|
||||
bool readPixels (void* targetData, int lineStride, const Rectangle<int>& sourceArea);
|
||||
bool readPixels (void* targetData, const Rectangle<int>& sourceArea);
|
||||
|
||||
/** Writes an area of pixels into the framebuffer from a specified pixel array.
|
||||
The lineStride is measured as a number of pixels, not bytes - pass a stride
|
||||
of 0 to indicate a packed array.
|
||||
*/
|
||||
bool writePixels (const void* srcData,
|
||||
int srcLineStride, int srcPixelStride,
|
||||
bool writePixels (const void* srcData, int srcPixelStride,
|
||||
const Rectangle<int>& targetArea);
|
||||
|
||||
/** This will render an anti-aliased path into just the alpha channel of this framebuffer.
|
||||
|
|
@ -131,7 +139,9 @@ public:
|
|||
Calling this will make changes to a lot of openGL state, including colour masks, blend
|
||||
functions, etc
|
||||
*/
|
||||
void createAlphaChannelFromPath (const Path& path, int oversamplingLevel = 4);
|
||||
void createAlphaChannelFromPath (const Path& path,
|
||||
const AffineTransform& transform,
|
||||
int oversamplingLevel = 4);
|
||||
|
||||
private:
|
||||
class Pimpl;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
//==============================================================================
|
||||
void OpenGLHelpers::resetErrorState()
|
||||
{
|
||||
while (glGetError() != GL_NO_ERROR) {}
|
||||
|
|
@ -44,7 +45,7 @@ void OpenGLHelpers::setColour (const Colour& colour)
|
|||
colour.getFloatBlue(), colour.getFloatAlpha());
|
||||
}
|
||||
|
||||
void OpenGLHelpers::prepareFor2D (int width, int height)
|
||||
void OpenGLHelpers::prepareFor2D (const int width, const int height)
|
||||
{
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
|
@ -75,6 +76,15 @@ void OpenGLHelpers::setPerspective (double fovy, double aspect, double zNear, do
|
|||
#endif
|
||||
}
|
||||
|
||||
void OpenGLHelpers::applyTransform (const AffineTransform& t)
|
||||
{
|
||||
const GLfloat m[] = { t.mat00, t.mat10, 0, 0,
|
||||
t.mat01, t.mat11, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
t.mat02, t.mat12, 0, 1 };
|
||||
glMultMatrixf (m);
|
||||
}
|
||||
|
||||
void OpenGLHelpers::drawQuad2D (float x1, float y1,
|
||||
float x2, float y2,
|
||||
float x3, float y3,
|
||||
|
|
@ -126,6 +136,8 @@ namespace OpenGLGradientHelpers
|
|||
{
|
||||
void drawTriangles (GLenum mode, const GLfloat* vertices, const GLfloat* textureCoords, const int numElements)
|
||||
{
|
||||
glEnable (GL_BLEND);
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState (GL_COLOR_ARRAY);
|
||||
|
|
@ -243,11 +255,6 @@ void OpenGLHelpers::fillRectWithColourGradient (const Rectangle<int>& rect,
|
|||
texture.load (lookup, textureSize, 1);
|
||||
texture.bind();
|
||||
|
||||
if (gradient.isOpaque())
|
||||
glDisable (GL_BLEND);
|
||||
else
|
||||
glEnable (GL_BLEND);
|
||||
|
||||
if (gradient.point1 == gradient.point2)
|
||||
{
|
||||
fillRectWithColour (rect, gradient.getColourAtPosition (1.0));
|
||||
|
|
@ -267,13 +274,17 @@ void OpenGLHelpers::fillRectWithColour (const Rectangle<int>& rect, const Colour
|
|||
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState (GL_COLOR_ARRAY);
|
||||
glDisableClientState (GL_NORMAL_ARRAY);
|
||||
setColour (colour);
|
||||
fillRect (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() };
|
||||
|
||||
setColour (colour);
|
||||
glVertexPointer (2, GL_FLOAT, 0, vertices);
|
||||
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
|
@ -283,11 +294,11 @@ void OpenGLHelpers::fillRectWithColour (const Rectangle<int>& rect, const Colour
|
|||
class TriangulatedPath::TrapezoidedPath
|
||||
{
|
||||
public:
|
||||
TrapezoidedPath (const Path& p)
|
||||
TrapezoidedPath (const Path& p, const AffineTransform& transform)
|
||||
: firstSlice (nullptr),
|
||||
windingMask (p.isUsingNonZeroWinding() ? -1 : 1)
|
||||
{
|
||||
for (PathFlatteningIterator iter (p); iter.next();)
|
||||
for (PathFlatteningIterator iter (p, transform); iter.next();)
|
||||
addLine (floatToInt (iter.x1), floatToInt (iter.y1),
|
||||
floatToInt (iter.x2), floatToInt (iter.y2));
|
||||
}
|
||||
|
|
@ -558,10 +569,10 @@ struct TriangulatedPath::TriangleBlock
|
|||
HeapBlock<GLfloat> triangles;
|
||||
};
|
||||
|
||||
TriangulatedPath::TriangulatedPath (const Path& path)
|
||||
TriangulatedPath::TriangulatedPath (const Path& path, const AffineTransform& transform)
|
||||
{
|
||||
startNewBlock();
|
||||
TrapezoidedPath (path).iterate (*this);
|
||||
TrapezoidedPath (path, transform).iterate (*this);
|
||||
}
|
||||
|
||||
void TriangulatedPath::draw (const int oversamplingLevel) const
|
||||
|
|
@ -619,4 +630,254 @@ void TriangulatedPath::addTrapezoid (GLfloat y1, GLfloat y2, GLfloat x1, GLfloat
|
|||
currentBlock->numVertices += 12;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
OpenGLTextureFromImage::OpenGLTextureFromImage (const Image& image)
|
||||
: width (image.getWidth()),
|
||||
height (image.getHeight())
|
||||
{
|
||||
OpenGLFrameBufferImage* glImage = dynamic_cast <OpenGLFrameBufferImage*> (image.getSharedImage());
|
||||
|
||||
if (glImage != nullptr)
|
||||
{
|
||||
textureID = glImage->frameBuffer.getTextureID();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OpenGLTexture::isValidSize (width, height))
|
||||
{
|
||||
texture = new OpenGLTexture();
|
||||
texture->load (image);
|
||||
textureID = texture->getTextureID();
|
||||
}
|
||||
else
|
||||
{
|
||||
frameBuffer = new OpenGLFrameBuffer();
|
||||
frameBuffer->initialise (image);
|
||||
textureID = frameBuffer->getTextureID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLTextureFromImage::~OpenGLTextureFromImage() {}
|
||||
|
||||
//==============================================================================
|
||||
OpenGLRenderingTarget::OpenGLRenderingTarget() {}
|
||||
OpenGLRenderingTarget::~OpenGLRenderingTarget() {}
|
||||
|
||||
void OpenGLRenderingTarget::prepareFor2D()
|
||||
{
|
||||
OpenGLHelpers::prepareFor2D (getRenderingTargetWidth(),
|
||||
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
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
#ifndef __JUCE_OPENGLHELPERS_JUCEHEADER__
|
||||
#define __JUCE_OPENGLHELPERS_JUCEHEADER__
|
||||
|
||||
class OpenGLTexture;
|
||||
class OpenGLFrameBuffer;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A set of miscellaneous openGL helper functions.
|
||||
|
|
@ -48,6 +52,8 @@ public:
|
|||
/** This does the same job as gluPerspective(). */
|
||||
static void setPerspective (double fovy, double aspect, double zNear, double zFar);
|
||||
|
||||
static void applyTransform (const AffineTransform& t);
|
||||
|
||||
/** Draws a 2D quad with the specified corner points. */
|
||||
static void drawQuad2D (float x1, float y1,
|
||||
float x2, float y2,
|
||||
|
|
@ -62,6 +68,8 @@ public:
|
|||
float x4, float y4, float z4,
|
||||
const Colour& colour);
|
||||
|
||||
static void fillRect (const Rectangle<int>& rect);
|
||||
|
||||
/** Fills a rectangle with the specified colour. */
|
||||
static void fillRectWithColour (const Rectangle<int>& rect,
|
||||
const Colour& colour);
|
||||
|
|
@ -78,7 +86,7 @@ public:
|
|||
class JUCE_API TriangulatedPath
|
||||
{
|
||||
public:
|
||||
TriangulatedPath (const Path& path);
|
||||
TriangulatedPath (const Path& path, const AffineTransform& transform);
|
||||
|
||||
/** Renders the path, using a jittered oversampling method.
|
||||
The oversampling level is the square root of the number of times it
|
||||
|
|
@ -106,4 +114,29 @@ private:
|
|||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Used as a local object while rendering, this will create a temporary texture ID
|
||||
from an image in the quickest way possible.
|
||||
|
||||
If the image is backed by an OpenGL framebuffer, it will use that directly; otherwise,
|
||||
this object will create a temporary texture or framebuffer and copy the image.
|
||||
*/
|
||||
class JUCE_API OpenGLTextureFromImage
|
||||
{
|
||||
public:
|
||||
OpenGLTextureFromImage (const Image& image);
|
||||
~OpenGLTextureFromImage();
|
||||
|
||||
GLuint textureID;
|
||||
const int width, height;
|
||||
|
||||
private:
|
||||
ScopedPointer<OpenGLTexture> texture;
|
||||
ScopedPointer<OpenGLFrameBuffer> frameBuffer;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLTextureFromImage);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_OPENGLHELPERS_JUCEHEADER__
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ namespace OpenGLImageHelpers
|
|||
{
|
||||
static void read (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
|
||||
{
|
||||
frameBuffer.readPixels (bitmapData.data, 0, Rectangle<int> (x, y, bitmapData.width, bitmapData.height));
|
||||
frameBuffer.readPixels (bitmapData.data, Rectangle<int> (x, y, bitmapData.width, bitmapData.height));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ namespace OpenGLImageHelpers
|
|||
|
||||
void write (const void* const data) const noexcept
|
||||
{
|
||||
frameBuffer.writePixels (data, 0, 4, area);
|
||||
frameBuffer.writePixels (data, 4, area);
|
||||
}
|
||||
|
||||
OpenGLFrameBuffer& frameBuffer;
|
||||
|
|
|
|||
62
modules/juce_opengl/opengl/juce_OpenGLRenderingTarget.h
Normal file
62
modules/juce_opengl/opengl/juce_OpenGLRenderingTarget.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-11 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_OPENGLRENDERINGTARGET_JUCEHEADER__
|
||||
#define __JUCE_OPENGLRENDERINGTARGET_JUCEHEADER__
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for OpenGL objects which can be selected as a rendering target.
|
||||
*/
|
||||
class JUCE_API OpenGLRenderingTarget
|
||||
{
|
||||
public:
|
||||
OpenGLRenderingTarget();
|
||||
virtual ~OpenGLRenderingTarget();
|
||||
|
||||
/** Activates this object as the current OpenGL target. */
|
||||
virtual bool makeCurrentRenderingTarget() = 0;
|
||||
|
||||
/** Deactivates this object as the current OpenGL target. */
|
||||
virtual void releaseAsRenderingTarget() = 0;
|
||||
|
||||
/** Returns the width in pixels of this target. */
|
||||
virtual int getRenderingTargetWidth() const = 0;
|
||||
/** Returns the height in pixels of this target. */
|
||||
virtual int getRenderingTargetHeight() const = 0;
|
||||
|
||||
/** Sets the current matrix for 2D rendering into this object.
|
||||
@see OpenGLHelpers::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);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_OPENGLRENDERINGTARGET_JUCEHEADER__
|
||||
|
|
@ -42,16 +42,20 @@ OpenGLTexture::~OpenGLTexture()
|
|||
release();
|
||||
}
|
||||
|
||||
bool OpenGLTexture::isValidSize (int width, int height)
|
||||
{
|
||||
return isPowerOfTwo (width) && isPowerOfTwo (height);
|
||||
}
|
||||
|
||||
void OpenGLTexture::create (const int w, const int h)
|
||||
{
|
||||
jassert (isValidSize (w, h)); // Perhaps these dimensions must be a power-of-two?
|
||||
|
||||
release();
|
||||
|
||||
width = w;
|
||||
height = h;
|
||||
|
||||
jassert (BitArray (width).countNumberOfSetBits() == 1); // these dimensions must be a power-of-two
|
||||
jassert (BitArray (height).countNumberOfSetBits() == 1);
|
||||
|
||||
glGenTextures (1, &textureID);
|
||||
glBindTexture (GL_TEXTURE_2D, textureID);
|
||||
|
||||
|
|
@ -67,14 +71,21 @@ void OpenGLTexture::load (const Image& image)
|
|||
{
|
||||
create (image.getWidth(), image.getHeight());
|
||||
|
||||
Image::BitmapData srcData (image, Image::BitmapData::readOnly);
|
||||
{
|
||||
Image::BitmapData srcData (image, Image::BitmapData::readOnly);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, srcData.pixelFormat);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, srcData.lineStride);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, srcData.pixelFormat);
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, internalGLTextureFormat, width, height, 0,
|
||||
srcData.pixelFormat == Image::RGB ? GL_RGB : GL_BGRA_EXT,
|
||||
GL_UNSIGNED_BYTE, srcData.data);
|
||||
if (srcData.lineStride == image.getWidth() * srcData.pixelStride)
|
||||
{
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, internalGLTextureFormat, width, height, 0,
|
||||
srcData.pixelFormat == Image::RGB ? GL_RGB : GL_BGRA_EXT,
|
||||
GL_UNSIGNED_BYTE, srcData.data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
load (Image (image.getSharedImage()->clone()));
|
||||
}
|
||||
|
||||
void OpenGLTexture::load (const PixelARGB* const pixels, const int w, const int h)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#ifndef __JUCE_OPENGLTEXTURE_JUCEHEADER__
|
||||
#define __JUCE_OPENGLTEXTURE_JUCEHEADER__
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Creates an openGL texture from an Image.
|
||||
*/
|
||||
|
|
@ -66,8 +67,16 @@ public:
|
|||
float x4, float y4, float z4,
|
||||
const Colour& colour) const;
|
||||
|
||||
/** Returns the GL texture ID number. */
|
||||
GLuint getTextureID() const noexcept { return textureID; }
|
||||
|
||||
/** Returns true if a texture can be created with the given size.
|
||||
Some systems may require that the sizes are powers-of-two.
|
||||
*/
|
||||
static bool isValidSize (int width, int height);
|
||||
|
||||
private:
|
||||
unsigned int textureID;
|
||||
GLuint textureID;
|
||||
int width, height;
|
||||
|
||||
void create (int w, int h);
|
||||
|
|
@ -75,4 +84,5 @@ private:
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLTexture);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_OPENGLTEXTURE_JUCEHEADER__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue