| @@ -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; | |||
| } | |||
| @@ -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; | |||
| @@ -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" | |||
| @@ -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 | |||
| @@ -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__ | |||
| @@ -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(); | |||
| } | |||
| } | |||
| @@ -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); | |||
| }; | |||
| @@ -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() | |||
| @@ -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); | |||
| }; | |||