Browse Source

Big OpenGLRenderer rewrite, plus a revamped OpenGL demo page to demonstrate 2D rendering.

tags/2021-05-28
jules 14 years ago
parent
commit
115a171d76
10 changed files with 886 additions and 1110 deletions
  1. +88
    -58
      extras/JuceDemo/Source/demos/OpenGLDemo.cpp
  2. +4
    -7
      modules/juce_graphics/geometry/juce_EdgeTable.cpp
  3. +3
    -3
      modules/juce_opengl/juce_opengl.cpp
  4. +87
    -84
      modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp
  5. +621
    -441
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
  6. +3
    -2
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
  7. +16
    -438
      modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp
  8. +3
    -43
      modules/juce_opengl/opengl/juce_OpenGLHelpers.h
  9. +31
    -30
      modules/juce_opengl/opengl/juce_OpenGLTexture.cpp
  10. +30
    -4
      modules/juce_opengl/opengl/juce_OpenGLTexture.h

+ 88
- 58
extras/JuceDemo/Source/demos/OpenGLDemo.cpp View File

@@ -34,29 +34,18 @@ class DemoOpenGLCanvas : public OpenGLComponent,
public:
DemoOpenGLCanvas()
: rotation (0.0f),
delta (1.0f)
delta (1.0f),
textScrollPos (200)
{
startTimer (20);
}
// when the component creates a new internal context, this is called, and
// we'll use the opportunity to create the textures needed.
// we'll use the opportunity to create some images to use as textures.
void newOpenGLContextCreated()
{
texture1.load (createImage1());
texture2.load (createImage2());
// (no need to call makeCurrentContextActive(), as that will have
// been done for us before the method call).
glDepthFunc (GL_LESS);
glEnable (GL_DEPTH_TEST);
glEnable (GL_TEXTURE_2D);
glEnable (GL_BLEND);
glShadeModel (GL_SMOOTH);
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint (GL_POINT_SMOOTH_HINT, GL_NICEST);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
logoImage = createLogoImage();
dynamicTextureImage = Image (Image::ARGB, 128, 128, true, OpenGLImageType());
}
void mouseDrag (const MouseEvent& e)
@@ -68,76 +57,117 @@ public:
void renderOpenGL()
{
OpenGLHelpers::clear (Colours::darkgrey.withAlpha (1.0f));
OpenGLHelpers::prepareFor2D (getWidth(), getHeight());
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
updateTextureImage(); // this will update our dynamically-changing texture image.
texture1.draw2D (50.0f, getHeight() - 50.0f,
getWidth() - 50.0f, getHeight() - 50.0f,
getWidth() - 50.0f, 50.0f,
50.0f, 50.0f,
Colours::white.withAlpha (fabsf (::sinf (rotation / 100.0f))));
drawBackground2DStuff(); // draws some 2D content to demonstrate the OpenGLRenderer class
glClear (GL_DEPTH_BUFFER_BIT);
// Having used the juce 2D renderer, it will have messed-up a whole load of GL state, so
// we'll put back any important settings before doing our normal GL 3D drawing..
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LESS);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_TEXTURE_2D);
OpenGLHelpers::setPerspective (45.0, getWidth() / (double) getHeight(), 0.1, 100.0);
glTranslatef (0.0f, 0.0f, -5.0f);
glRotatef (rotation, 0.5f, 1.0f, 0.0f);
// this draws the sides of our spinning cube..
texture1.draw3D (-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, Colours::white);
texture1.draw3D (-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, Colours::white);
texture1.draw3D (-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Colours::white);
texture2.draw3D (-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, Colours::white);
texture2.draw3D ( 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, Colours::white);
texture2.draw3D (-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, Colours::white);
// logoImage and dynamicTextureImage are actually OpenGL images, so we can use this utility function to
// extract the frame buffer which is their backing store, and use it directly.
OpenGLFrameBuffer* tex1 = OpenGLImageType::getFrameBufferFrom (logoImage);
OpenGLFrameBuffer* tex2 = OpenGLImageType::getFrameBufferFrom (dynamicTextureImage);
jassert (tex1 != nullptr && tex2 != nullptr); // (this would mean that our images weren't created correctly)
// This draws the sides of our spinning cube.
// I've used some of the juce helper functions, but you can also just use normal GL calls here too.
tex1->draw3D (-1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, Colours::white);
tex1->draw3D (-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, Colours::white);
tex1->draw3D (-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, Colours::white);
tex2->draw3D (-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, Colours::white);
tex2->draw3D ( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, Colours::white);
tex2->draw3D (-1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Colours::white);
drawForeground2DStuff(); // draws our scrolling text overlay
}
void updateTextureImage()
{
// This image is a special framebuffer-backed image, so when we draw to it, the context
// will render directly into its framebuffer
dynamicTextureImage.clear (dynamicTextureImage.getBounds(), Colours::red.withRotatedHue (fabsf (::sinf (rotation / 300.0f))).withAlpha (0.7f));
Graphics g (dynamicTextureImage);
g.setFont (dynamicTextureImage.getHeight() / 3.0f);
g.setColour (Colours::black);
drawScrollingMessage (g, dynamicTextureImage.getHeight() / 2);
}
void drawBackground2DStuff()
{
OpenGLRenderer glRenderer (*this); // Create an OpenGLRenderer that will draw into this GL window..
Graphics g (&glRenderer); // ..and then wrap it in a normal Graphics object so we can draw with it.
// This stuff just creates a spinning star shape and fills it..
Path p;
const float scale = getHeight() * 0.4f;
p.addStar (getLocalBounds().getCentre().toFloat(), 7,
scale + ::cosf (rotation * 0.0021f) * scale / 2,
scale + ::sinf (rotation * 0.001f) * scale / 2, rotation / 50.0f);
g.setGradientFill (ColourGradient (Colours::green.withRotatedHue (fabsf (::sinf (rotation / 300.0f))),
0, 0,
Colours::green.withRotatedHue (fabsf (::cosf (rotation / -431.0f))),
0, (float) getHeight(), false));
g.fillPath (p);
}
void drawForeground2DStuff()
{
OpenGLRenderer glRenderer (*this); // Create an OpenGLRenderer that will draw into this GL window..
Graphics g (&glRenderer); // ..and then wrap it in a normal Graphics object so we can draw with it.
// Then, just draw our scolling text like we would in any other component.
g.setColour (Colours::blue.withAlpha (0.5f));
g.setFont (30.0f, Font::bold);
drawScrollingMessage (g, getHeight() / 2);
}
void drawScrollingMessage (Graphics& g, int y) const
{
g.drawSingleLineText ("The background, foreground and texture are all being drawn using the OpenGLRenderer class, which "
"lets you use a standard JUCE 2D graphics context to render directly onto an OpenGL window or framebuffer... ",
(int) -std::fmod (textScrollPos, 2500.0f), y);
}
void timerCallback()
{
rotation += delta;
textScrollPos += 1.4f;
repaint();
}
private:
OpenGLTexture texture1, texture2;
float rotation, delta;
Image logoImage, dynamicTextureImage;
float rotation, delta, textScrollPos;
// Functions to create a couple of images to use as textures..
static Image createImage1()
static Image createLogoImage()
{
Image image (Image::ARGB, 256, 256, true);
Image image (Image::ARGB, 256, 256, true, OpenGLImageType());
Graphics g (image);
g.fillAll (Colours::white.withAlpha (0.7f));
g.fillAll (Colours::lightgrey.withAlpha (0.8f));
g.drawImageWithin (ImageFileFormat::loadFrom (BinaryData::juce_png, BinaryData::juce_pngSize),
0, 0, image.getWidth(), image.getHeight(), RectanglePlacement::stretchToFit);
drawRandomStars (g, image.getWidth(), image.getHeight());
return image;
}
static Image createImage2()
{
Image image (Image::ARGB, 128, 128, true);
Graphics g (image);
g.fillAll (Colours::darkred.withAlpha (0.7f));
Path p;
p.addStar (image.getBounds().getCentre().toFloat(), 11, image.getWidth() * 0.3f, image.getWidth() * 0.5f);
g.setGradientFill (ColourGradient (Colours::blue, image.getWidth() * 0.5f, image.getHeight() * 0.5f,
Colours::green, image.getWidth() * 0.2f, image.getHeight() * 0.2f,
true));
g.fillPath (p);
drawRandomStars (g, image.getWidth(), image.getHeight());
return image;
}


