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:
parent
27d7185f34
commit
0e478bf131
16 changed files with 346 additions and 163 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -146,6 +146,11 @@ public:
|
|||
return renderContext;
|
||||
}
|
||||
|
||||
unsigned int getFrameBufferID() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateWindowPosition (const Rectangle<int>& bounds)
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
|
|
|
|||
|
|
@ -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>&) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue