1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

More OpenGL work.

This commit is contained in:
jules 2011-10-20 22:26:55 +01:00
parent 27d7185f34
commit 0e478bf131
16 changed files with 346 additions and 163 deletions

View file

@ -120,6 +120,14 @@
#include <GLES/glext.h>
#endif
#if JUCE_WINDOWS
#define JUCE_DECLARE_GL_EXTENSION_FUNCTION(name, returnType, params) \
typedef returnType (__stdcall *type_ ## name) params; static type_ ## name name;
#else
#define JUCE_DECLARE_GL_EXTENSION_FUNCTION(name, returnType, params) \
typedef returnType (*type_ ## name) params; static type_ ## name name;
#endif
//==============================================================================
// START_AUTOINCLUDE opengl/*.cpp
#include "opengl/juce_OpenGLComponent.cpp"

View file

@ -114,6 +114,7 @@ public:
OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return glLayer; }
unsigned int getFrameBufferID() const { return (unsigned int) frameBufferHandle; }
void updateWindowPosition (const Rectangle<int>& bounds)
{

View file

@ -146,6 +146,11 @@ public:
return renderContext;
}
unsigned int getFrameBufferID() const
{
return 0;
}
void updateWindowPosition (const Rectangle<int>& bounds)
{
ScopedXLock xlock;

View file

@ -207,6 +207,7 @@ public:
OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return renderContext; }
unsigned int getFrameBufferID() const { return 0; }
void updateWindowPosition (const Rectangle<int>&) {}

View file

@ -26,7 +26,6 @@
#define WGL_EXT_FUNCTION_INIT(extType, extFunc) \
((extFunc = (extType) wglGetProcAddress (#extFunc)) != 0)
typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
@ -59,16 +58,6 @@ enum
WGL_TYPE_RGBA_ARB = 0x202B
};
static void getWglExtensions (HDC dc, StringArray& result) noexcept
{
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
if (WGL_EXT_FUNCTION_INIT (PFNWGLGETEXTENSIONSSTRINGARBPROC, wglGetExtensionsStringARB))
result.addTokens (String (wglGetExtensionsStringARB (dc)), false);
else
jassertfalse; // If this fails, it may be because you didn't activate the openGL context
}
extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component* component, void* parent);
//==============================================================================
@ -146,12 +135,8 @@ public:
OpenGLPixelFormat getPixelFormat() const
{
OpenGLPixelFormat pf;
makeActive();
StringArray availableExtensions;
getWglExtensions (dc, availableExtensions);
fillInPixelFormatDetails (GetPixelFormat (dc), pf, availableExtensions);
fillInPixelFormatDetails (GetPixelFormat (dc), pf);
return pf;
}
@ -160,6 +145,11 @@ public:
return renderContext;
}
unsigned int getFrameBufferID() const
{
return 0;
}
bool setPixelFormat (const OpenGLPixelFormat& pixelFormat)
{
makeActive();
@ -188,10 +178,7 @@ public:
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = 0;
StringArray availableExtensions;
getWglExtensions (dc, availableExtensions);
if (availableExtensions.contains ("WGL_ARB_pixel_format")
if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_pixel_format")
&& WGL_EXT_FUNCTION_INIT (PFNWGLCHOOSEPIXELFORMATARBPROC, wglChoosePixelFormatARB))
{
int attributes[64];
@ -236,7 +223,7 @@ public:
attributes[n++] = WGL_ACCUM_ALPHA_BITS_ARB;
attributes[n++] = pixelFormat.accumulationBufferAlphaBits;
if (availableExtensions.contains ("WGL_ARB_multisample")
if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_multisample")
&& pixelFormat.fullSceneAntiAliasingNumSamples > 0)
{
attributes[n++] = WGL_SAMPLE_BUFFERS_ARB;
@ -303,12 +290,9 @@ public:
{
makeActive();
StringArray availableExtensions;
getWglExtensions (dc, availableExtensions);
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = 0;
return availableExtensions.contains ("WGL_EXT_swap_control")
return OpenGLHelpers::isExtensionSupported ("WGL_EXT_swap_control")
&& WGL_EXT_FUNCTION_INIT (PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT)
&& wglSwapIntervalEXT (numFramesPerSwap) != FALSE;
}
@ -317,12 +301,9 @@ public:
{
makeActive();
StringArray availableExtensions;
getWglExtensions (dc, availableExtensions);
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = 0;
if (availableExtensions.contains ("WGL_EXT_swap_control")
if (OpenGLHelpers::isExtensionSupported ("WGL_EXT_swap_control")
&& WGL_EXT_FUNCTION_INIT (PFNWGLGETSWAPINTERVALEXTPROC, wglGetSwapIntervalEXT))
return wglGetSwapIntervalEXT();
@ -333,13 +314,10 @@ public:
{
jassert (isActive());
StringArray availableExtensions;
getWglExtensions (dc, availableExtensions);
PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0;
int numTypes = 0;
if (availableExtensions.contains("WGL_ARB_pixel_format")
if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_pixel_format")
&& WGL_EXT_FUNCTION_INIT (PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB))
{
int attributes = WGL_NUMBER_PIXEL_FORMATS_ARB;
@ -356,7 +334,7 @@ public:
for (int i = 0; i < numTypes; ++i)
{
if (fillInPixelFormatDetails (i + 1, pf, availableExtensions))
if (fillInPixelFormatDetails (i + 1, pf))
{
bool alreadyListed = false;
for (int j = results.size(); --j >= 0;)
@ -391,13 +369,11 @@ private:
dc = GetDC ((HWND) nativeWindow->getNativeHandle());
}
bool fillInPixelFormatDetails (const int pixelFormatIndex,
OpenGLPixelFormat& result,
const StringArray& availableExtensions) const noexcept
bool fillInPixelFormatDetails (const int pixelFormatIndex, OpenGLPixelFormat& result) const noexcept
{
PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0;
if (availableExtensions.contains ("WGL_ARB_pixel_format")
if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_pixel_format")
&& WGL_EXT_FUNCTION_INIT (PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB))
{
int attributes[32];
@ -419,7 +395,7 @@ private:
attributes[numAttributes++] = WGL_ACCUM_BLUE_BITS_ARB;
attributes[numAttributes++] = WGL_ACCUM_ALPHA_BITS_ARB;
if (availableExtensions.contains ("WGL_ARB_multisample"))
if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_multisample"))
attributes[numAttributes++] = WGL_SAMPLES_ARB;
int values[32] = { 0 };

View file

@ -433,5 +433,9 @@ void OpenGLComponent::internalRepaint (int x, int y, int w, int h)
context->repaint();
}
unsigned int OpenGLComponent::getFrameBufferID() const
{
return context != nullptr ? context->getFrameBufferID() : 0;
}
END_JUCE_NAMESPACE

View file

@ -205,6 +205,11 @@ public:
*/
void deleteContext();
/** If this component is backed by a frame buffer, this returns its ID number, or
0 if the component has no accessible framebuffer.
*/
unsigned int getFrameBufferID() const;
//==============================================================================
/** Returns the native handle of an embedded heavyweight window, if there is one.

View file

@ -100,6 +100,11 @@ public:
*/
virtual void deleteContext() = 0;
/** If this context is backed by a frame buffer, this returns its ID number, or
0 if the context has no accessible framebuffer.
*/
virtual unsigned int getFrameBufferID() const = 0;
//==============================================================================
/** Returns the context that's currently in active use by the calling thread.

View file

@ -60,16 +60,7 @@ enum
USE_FUNCTION (glGetFramebufferAttachmentParameterivEXT, void, (GLenum target, GLenum attachment, GLenum pname, GLint *params))\
USE_FUNCTION (glGenerateMipmapEXT, void, (GLenum target))\
#if JUCE_WINDOWS
#define APICALLTYPE __stdcall
#else
#define APICALLTYPE
#endif
#define DECLARE_FUNCTION(name, returnType, params) \
typedef returnType (APICALLTYPE * type_ ## name) params; static type_ ## name name;
FRAMEBUFFER_FUNCTION_LIST (DECLARE_FUNCTION)
#undef DECLARE_FUNCTION
FRAMEBUFFER_FUNCTION_LIST (JUCE_DECLARE_GL_EXTENSION_FUNCTION)
static bool framebufferFunctionsInitialised = false;
@ -79,16 +70,9 @@ static void initialiseFrameBufferFunctions()
{
framebufferFunctionsInitialised = true;
#if JUCE_LINUX
#define JUCE_LOOKUP_FUNCTION(name) glXGetProcAddress ((const GLubyte*) name)
#else
#define JUCE_LOOKUP_FUNCTION(name) wglGetProcAddress (name)
#endif
#define FIND_FUNCTION(name, returnType, params) name = (type_ ## name) JUCE_LOOKUP_FUNCTION (#name);
#define FIND_FUNCTION(name, returnType, params) name = (type_ ## name) OpenGLHelpers::getExtensionFunction (#name);
FRAMEBUFFER_FUNCTION_LIST (FIND_FUNCTION)
#undef FIND_FUNCTION
#undef JUCE_LOOKUP_FUNCTION
}
}
@ -134,8 +118,7 @@ class OpenGLFrameBuffer::Pimpl
{
public:
Pimpl (const int width_, const int height_,
const bool wantsDepthBuffer, const bool wantsStencilBuffer,
const GLenum textureType = GL_TEXTURE_2D)
const bool wantsDepthBuffer, const bool wantsStencilBuffer)
: width (width_),
height (height_),
textureID (0),
@ -159,14 +142,19 @@ public:
OpenGLHelpers::resetErrorState();
glGenFramebuffersEXT (1, &frameBufferHandle);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, frameBufferHandle);
glGenTextures (1, &textureID);
glBindTexture (textureType, textureID);
glTexImage2D (textureType, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture (GL_TEXTURE_2D, textureID);
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textureType, textureID, 0);
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);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureID, 0);
if (wantsDepthBuffer || wantsStencilBuffer)
{
@ -196,11 +184,6 @@ public:
ok = checkStatus();
glTexParameterf (textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf (textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf (textureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf (textureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
}
@ -254,14 +237,14 @@ public:
: width (w), height (h),
data (w * h)
{
buffer.readPixels (data, Rectangle<int> (0, 0, w, h));
buffer.readPixels (data, Rectangle<int> (w, h));
}
bool restore (OpenGLFrameBuffer& buffer)
{
if (buffer.initialise (width, height))
{
buffer.writePixels (data, 4, Rectangle<int> (0, 0, width, height));
buffer.writePixels (data, Rectangle<int> (width, height));
return true;
}
@ -270,7 +253,7 @@ public:
private:
const int width, height;
HeapBlock <int32> data;
HeapBlock <PixelARGB> data;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedState);
};
@ -292,19 +275,13 @@ bool OpenGLFrameBuffer::initialise (int width, int height)
bool OpenGLFrameBuffer::initialise (const Image& image)
{
if (initialise (image.getWidth(), image.getHeight()))
{
{
Image::BitmapData bitmap (image, Image::BitmapData::readOnly);
if (! image.isARGB())
return initialise (image.convertedToFormat (Image::ARGB));
if (bitmap.lineStride == image.getWidth() * bitmap.pixelStride)
return writePixels (bitmap.data, bitmap.pixelStride, image.getBounds());
}
Image::BitmapData bitmap (image, Image::BitmapData::readOnly);
return initialise (Image (image.getSharedImage()->clone()));
}
return false;
return initialise (bitmap.width, bitmap.height)
&& writePixels ((const PixelARGB*) bitmap.data, image.getBounds());
}
bool OpenGLFrameBuffer::initialise (const OpenGLFrameBuffer& other)
@ -320,6 +297,7 @@ bool OpenGLFrameBuffer::initialise (const OpenGLFrameBuffer& other)
if (initialise (p->width, p->height))
{
pimpl->bind();
OpenGLHelpers::prepareFor2D (p->width, p->height);
glDisable (GL_BLEND);
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
other.drawAt (0, 0);
@ -372,10 +350,14 @@ bool OpenGLFrameBuffer::makeCurrentRenderingTarget()
return pimpl != nullptr && pimpl->bind();
}
void OpenGLFrameBuffer::setCurrentFrameBufferTarget (GLuint frameBufferID)
{
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, frameBufferID);
}
void OpenGLFrameBuffer::releaseAsRenderingTarget()
{
if (pimpl != nullptr)
pimpl->unbind();
setCurrentFrameBufferTarget (0);
}
void OpenGLFrameBuffer::clear (const Colour& colour)
@ -396,69 +378,53 @@ void OpenGLFrameBuffer::makeCurrentAndClear()
}
}
bool OpenGLFrameBuffer::readPixels (void* target, const Rectangle<int>& area)
bool OpenGLFrameBuffer::readPixels (PixelARGB* target, const Rectangle<int>& area)
{
if (! makeCurrentRenderingTarget())
return false;
glPixelStorei (GL_PACK_ALIGNMENT, 4);
glReadPixels (area.getX(), area.getY(), area.getWidth(), area.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, target);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
return true;
}
bool OpenGLFrameBuffer::writePixels (const void* data, int pixelStride, const Rectangle<int>& area)
bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int>& area)
{
if (! makeCurrentRenderingTarget())
return false;
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);
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
#if JUCE_OPENGL_ES
// GLES has no glDrawPixels function, so we have to create a texture and draw it..
GLuint temporaryTexture = 0;
glGenTextures (1, &temporaryTexture);
jassert (temporaryTexture != 0); // can't create a texture!
if (temporaryTexture != 0)
{
// GLES has no glDrawPixels function, so we have to create a texture and draw it..
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, temporaryTexture);
glPixelStorei (GL_UNPACK_ALIGNMENT, pixelStride);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, area.getWidth(), area.getHeight(), 0,
format, GL_UNSIGNED_BYTE, data);
OpenGLTexture temp;
temp.load (data, area.getWidth(), area.getHeight());
temp.bind();
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const int cropRect[4] = { 0, 0, area.getWidth(), area.getHeight() };
const GLint cropRect[4] = { 0, 0, area.getWidth(), area.getHeight() };
glTexParameteriv (GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
glDrawTexiOES (area.getX(), invertedY, 1, area.getWidth(), area.getHeight());
glBindTexture (GL_TEXTURE_2D, 0);
glDeleteTextures (1, &temporaryTexture);
}
#else
glRasterPos2i (area.getX(), invertedY);
glBindTexture (GL_TEXTURE_2D, 0);
glPixelStorei (GL_UNPACK_ALIGNMENT, pixelStride);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
glDrawPixels (area.getWidth(), area.getHeight(), format, GL_UNSIGNED_BYTE, data);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glDrawPixels (area.getWidth(), area.getHeight(), GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
#endif
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
return true;
}

View file

@ -98,6 +98,11 @@ public:
/** Deselects this buffer as the current OpenGL rendering target. */
void releaseAsRenderingTarget();
/** Selects a framebuffer as the active target, or deselects the current
target buffer if you pass 0.
*/
static void setCurrentFrameBufferTarget (GLuint frameBufferID);
/** Clears the framebuffer with the specified colour. */
void clear (const Colour& colour);
@ -125,14 +130,13 @@ public:
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, const Rectangle<int>& sourceArea);
bool readPixels (PixelARGB* 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 srcPixelStride,
const Rectangle<int>& targetArea);
bool writePixels (const PixelARGB* srcData, const Rectangle<int>& targetArea);
private:
class Pimpl;

View file

@ -31,6 +31,84 @@ void OpenGLHelpers::resetErrorState()
while (glGetError() != GL_NO_ERROR) {}
}
void* OpenGLHelpers::getExtensionFunction (const char* functionName)
{
#if JUCE_WINDOWS
return (void*) wglGetProcAddress (functionName);
#elif JUCE_MAC
static void* handle = dlopen (nullptr, RTLD_LAZY);
return dlsym (handle, functionName);
#elif JUCE_LINUX
return (void*) glXGetProcAddress ((const GLubyte*) functionName);
#endif
}
#if ! JUCE_OPENGL_ES
namespace
{
bool isExtensionSupportedV3 (const char* extensionName)
{
#ifndef GL_NUM_EXTENSIONS
enum { GL_NUM_EXTENSIONS = 0x821d };
#endif
JUCE_DECLARE_GL_EXTENSION_FUNCTION (glGetStringi, const GLubyte*, (GLenum, GLuint))
if (glGetStringi == nullptr)
glGetStringi = (type_glGetStringi) OpenGLHelpers::getExtensionFunction ("glGetStringi");
if (glGetStringi != nullptr)
{
GLint numExtensions = 0;
glGetIntegerv (GL_NUM_EXTENSIONS, &numExtensions);
for (int i = 0; i < numExtensions; ++i)
if (strcmp (extensionName, (const char*) glGetStringi (GL_EXTENSIONS, i)) == 0)
return true;
}
return false;
}
}
#endif
bool OpenGLHelpers::isExtensionSupported (const char* const extensionName)
{
jassert (extensionName != nullptr); // you must supply a genuine string for this.
jassert (isContextActive()); // An OpenGL context will need to be active before calling this.
#if ! JUCE_OPENGL_ES
const GLubyte* version = glGetString (GL_VERSION);
if (version != nullptr && version[0] >= '3')
{
return isExtensionSupportedV3 (extensionName);
}
else
#endif
{
const char* extensions = (const char*) glGetString (GL_EXTENSIONS);
jassert (extensions != nullptr); // Perhaps you didn't activate an OpenGL context before calling this?
for (;;)
{
const char* found = strstr (extensions, extensionName);
if (found == nullptr)
break;
extensions = found + strlen (extensionName);
if (extensions[0] == ' ' || extensions[0] == 0)
return true;
}
}
return false;
}
void OpenGLHelpers::clear (const Colour& colour)
{
glClearColor (colour.getFloatRed(), colour.getFloatGreen(),
@ -295,15 +373,14 @@ void OpenGLHelpers::fillRectWithTiledTexture (int textureWidth, int textureHeigh
glEnable (GL_TEXTURE_2D);
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_REPEAT);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glEnableClientState (GL_VERTEX_ARRAY);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
glDisableClientState (GL_COLOR_ARRAY);
glDisableClientState (GL_NORMAL_ARRAY);
glColor4f (1.0f, 1.0f, 1.0f, alpha);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
const GLfloat clipX = (GLfloat) clip.getX();
const GLfloat clipY = (GLfloat) clip.getY();
const GLfloat clipR = (GLfloat) clip.getRight();
@ -325,6 +402,87 @@ void OpenGLHelpers::fillRectWithTiledTexture (int textureWidth, int textureHeigh
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}
//==============================================================================
struct OpenGLEdgeTableRenderer
{
OpenGLEdgeTableRenderer (float r_, float g_, float b_, const Point<int>& origin_) noexcept
: origin (origin_), r (r_), g (g_), b (b_), lastAlpha (-1)
{
}
void draw (const EdgeTable& et)
{
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer (2, GL_FLOAT, 0, vertices);
et.iterate (*this);
}
void setEdgeTableYPos (const int y) noexcept
{
const int lineY = y + origin.getY();
vertices[1] = (GLfloat) lineY;
vertices[3] = (GLfloat) (lineY + 1);
vertices[5] = (GLfloat) lineY;
vertices[7] = (GLfloat) (lineY + 1);
}
void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
{
drawHorizontal (x, 1, alphaLevel);
}
void handleEdgeTablePixelFull (const int x) noexcept
{
drawHorizontal (x, 1, 255);
}
void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept
{
drawHorizontal (x, width, alphaLevel);
}
void handleEdgeTableLineFull (const int x, const int width) noexcept
{
drawHorizontal (x, width, 255);
}
private:
GLfloat vertices[8];
const Point<int> origin;
const float r, g, b;
int lastAlpha;
void drawHorizontal (int x, const int w, const int alphaLevel) noexcept
{
x += origin.getX();
vertices[0] = (GLfloat) x;
vertices[2] = (GLfloat) x;
vertices[4] = (GLfloat) (x + w);
vertices[6] = (GLfloat) (x + w);
if (lastAlpha != alphaLevel)
{
lastAlpha = alphaLevel;
glColor4f (r, g, b, alphaLevel / 255.0f);
}
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}
JUCE_DECLARE_NON_COPYABLE (OpenGLEdgeTableRenderer);
};
void OpenGLHelpers::fillEdgeTable (const EdgeTable& edgeTable,
float red, float green, float blue,
const Point<int>& offset)
{
OpenGLEdgeTableRenderer etr (red, green, blue, offset);
etr.draw (edgeTable);
}
//==============================================================================
// This breaks down a path into a series of horizontal strips of trapezoids..
@ -390,7 +548,7 @@ private:
}
else
{
const int newX = x1 + (s->y1 - y1) * (x2 - x1) / (y2 - y1);
const int newX = x1 + (int) ((s->y1 - y1) * (int64) (x2 - x1) / (y2 - y1));
HorizontalSlice* const newSlice = new HorizontalSlice (s, x1, y1, newX, s->y1, winding);
insert (last, newSlice);
last = newSlice;
@ -411,7 +569,7 @@ private:
if (y2 > s->y2)
{
const int newY = s->y2;
const int newX = x1 + (newY - y1) * (x2 - x1) / (y2 - y1);
const int newX = x1 + (int) ((newY - y1) * (int64) (x2 - x1) / (y2 - y1));
s->addLine (x1, newX, winding);
x1 = newX;
y1 = newY;
@ -467,7 +625,7 @@ private:
if (dxDiff != 0)
{
const int intersectionY = (dy * diff1) / dxDiff;
const int intersectionY = (int) ((dy * (int64) diff1) / dxDiff);
if (intersectionY > 0 && intersectionY < dy)
{
@ -505,7 +663,7 @@ private:
for (int i = 0; i < segments.size(); ++i)
{
LineSegment& l = oldSegments[i];
const int newX = l.x1 + dy1 * (l.x2 - l.x1) / dy2;
const int newX = l.x1 + (int) (dy1 * (int64) (l.x2 - l.x1) / dy2);
newSegments[i].x1 = newX;
l.x2 = newX;
}

View file

@ -86,6 +86,17 @@ public:
const Rectangle<int>& targetArea,
const AffineTransform& transform,
float alpha);
/** Renders an edge-table into the current context. */
static void fillEdgeTable (const EdgeTable& edgeTable,
float red, float green, float blue,
const Point<int>& offset);
/** Checks whether the current context supports the specified extension. */
static bool isExtensionSupported (const char* extensionName);
/** Returns the address of a named GL extension function */
static void* getExtensionFunction (const char* functionName);
};
//==============================================================================

View file

@ -25,8 +25,8 @@
BEGIN_JUCE_NAMESPACE
OpenGLFrameBufferImage::OpenGLFrameBufferImage (Image::PixelFormat format, int width, int height)
: Image::SharedImage (format, width, height),
OpenGLFrameBufferImage::OpenGLFrameBufferImage (int width, int height)
: Image::SharedImage (Image::ARGB, width, height),
pixelStride (4),
lineStride (width * pixelStride)
{
@ -43,7 +43,7 @@ LowLevelGraphicsContext* OpenGLFrameBufferImage::createLowLevelContext()
Image::SharedImage* OpenGLFrameBufferImage::clone()
{
OpenGLFrameBufferImage* im = new OpenGLFrameBufferImage (getPixelFormat(), getWidth(), getHeight());
OpenGLFrameBufferImage* im = new OpenGLFrameBufferImage (getWidth(), getHeight());
im->incReferenceCount();
{
@ -67,14 +67,15 @@ namespace OpenGLImageHelpers
{
Dummy (OpenGLFrameBuffer&, int, int, int, int) noexcept {}
static void read (OpenGLFrameBuffer&, Image::BitmapData& , int, int) noexcept {}
static void write (const void*) noexcept {}
static void write (const PixelARGB*) noexcept {}
};
struct Reader
{
static void read (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
{
frameBuffer.readPixels (bitmapData.data, Rectangle<int> (x, y, bitmapData.width, bitmapData.height));
frameBuffer.readPixels ((PixelARGB*) bitmapData.data,
Rectangle<int> (x, y, bitmapData.width, bitmapData.height));
}
};
@ -84,9 +85,9 @@ namespace OpenGLImageHelpers
: frameBuffer (frameBuffer_), area (x, y, w, h)
{}
void write (const void* const data) const noexcept
void write (const PixelARGB* const data) const noexcept
{
frameBuffer.writePixels (data, 4, area);
frameBuffer.writePixels (data, area);
}
OpenGLFrameBuffer& frameBuffer;
@ -98,8 +99,8 @@ namespace OpenGLImageHelpers
template <class ReaderType, class WriterType>
struct DataReleaser : public Image::BitmapData::BitmapDataReleaser
{
DataReleaser (OpenGLFrameBuffer& frameBuffer, size_t dataSize, int x, int y, int w, int h)
: data (dataSize),
DataReleaser (OpenGLFrameBuffer& frameBuffer, int x, int y, int w, int h)
: data (w * h),
writer (frameBuffer, x, y, w, h)
{}
@ -110,15 +111,14 @@ namespace OpenGLImageHelpers
static void initialise (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
{
DataReleaser* r = new DataReleaser (frameBuffer, bitmapData.lineStride * bitmapData.height,
x, y, bitmapData.width, bitmapData.height);
DataReleaser* r = new DataReleaser (frameBuffer, x, y, bitmapData.width, bitmapData.height);
bitmapData.dataReleaser = r;
bitmapData.data = r->data + x * bitmapData.pixelStride + y * bitmapData.lineStride;
bitmapData.data = (uint8*) (r->data + (x + y * bitmapData.width));
ReaderType::read (frameBuffer, bitmapData, x, y);
}
HeapBlock<uint8> data;
HeapBlock<PixelARGB> data;
WriterType writer;
};
}

View file

@ -41,7 +41,7 @@
class JUCE_API OpenGLFrameBufferImage : public Image::SharedImage
{
public:
OpenGLFrameBufferImage (Image::PixelFormat format, int width, int height);
OpenGLFrameBufferImage (int width, int height);
/** Destructor. */
~OpenGLFrameBufferImage();

View file

@ -47,7 +47,7 @@ bool OpenGLTexture::isValidSize (int width, int height)
return isPowerOfTwo (width) && isPowerOfTwo (height);
}
void OpenGLTexture::create (const int w, const int h)
void OpenGLTexture::create (const int w, const int h, const void* pixels)
{
// Texture objects can only be created when the current thread has an active OpenGL
// context. You'll need to make an OpenGLComponent active before calling this.
@ -69,38 +69,73 @@ void OpenGLTexture::create (const int w, const int h)
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);
}
void OpenGLTexture::load (const Image& image)
{
create (image.getWidth(), image.getHeight());
{
Image::BitmapData srcData (image, Image::BitmapData::readOnly);
glPixelStorei (GL_UNPACK_ALIGNMENT, srcData.pixelFormat);
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)
{
create (w, h);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glTexImage2D (GL_TEXTURE_2D, 0, internalGLTextureFormat, w, h, 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
}
void OpenGLTexture::load (const Image& image)
{
const int imageW = image.getWidth();
const int imageH = image.getHeight();
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;
if (srcData.pixelFormat != Image::ARGB
|| textureW != imageW
|| textureH != imageH
|| srcData.lineStride != imageW * srcData.pixelStride)
{
const int srcLineStride = (srcData.pixelStride * imageW + 3) & ~3;
dataCopy.malloc (textureW * textureH);
data = dataCopy;
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);
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, addBytesToPointer (srcData.data, srcLineStride * y), srcLineStride);
}
}
create (textureW, textureH, data);
}
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)
{
dataCopy.malloc (textureW * textureH);
for (int y = 0; y < h; ++y)
memcpy (dataCopy + textureW * y, pixels + w * y, w * 4);
pixels = dataCopy;
}
create (textureW, textureH, pixels);
}
void OpenGLTexture::release()
{
if (textureID != 0)

View file

@ -37,7 +37,8 @@ public:
~OpenGLTexture();
/** Creates a texture from the given image.
Note that the image's width and height must both be a power-of-two.
Note that if the image's dimensions aren't a power-of-two, the texture may
be created with a larger size.
*/
void load (const Image& image);
@ -70,6 +71,9 @@ public:
/** Returns the GL texture ID number. */
GLuint getTextureID() const noexcept { return textureID; }
int getWidth() const noexcept { return width; }
int getHeight() const noexcept { return height; }
/** Returns true if a texture can be created with the given size.
Some systems may require that the sizes are powers-of-two.
*/
@ -79,7 +83,7 @@ private:
GLuint textureID;
int width, height;
void create (int w, int h);
void create (int w, int h, const void*);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLTexture);
};