+ 4
- 7
modules/juce_graphics/geometry/juce_EdgeTable.cpp View File

@@ -44,10 +44,10 @@ EdgeTable::EdgeTable (const Rectangle<int>& bounds_,
t += lineStrideElements;
}
const int topLimit = bounds.getY() << 8;
const int topLimit = bounds.getY() << 8;
const int heightLimit = bounds.getHeight() << 8;
const int leftLimit = bounds.getX() << 8;
const int rightLimit = bounds.getRight() << 8;
const int leftLimit = bounds.getX() << 8;
const int rightLimit = bounds.getRight() << 8;
PathFlatteningIterator iter (path, transform);
@@ -598,13 +598,10 @@ void EdgeTable::clipToRectangle (const Rectangle<int>& r)
if (bottom < bounds.getHeight())
bounds.setHeight (bottom);
if (clipped.getRight() < bounds.getRight())
bounds.setRight (clipped.getRight());
for (int i = top; --i >= 0;)
table [lineStrideElements * i] = 0;
if (clipped.getX() > bounds.getX())
if (clipped.getX() > bounds.getX() || clipped.getRight() < bounds.getRight())
{
const int x1 = clipped.getX() << 8;
const int x2 = jmin (bounds.getRight(), clipped.getRight()) << 8;


+ 3
- 3
modules/juce_opengl/juce_opengl.cpp View File

@@ -57,9 +57,6 @@
#if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "imm32.lib")
#endif
#if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment(lib, "OpenGL32.Lib")
#pragma comment(lib, "GlU32.Lib")
#endif
@@ -128,6 +125,9 @@
typedef returnType (*type_ ## name) params; static type_ ## name name;
#endif
#define JUCE_INSTANTIATE_GL_EXTENSION(name) \
name = (type_ ## name) OpenGLHelpers::getExtensionFunction (#name);
//==============================================================================
// START_AUTOINCLUDE opengl/*.cpp
#include "opengl/juce_OpenGLComponent.cpp"


+ 87
- 84
modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp View File

@@ -25,95 +25,98 @@
BEGIN_JUCE_NAMESPACE
#if JUCE_WINDOWS
enum
namespace
{
GL_FRAMEBUFFER_EXT = 0x8D40,
GL_RENDERBUFFER_EXT = 0x8D41,
GL_FRAMEBUFFER_BINDING_EXT = 0x8CA6,
GL_COLOR_ATTACHMENT0_EXT = 0x8CE0,
GL_DEPTH_ATTACHMENT_EXT = 0x8D00,
GL_STENCIL_ATTACHMENT_EXT = 0x8D20,
GL_FRAMEBUFFER_COMPLETE_EXT = 0x8CD5,
GL_DEPTH24_STENCIL8_EXT = 0x88F0,
GL_RENDERBUFFER_DEPTH_SIZE_EXT = 0x8D54
};
#endif
#if JUCE_WINDOWS || JUCE_LINUX
#define FRAMEBUFFER_FUNCTION_LIST(USE_FUNCTION) \
USE_FUNCTION (glIsRenderbufferEXT, GLboolean, (GLuint renderbuffer))\
USE_FUNCTION (glBindRenderbufferEXT, void, (GLenum target, GLuint renderbuffer))\
USE_FUNCTION (glDeleteRenderbuffersEXT, void, (GLsizei n, const GLuint *renderbuffers))\
USE_FUNCTION (glGenRenderbuffersEXT, void, (GLsizei n, GLuint *renderbuffers))\
USE_FUNCTION (glRenderbufferStorageEXT, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height))\
USE_FUNCTION (glGetRenderbufferParameterivEXT, void, (GLenum target, GLenum pname, GLint* params))\
USE_FUNCTION (glIsFramebufferEXT, GLboolean, (GLuint framebuffer))\
USE_FUNCTION (glBindFramebufferEXT, void, (GLenum target, GLuint framebuffer))\
USE_FUNCTION (glDeleteFramebuffersEXT, void, (GLsizei n, const GLuint *framebuffers))\
USE_FUNCTION (glGenFramebuffersEXT, void, (GLsizei n, GLuint *framebuffers))\
USE_FUNCTION (glCheckFramebufferStatusEXT, GLenum, (GLenum target))\
USE_FUNCTION (glFramebufferTexture1DEXT, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))\
USE_FUNCTION (glFramebufferTexture2DEXT, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))\
USE_FUNCTION (glFramebufferTexture3DEXT, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset))\
USE_FUNCTION (glFramebufferRenderbufferEXT, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer))\
USE_FUNCTION (glGetFramebufferAttachmentParameterivEXT, void, (GLenum target, GLenum attachment, GLenum pname, GLint *params))\
USE_FUNCTION (glGenerateMipmapEXT, void, (GLenum target))\
FRAMEBUFFER_FUNCTION_LIST (JUCE_DECLARE_GL_EXTENSION_FUNCTION)
static bool framebufferFunctionsInitialised = false;
static void initialiseFrameBufferFunctions()
{
if (! framebufferFunctionsInitialised)
#if JUCE_WINDOWS
enum
{
GL_FRAMEBUFFER_EXT = 0x8D40,
GL_RENDERBUFFER_EXT = 0x8D41,
GL_FRAMEBUFFER_BINDING_EXT = 0x8CA6,
GL_COLOR_ATTACHMENT0_EXT = 0x8CE0,
GL_DEPTH_ATTACHMENT_EXT = 0x8D00,
GL_STENCIL_ATTACHMENT_EXT = 0x8D20,
GL_FRAMEBUFFER_COMPLETE_EXT = 0x8CD5,
GL_DEPTH24_STENCIL8_EXT = 0x88F0,
GL_RENDERBUFFER_DEPTH_SIZE_EXT = 0x8D54
};
#endif
#if JUCE_WINDOWS || JUCE_LINUX
#define FRAMEBUFFER_FUNCTION_LIST(USE_FUNCTION) \
USE_FUNCTION (glIsRenderbufferEXT, GLboolean, (GLuint renderbuffer))\
USE_FUNCTION (glBindRenderbufferEXT, void, (GLenum target, GLuint renderbuffer))\
USE_FUNCTION (glDeleteRenderbuffersEXT, void, (GLsizei n, const GLuint *renderbuffers))\
USE_FUNCTION (glGenRenderbuffersEXT, void, (GLsizei n, GLuint *renderbuffers))\
USE_FUNCTION (glRenderbufferStorageEXT, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height))\
USE_FUNCTION (glGetRenderbufferParameterivEXT, void, (GLenum target, GLenum pname, GLint* params))\
USE_FUNCTION (glIsFramebufferEXT, GLboolean, (GLuint framebuffer))\
USE_FUNCTION (glBindFramebufferEXT, void, (GLenum target, GLuint framebuffer))\
USE_FUNCTION (glDeleteFramebuffersEXT, void, (GLsizei n, const GLuint *framebuffers))\
USE_FUNCTION (glGenFramebuffersEXT, void, (GLsizei n, GLuint *framebuffers))\
USE_FUNCTION (glCheckFramebufferStatusEXT, GLenum, (GLenum target))\
USE_FUNCTION (glFramebufferTexture1DEXT, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))\
USE_FUNCTION (glFramebufferTexture2DEXT, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))\
USE_FUNCTION (glFramebufferTexture3DEXT, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset))\
USE_FUNCTION (glFramebufferRenderbufferEXT, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer))\
USE_FUNCTION (glGetFramebufferAttachmentParameterivEXT, void, (GLenum target, GLenum attachment, GLenum pname, GLint *params))\
USE_FUNCTION (glGenerateMipmapEXT, void, (GLenum target))\
FRAMEBUFFER_FUNCTION_LIST (JUCE_DECLARE_GL_EXTENSION_FUNCTION)
static bool framebufferFunctionsInitialised = false;
void initialiseFrameBufferFunctions()
{
framebufferFunctionsInitialised = true;
if (! framebufferFunctionsInitialised)
{
framebufferFunctionsInitialised = true;
#define FIND_FUNCTION(name, returnType, params) name = (type_ ## name) OpenGLHelpers::getExtensionFunction (#name);
FRAMEBUFFER_FUNCTION_LIST (FIND_FUNCTION)
#undef FIND_FUNCTION
#define FIND_FUNCTION(name, returnType, params) name = (type_ ## name) OpenGLHelpers::getExtensionFunction (#name);
FRAMEBUFFER_FUNCTION_LIST (FIND_FUNCTION)
#undef FIND_FUNCTION
}
}
}
#undef FRAMEBUFFER_FUNCTION_LIST
#undef FRAMEBUFFER_FUNCTION_LIST
//==============================================================================
#elif JUCE_OPENGL_ES
#define glIsRenderbufferEXT glIsRenderbufferOES
#define glBindRenderbufferEXT glBindRenderbufferOES
#define glDeleteRenderbuffersEXT glDeleteRenderbuffersOES
#define glGenRenderbuffersEXT glGenRenderbuffersOES
#define glRenderbufferStorageEXT glRenderbufferStorageOES
#define glGetRenderbufferParameterivEXT glGetRenderbufferParameterivOES
#define glIsFramebufferEXT glIsFramebufferOES
#define glBindFramebufferEXT glBindFramebufferOES
#define glDeleteFramebuffersEXT glDeleteFramebuffersOES
#define glGenFramebuffersEXT glGenFramebuffersOES
#define glCheckFramebufferStatusEXT glCheckFramebufferStatusOES
#define glFramebufferTexture1DEXT glFramebufferTexture1DOES
#define glFramebufferTexture2DEXT glFramebufferTexture2DOES
#define glFramebufferTexture3DEXT glFramebufferTexture3DOES
#define glFramebufferRenderbufferEXT glFramebufferRenderbufferOES
#define glGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameterivOES
#define glGenerateMipmapEXT glGenerateMipmapOES
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_OES
#define GL_RGBA8 GL_RGBA
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER_OES
#define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT GL_RENDERBUFFER_DEPTH_SIZE_OES
#define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT_OES
#define GL_STENCIL_ATTACHMENT_EXT GL_STENCIL_ATTACHMENT_OES
#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE_OES
#define GL_FRAMEBUFFER_UNSUPPORTED_EXT GL_FRAMEBUFFER_UNSUPPORTED_OES
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES
//==============================================================================
#elif JUCE_OPENGL_ES
#define glIsRenderbufferEXT glIsRenderbufferOES
#define glBindRenderbufferEXT glBindRenderbufferOES
#define glDeleteRenderbuffersEXT glDeleteRenderbuffersOES
#define glGenRenderbuffersEXT glGenRenderbuffersOES
#define glRenderbufferStorageEXT glRenderbufferStorageOES
#define glGetRenderbufferParameterivEXT glGetRenderbufferParameterivOES
#define glIsFramebufferEXT glIsFramebufferOES
#define glBindFramebufferEXT glBindFramebufferOES
#define glDeleteFramebuffersEXT glDeleteFramebuffersOES
#define glGenFramebuffersEXT glGenFramebuffersOES
#define glCheckFramebufferStatusEXT glCheckFramebufferStatusOES
#define glFramebufferTexture1DEXT glFramebufferTexture1DOES
#define glFramebufferTexture2DEXT glFramebufferTexture2DOES
#define glFramebufferTexture3DEXT glFramebufferTexture3DOES
#define glFramebufferRenderbufferEXT glFramebufferRenderbufferOES
#define glGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameterivOES
#define glGenerateMipmapEXT glGenerateMipmapOES
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_OES
#define GL_RGBA8 GL_RGBA
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER_OES
#define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT GL_RENDERBUFFER_DEPTH_SIZE_OES
#define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT_OES
#define GL_STENCIL_ATTACHMENT_EXT GL_STENCIL_ATTACHMENT_OES
#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE_OES
#define GL_FRAMEBUFFER_UNSUPPORTED_EXT GL_FRAMEBUFFER_UNSUPPORTED_OES
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES
#endif
#endif
}
//==============================================================================
class OpenGLFrameBuffer::Pimpl
@@ -399,7 +402,7 @@ bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int>
glDisable (GL_BLEND);
OpenGLTexture tex;
tex.load (data, area.getWidth(), area.getHeight());
tex.loadARGBFlipped (data, area.getWidth(), area.getHeight());
const int texH = tex.getHeight();
#if JUCE_OPENGL_ES


+ 621
- 441
modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
File diff suppressed because it is too large
View File


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

@@ -75,12 +75,13 @@ public:
#ifndef DOXYGEN
class SavedState;
class ScratchBufferManager;
#endif
private:
ScopedPointer<ScratchBufferManager> scratchBufferManager;
RenderingHelpers::SavedStateStack<SavedState> stack;
GLuint previousFrameBufferTarget;
void initialise();
};
#endif // __JUCE_OPENGLGRAPHICSCONTEXT_JUCEHEADER__

+ 16
- 438
modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp View File

@@ -234,12 +234,12 @@ void OpenGLHelpers::drawTriangleStrip (const GLfloat* const vertices, const GLfl
glBindTexture (GL_TEXTURE_2D, 0);
}
void OpenGLHelpers::drawTextureQuad (GLuint textureID, int x, int y, int w, int h)
void OpenGLHelpers::drawTextureQuad (GLuint textureID, const Rectangle<int>& rect)
{
const GLfloat l = (GLfloat) x;
const GLfloat t = (GLfloat) y;
const GLfloat r = (GLfloat) (x + w);
const GLfloat b = (GLfloat) (y + h);
const GLfloat l = (GLfloat) rect.getX();
const GLfloat t = (GLfloat) rect.getY();
const GLfloat r = (GLfloat) rect.getRight();
const GLfloat b = (GLfloat) rect.getBottom();
const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
const GLfloat textureCoords[] = { 0, 1.0f, 1.0f, 1.0f, 0, 0, 1.0f, 0 };
@@ -255,7 +255,7 @@ void OpenGLHelpers::fillRectWithTexture (const Rectangle<int>& rect, GLuint text
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glColor4f (alpha, alpha, alpha, alpha);
drawTextureQuad (textureID, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
drawTextureQuad (textureID, rect);
}
//==============================================================================
@@ -280,449 +280,27 @@ void OpenGLHelpers::fillRect (const Rectangle<int>& rect)
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}
//==============================================================================
struct OpenGLEdgeTableRenderer
{
OpenGLEdgeTableRenderer() noexcept
: 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
{
vertices[1] = vertices[5] = (GLfloat) y;
vertices[3] = vertices[7] = (GLfloat) (y + 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];
int lastAlpha;
void drawHorizontal (int x, const int w, const int alphaLevel) noexcept
{
vertices[0] = vertices[2] = (GLfloat) x;
vertices[4] = vertices[6] = (GLfloat) (x + w);
if (lastAlpha != alphaLevel)
{
lastAlpha = alphaLevel;
const float a = alphaLevel / 255.0f;
glColor4f (a, a, a, a);
}
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}
JUCE_DECLARE_NON_COPYABLE (OpenGLEdgeTableRenderer);
};
void OpenGLHelpers::fillEdgeTable (const EdgeTable& edgeTable)
{
OpenGLEdgeTableRenderer etr;
etr.draw (edgeTable);
}
//==============================================================================
// This breaks down a path into a series of horizontal strips of trapezoids..
class TriangulatedPath::TrapezoidedPath
{
public:
TrapezoidedPath (const Path& p, const AffineTransform& transform)
: firstSlice (nullptr),
windingMask (p.isUsingNonZeroWinding() ? -1 : 1)
{
for (PathFlatteningIterator iter (p, transform); iter.next();)
addLine (floatToInt (iter.x1), floatToInt (iter.y1),
floatToInt (iter.x2), floatToInt (iter.y2));
}
~TrapezoidedPath()
{
for (HorizontalSlice* s = firstSlice; s != nullptr;)
{
const ScopedPointer<HorizontalSlice> deleter (s);
s = s->next;
}
}
template <class Consumer>
void iterate (Consumer& consumer) const
{
for (HorizontalSlice* s = firstSlice; s != nullptr; s = s->next)
s->iterate (consumer, windingMask);
}
private:
void addLine (int x1, int y1, int x2, int y2)
{
int winding = 1;
if (y2 < y1)
{
std::swap (x1, x2);
std::swap (y1, y2);
winding = -1;
}
HorizontalSlice* last = nullptr;
HorizontalSlice* s = firstSlice;
while (y2 > y1)
{
if (s == nullptr)
{
insert (last, new HorizontalSlice (nullptr, x1, y1, x2, y2, winding));
break;
}
if (s->y2 > y1)
{
if (y1 < s->y1)
{
if (y2 <= s->y1)
{
insert (last, new HorizontalSlice (s, x1, y1, x2, y2, winding));
break;
}
else
{
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;
x1 = newX;
y1 = s->y1;
continue;
}
}
else if (y1 > s->y1)
{
s->split (y1);
s = s->next;
jassert (s != nullptr);
}
jassert (y1 == s->y1);
if (y2 > s->y2)
{
const int newY = s->y2;
const int newX = x1 + (int) ((newY - y1) * (int64) (x2 - x1) / (y2 - y1));
s->addLine (x1, newX, winding);
x1 = newX;
y1 = newY;
}
else
{
if (y2 < s->y2)
s->split (y2);
jassert (y2 == s->y2);
s->addLine (x1, x2, winding);
break;
}
}
last = s;
s = s->next;
}
}
struct HorizontalSlice
{
HorizontalSlice (const HorizontalSlice& other, HorizontalSlice* const next_, int y1_, int y2_)
: next (next_), y1 (y1_), y2 (y2_), segments (other.segments)
{
}
HorizontalSlice (HorizontalSlice* const next_, int x1, int y1_, int x2, int y2_, int winding)
: next (next_), y1 (y1_), y2 (y2_)
{
jassert (next != this);
jassert (y2 > y1);
segments.ensureStorageAllocated (32);
segments.add (LineSegment (x1, x2, winding));
}
void addLine (const int x1, const int x2, int winding)
{
const int dy = y2 - y1;
for (int i = 0; i < segments.size(); ++i)
{
const LineSegment& l = segments.getReference (i);
const int diff1 = l.x1 - x1;
const int diff2 = l.x2 - x2;
if ((diff1 < 0) == (diff2 > 0))
{
const int dx1 = l.x2 - l.x1;
const int dx2 = x2 - x1;
const int dxDiff = dx2 - dx1;
if (dxDiff != 0)
{
const int intersectionY = (int) ((dy * (int64) diff1) / dxDiff);
if (intersectionY > 0 && intersectionY < dy)
{
const int intersectionX = x1 + (intersectionY * dx2) / dy;
split (intersectionY + y1);
next->addLine (intersectionX, x2, winding);
addLine (x1, intersectionX, winding);
return;
}
}
}
if (diff1 + diff2 > 0)
{
segments.insert (i, LineSegment (x1, x2, winding));
return;
}
}
segments.add (LineSegment (x1, x2, winding));
}
void split (const int newY)
{
jassert (newY > y1 && newY < y2);
const int dy1 = newY - y1;
const int dy2 = y2 - y1;
next = new HorizontalSlice (*this, next, newY, y2);
y2 = newY;
LineSegment* const oldSegments = segments.getRawDataPointer();
LineSegment* const newSegments = next->segments.getRawDataPointer();
for (int i = 0; i < segments.size(); ++i)
{
LineSegment& l = oldSegments[i];
const int newX = l.x1 + (int) (dy1 * (int64) (l.x2 - l.x1) / dy2);
newSegments[i].x1 = newX;
l.x2 = newX;
}
}
template <class Consumer>
void iterate (Consumer& consumer, const int windingMask)
{
jassert (segments.size() > 0);
const float fy1 = intToFloat (y1);
const float fy2 = intToFloat (y2);
const LineSegment* s1 = segments.getRawDataPointer();
const LineSegment* s2 = s1;
int winding = s1->winding;
for (int i = segments.size(); --i > 0;)
{
++s2;
winding += s2->winding;
if ((winding & windingMask) == 0)
{
const float ax1 = intToFloat (s1->x1);
const float ax2 = intToFloat (s1->x2);
if (s1->x1 == s2->x1)
consumer.addTriangle (ax1, fy1, ax2, fy2, intToFloat (s2->x2), fy2);
else if (s1->x2 == s2->x2)
consumer.addTriangle (ax1, fy1, intToFloat (s2->x1), fy1, ax2, fy2);
else
consumer.addTrapezoid (fy1, fy2, ax1, ax2, intToFloat (s2->x1), intToFloat (s2->x2));
s1 = s2 + 1;
}
}
}
HorizontalSlice* next;
int y1, y2;
private:
struct LineSegment
{
inline LineSegment (int x1_, int x2_, int winding_) noexcept
: x1 (x1_), x2 (x2_), winding (winding_) {}
int x1, x2;
int winding;
};
Array<LineSegment> segments;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HorizontalSlice);
};
HorizontalSlice* firstSlice;
const int windingMask;
inline void insert (HorizontalSlice* const last, HorizontalSlice* const newOne) noexcept
{
if (last == nullptr)
firstSlice = newOne;
else
last->next = newOne;
}
enum { factor = 128 };
static inline int floatToInt (const float n) noexcept { return roundToInt (n * (float) factor); }
static inline float intToFloat (const int n) noexcept { return n * (1.0f / (float) factor); }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TrapezoidedPath);
};
//==============================================================================
struct TriangulatedPath::TriangleBlock
{
TriangleBlock() noexcept
: numVertices (0),
triangles (maxVerticesPerBlock)
{}
void draw() const
{
glVertexPointer (2, GL_FLOAT, 0, triangles);
glDrawArrays (GL_TRIANGLES, 0, numVertices / 2);
}
inline GLfloat* getNextTriangle() noexcept { return triangles + numVertices; }
void optimiseStorage() { triangles.realloc (numVertices); }
// Some GL implementations can't take very large triangle lists, so store
// the list as a series of blocks containing this max number of triangles.
enum { maxVerticesPerBlock = 256 * 6 };
unsigned int numVertices;
HeapBlock<GLfloat> triangles;
};
TriangulatedPath::TriangulatedPath (const Path& path, const AffineTransform& transform)
{
startNewBlock();
TrapezoidedPath (path, transform).iterate (*this);
}
TriangulatedPath::~TriangulatedPath() {}
void TriangulatedPath::draw (const int oversamplingLevel) const
{
const float a = 1.0f / (oversamplingLevel * oversamplingLevel);
glColor4f (a, a, a, a);
glPushMatrix();
glTranslatef (-0.5f, -0.5f, 0.0f);
const float inc = 1.0f / oversamplingLevel;
for (int y = oversamplingLevel; --y >= 0;)
{
for (int x = oversamplingLevel; --x >= 0;)
{
glTranslatef (inc, 0.0f, 0.0f);
for (int i = 0; i < blocks.size(); ++i)
blocks.getUnchecked(i)->draw();
}
glTranslatef (-1.0f, inc, 0.0f);
}
glPopMatrix();
}
void TriangulatedPath::optimiseStorage()
{
currentBlock->optimiseStorage();
}
void TriangulatedPath::startNewBlock()
{
currentBlock = new TriangleBlock();
blocks.add (currentBlock);
}
void TriangulatedPath::addTriangle (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3)
{
if (currentBlock->numVertices >= TriangleBlock::maxVerticesPerBlock)
startNewBlock();
GLfloat* t = currentBlock->getNextTriangle();
*t++ = x1; *t++ = y1; *t++ = x2; *t++ = y2; *t++ = x3; *t++ = y3;
currentBlock->numVertices += 6;
}
void TriangulatedPath::addTrapezoid (GLfloat y1, GLfloat y2, GLfloat x1, GLfloat x2, GLfloat x3, GLfloat x4)
{
if (currentBlock->numVertices >= TriangleBlock::maxVerticesPerBlock - 6)
startNewBlock();
GLfloat* t = currentBlock->getNextTriangle();
*t++ = x1; *t++ = y1; *t++ = x2; *t++ = y2; *t++ = x3; *t++ = y1;
*t++ = x4; *t++ = y2; *t++ = x2; *t++ = y2; *t++ = x3; *t++ = y1;
currentBlock->numVertices += 12;
}
//==============================================================================
OpenGLTextureFromImage::OpenGLTextureFromImage (const Image& image)
: width (image.getWidth()),
height (image.getHeight())
: imageWidth (image.getWidth()),
imageHeight (image.getHeight())
{
OpenGLFrameBuffer* const fb = OpenGLImageType::getFrameBufferFrom (image);
if (fb != nullptr)
{
textureID = fb->getTextureID();
fullWidthProportion = 1.0f;
fullHeightProportion = 1.0f;
}
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();
}
texture = new OpenGLTexture();
texture->loadImage (image);
textureID = texture->getTextureID();
fullWidthProportion = imageWidth / (float) texture->getWidth();
fullHeightProportion = imageHeight / (float) texture->getHeight();
}
}


+ 3
- 43
modules/juce_opengl/opengl/juce_OpenGLHelpers.h View File

@@ -78,7 +78,7 @@ public:
static void drawTriangleStrip (const GLfloat* const vertices, const GLfloat* const textureCoords,
const int numVertices, const GLuint textureID) noexcept;
static void drawTextureQuad (GLuint textureID, int x, int y, int w, int h);
static void drawTextureQuad (GLuint textureID, const Rectangle<int>& rect);
static void fillRectWithTexture (const Rectangle<int>& rect, GLuint textureID, const float alpha);
@@ -88,9 +88,6 @@ public:
static void fillRectWithColour (const Rectangle<int>& rect,
const Colour& colour);
/** Renders an edge-table into the current context. */
static void fillEdgeTable (const EdgeTable& edgeTable);
/** Checks whether the current context supports the specified extension. */
static bool isExtensionSupported (const char* extensionName);
@@ -98,43 +95,6 @@ public:
static void* getExtensionFunction (const char* functionName);
};
//==============================================================================
/** Holds a set of OpenGL triangles, having generated them from a Path object.
*/
class JUCE_API TriangulatedPath
{
public:
TriangulatedPath (const Path& path, const AffineTransform& transform);
/** Destructor. */
~TriangulatedPath();
/** Renders the path, using a jittered oversampling method.
The oversampling level is the square root of the number of times it
should be oversampled, so 3 or 4 might be reasonable.
*/
void draw (int oversamplingLevel) const;
/** Reduces the memory footprint of this object to the minimum possible. */
void optimiseStorage();
private:
class TrapezoidedPath;
friend class TrapezoidedPath;
void startNewBlock();
void addTriangle (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3);
void addTrapezoid (GLfloat y1, GLfloat y2, GLfloat x1, GLfloat x2, GLfloat x3, GLfloat x4);
struct TriangleBlock;
friend class OwnedArray<TriangleBlock>;
OwnedArray<TriangleBlock> blocks;
TriangleBlock* currentBlock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TriangulatedPath);
};
//==============================================================================
/**
Used as a local object while rendering, this will create a temporary texture ID
@@ -150,11 +110,11 @@ public:
~OpenGLTextureFromImage();
GLuint textureID;
const int width, height;
const int imageWidth, imageHeight;
float fullWidthProportion, fullHeightProportion;
private:
ScopedPointer<OpenGLTexture> texture;
ScopedPointer<OpenGLFrameBuffer> frameBuffer;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLTextureFromImage);
};


+ 31
- 30
modules/juce_opengl/opengl/juce_OpenGLTexture.cpp View File

@@ -25,12 +25,6 @@
BEGIN_JUCE_NAMESPACE
#if JUCE_OPENGL_ES
enum { internalGLTextureFormat = GL_RGBA };
#else
enum { internalGLTextureFormat = 4 };
#endif
OpenGLTexture::OpenGLTexture()
: textureID (0), width (0), height (0)
@@ -47,7 +41,7 @@ bool OpenGLTexture::isValidSize (int width, int height)
return isPowerOfTwo (width) && isPowerOfTwo (height);
}
void OpenGLTexture::create (const int w, const int h, const void* pixels)
void OpenGLTexture::create (const int w, const int h, const void* pixels, GLenum type)
{
// 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.
@@ -55,24 +49,26 @@ void OpenGLTexture::create (const int w, const int h, const void* pixels)
jassert (isValidSize (w, h)); // Perhaps these dimensions must be a power-of-two?
release();
if (width != w || height != h)
{
release();
width = w;
height = h;
width = w;
height = h;
glGenTextures (1, &textureID);
glBindTexture (GL_TEXTURE_2D, textureID);
glGenTextures (1, &textureID);
}
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
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);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glTexImage2D (GL_TEXTURE_2D, 0, internalGLTextureFormat, w, h, 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexImage2D (GL_TEXTURE_2D, 0, type == GL_ALPHA ? GL_ALPHA : GL_RGBA,
w, h, 0, type, GL_UNSIGNED_BYTE, pixels);
}
template <class PixelType>
@@ -96,7 +92,7 @@ struct Flipper
}
};
void OpenGLTexture::load (const Image& image)
void OpenGLTexture::loadImage (const Image& image)
{
const int imageW = image.getWidth();
const int imageH = image.getHeight();
@@ -114,25 +110,30 @@ void OpenGLTexture::load (const Image& image)
default: break;
}
create (textureW, textureH, dataCopy);
create (textureW, textureH, dataCopy, GL_BGRA_EXT);
}
void OpenGLTexture::loadARGB (const PixelARGB* pixels, const int w, const int h)
{
jassert (isValidSize (w, h));
create (w, h, pixels, GL_BGRA_EXT);
}
void OpenGLTexture::loadAlpha (const uint8* pixels, int w, int h)
{
jassert (isValidSize (w, h));
create (w, h, pixels, GL_ALPHA);
}
void OpenGLTexture::load (const PixelARGB* pixels, const int w, const int h)
void OpenGLTexture::loadARGBFlipped (const PixelARGB* pixels, int w, int h)
{
const int textureW = nextPowerOfTwo (w);
const int textureH = nextPowerOfTwo (h);
if (h == 1 && textureW == w)
{
create (w, 1, pixels);
}
else
{
const int textureH = nextPowerOfTwo (h);
HeapBlock<PixelARGB> flippedCopy;
Flipper<PixelARGB>::flip (flippedCopy, (const uint8*) pixels, 4 * w, w, h, textureW, textureH);
HeapBlock<PixelARGB> dataCopy;
Flipper<PixelARGB>::flip (dataCopy, (const uint8*) pixels, 4 * w, w, h, textureW, textureH);
create (textureW, textureH, dataCopy);
}
loadARGB (flippedCopy, textureW, textureH);
}
void OpenGLTexture::release()


+ 30
- 4
modules/juce_opengl/opengl/juce_OpenGLTexture.h View File

@@ -37,13 +37,39 @@ public:
~OpenGLTexture();
/** Creates a texture from the given image.
Note that if the image's dimensions aren't a power-of-two, the texture may
be created with a larger size.
The image will be arranged so that its top-left corner is at texture
coordinate (0, 1).
*/
void loadImage (const Image& image);
/** Creates a texture from a raw array of pixels.
The width and height provided must be valid - i.e. power-of-two unless
the underlying GL system allows otherwise.
The data is sent directly to the OpenGL driver without being flipped vertically,
so the first pixel will be mapped onto texture coordinate (0, 0).
bottom-left corner of the texture
*/
void load (const Image& image);
void loadARGB (const PixelARGB* pixels, int width, int height);
/** Creates a texture from a raw array of pixels. */
void load (const PixelARGB* pixels, int width, int height);
/** Creates a texture from a raw array of pixels.
This is like loadARGB, but will vertically flip the data so that the first
pixel ends up at texture coordinate (0, 1), and if the width and height are
not powers-of-two, it will compensate by using a larger texture size.
*/
void loadARGBFlipped (const PixelARGB* pixels, int width, int height);
/** Creates an alpha-channel texture from an array of alpha values.
The width and height provided must be valid - i.e. power-of-two unless
the underlying GL system allows otherwise.
The data is sent directly to the OpenGL driver without being flipped vertically,
so the first pixel will be mapped onto texture coordinate (0, 0).
bottom-left corner of the texture
*/
void loadAlpha (const uint8* pixels, int width, int height);
/** Frees the texture, if there is one. */
void release();
@@ -83,7 +109,7 @@ private:
GLuint textureID;
int width, height;
void create (int w, int h, const void*);
void create (int w, int h, const void*, GLenum type);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLTexture);
};


Loading…
Cancel
Save