From 6b94c7598d49f8cacebbce903ff98008c88c049e Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Fri, 9 Sep 2011 18:15:29 +0100 Subject: [PATCH] Tarted-up the openGL demo, and made the iOS demo the same as the normal one. Changed the opengl module to include gl.h automatically, so that your app doesn't need to include it. --- extras/JuceDemo/Source/demos/OpenGLDemo.cpp | 386 +++++++++++------- modules/juce_gui_basics/juce_gui_basics.cpp | 8 - modules/juce_opengl/juce_opengl.cpp | 4 - modules/juce_opengl/juce_opengl.h | 37 ++ .../native/juce_ios_OpenGLComponent.mm | 4 +- 5 files changed, 268 insertions(+), 171 deletions(-) diff --git a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp index b9abd54864..33bef045af 100644 --- a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp +++ b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp @@ -23,33 +23,153 @@ ============================================================================== */ -#ifdef _WIN32 - #include -#endif - #include "../jucedemo_headers.h" #if JUCE_OPENGL -#if JUCE_WINDOWS - #include - #include -#elif JUCE_LINUX - #include - #include - #undef KeyPress -#elif JUCE_IOS - #include - #include -#elif JUCE_MAC - #include -#elif JUCE_IOS - //#include -#endif +//============================================================================== +// Simple wrapper for an openGL texture.. +class OpenGLTexture +{ +public: + OpenGLTexture() + : textureID (0), width (0), height (0) + { + } -#ifndef GL_BGRA_EXT - #define GL_BGRA_EXT 0x80e1 -#endif + ~OpenGLTexture() + { + release(); + } + + void load (const Image& image) + { + release(); + + width = image.getWidth(); + height = image.getHeight(); + + jassert (BitArray (width).countNumberOfSetBits() == 1); // these dimensions must be a power-of-two + jassert (BitArray (height).countNumberOfSetBits() == 1); + + glGenTextures (1, &textureID); + glBindTexture (GL_TEXTURE_2D, textureID); + + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + #if ! JUCE_OPENGL_ES + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + #endif + + glPixelStorei (GL_UNPACK_ALIGNMENT, 4); + + Image::BitmapData srcData (image, Image::BitmapData::readOnly); + + glTexImage2D (GL_TEXTURE_2D, 0, internalFormat, + width, height, 0, + image.getFormat() == Image::RGB ? GL_RGB : GL_BGRA_EXT, + GL_UNSIGNED_BYTE, srcData.data); + } + + void release() + { + if (textureID != 0) + { + glDeleteTextures (1, &textureID); + textureID = 0; + width = 0; + height = 0; + } + } + + void bind() const + { + glBindTexture (GL_TEXTURE_2D, textureID); + } + + void draw2D (float x1, float y1, + float x2, float y2, + float x3, float y3, + float x4, float y4, + float alpha) const + { + bind(); + glColor4f (1.0f, 1.0f, 1.0f, alpha); + + #if JUCE_OPENGL_ES + const GLfloat vertices[] = { x1, y1, x2, y2, x4, y4, x3, y3 }; + const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f }; + + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (2, GL_FLOAT, 0, vertices); + + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); + + glDisableClientState (GL_COLOR_ARRAY); + glDisableClientState (GL_NORMAL_ARRAY); + + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + #else + glBegin (GL_QUADS); + glTexCoord2i (0, 0); glVertex2f (x1, y1); + glTexCoord2i (1, 0); glVertex2f (x2, y2); + glTexCoord2i (1, 1); glVertex2f (x3, y3); + glTexCoord2i (0, 1); glVertex2f (x4, y4); + glEnd(); + #endif + } + + void draw3D (float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4, + float alpha) const + { + bind(); + glColor4f (1.0f, 1.0f, 1.0f, alpha); + + #if JUCE_OPENGL_ES + const GLfloat vertices[] = { x1, y1, z1, x2, y2, z2, x4, y4, z4, x3, y3, z3 }; + const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f }; + + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (3, GL_FLOAT, 0, vertices); + + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); + + glDisableClientState (GL_COLOR_ARRAY); + glDisableClientState (GL_NORMAL_ARRAY); + + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + #else + glBegin (GL_QUADS); + glTexCoord2i (0, 0); glVertex3f (x1, y1, z1); + glTexCoord2i (1, 0); glVertex3f (x2, y2, z2); + glTexCoord2i (1, 1); glVertex3f (x3, y3, z3); + glTexCoord2i (0, 1); glVertex3f (x4, y4, z4); + glEnd(); + #endif + } + +private: + GLuint textureID; + int width, height; + + #if JUCE_OPENGL_ES + enum { internalFormat = GL_RGBA }; + #else + enum { internalFormat = 4 }; + #endif + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLTexture); +}; //============================================================================== class DemoOpenGLCanvas : public OpenGLComponent, @@ -60,18 +180,6 @@ public: : rotation (0.0f), delta (1.0f) { -#if JUCE_IOS - // (On the iPhone, choose a format without a depth buffer) - setPixelFormat (OpenGLPixelFormat (8, 8, 0, 0)); -#endif - - image = Image (Image::RGB, 512, 512, true, Image::SoftwareImage); - Graphics g (image); - - g.fillAll (Colours::white); - g.drawImageWithin (ImageFileFormat::loadFrom (BinaryData::juce_png, BinaryData::juce_pngSize), - 0, 0, 512, 512, RectanglePlacement::stretchToFit); - startTimer (20); // Just for demo purposes, let's dump a list of all the available pixel formats.. @@ -82,38 +190,32 @@ public: { const OpenGLPixelFormat* const pixFormat = availablePixelFormats[i]; - String formatDescription; - formatDescription - << i << ": RGBA=(" << pixFormat->redBits - << ", " << pixFormat->greenBits - << ", " << pixFormat->blueBits - << ", " << pixFormat->alphaBits - << "), depth=" << pixFormat->depthBufferBits - << ", stencil=" << pixFormat->stencilBufferBits - << ", accum RGBA=(" << pixFormat->accumulationBufferRedBits - << ", " << pixFormat->accumulationBufferGreenBits - << ", " << pixFormat->accumulationBufferBlueBits - << ", " << pixFormat->accumulationBufferAlphaBits - << "), full-scene AA=" - << (int) pixFormat->fullSceneAntiAliasingNumSamples; - - Logger::outputDebugString (formatDescription); + DBG (i << ": RGBA=(" << pixFormat->redBits + << ", " << pixFormat->greenBits + << ", " << pixFormat->blueBits + << ", " << pixFormat->alphaBits + << "), depth=" << pixFormat->depthBufferBits + << ", stencil=" << pixFormat->stencilBufferBits + << ", accum RGBA=(" << pixFormat->accumulationBufferRedBits + << ", " << pixFormat->accumulationBufferGreenBits + << ", " << pixFormat->accumulationBufferBlueBits + << ", " << pixFormat->accumulationBufferAlphaBits + << "), full-scene AA=" + << (int) pixFormat->fullSceneAntiAliasingNumSamples); } } - ~DemoOpenGLCanvas() - { - } - // when the component creates a new internal context, this is called, and // we'll use the opportunity to create the textures needed. void newOpenGLContextCreated() { -#if ! JUCE_IOS // (no need to call makeCurrentContextActive(), as that will have // been done for us before the method call). glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + + #if ! JUCE_OPENGL_ES glClearDepth (1.0); + #endif glDepthFunc (GL_LESS); glEnable (GL_DEPTH_TEST); @@ -121,23 +223,12 @@ public: glEnable (GL_BLEND); glShadeModel (GL_SMOOTH); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glPixelStorei (GL_UNPACK_ALIGNMENT, 4); - - Image::BitmapData srcData (image, Image::BitmapData::readOnly); - - glTexImage2D (GL_TEXTURE_2D, 0, 4, image.getWidth(), image.getHeight(), - 0, GL_RGB, - GL_UNSIGNED_BYTE, srcData.data); - glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); glHint (GL_POINT_SMOOTH_HINT, GL_NICEST); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif + + texture1.load (createImage1()); + texture2.load (createImage2()); } void mouseDrag (const MouseEvent& e) @@ -154,111 +245,94 @@ public: glMatrixMode (GL_PROJECTION); glLoadIdentity(); -#if JUCE_IOS - const GLfloat vertices[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; - const GLubyte colours[] = { 255, 255, 0, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 255, 255 }; - - glOrthof (-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f); - glMatrixMode (GL_MODELVIEW); - glPushMatrix(); - glRotatef (rotation, 0.0f, 0.0f, 1.0f); - - glVertexPointer (2, GL_FLOAT, 0, vertices); - glEnableClientState (GL_VERTEX_ARRAY); - glColorPointer (4, GL_UNSIGNED_BYTE, 0, colours); - glEnableClientState (GL_COLOR_ARRAY); - - glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - glPopMatrix(); -#else - + #if JUCE_OPENGL_ES + glOrthof (0.0f, (float) getWidth(), 0.0f, (float) getHeight(), 0.0f, 1.0f); + #else glOrtho (0.0, getWidth(), 0.0, getHeight(), 0, 1); + #endif - glColor4f (1.0f, 1.0f, 1.0f, fabsf (::sinf (rotation / 100.0f))); - glBegin (GL_QUADS); - glTexCoord2i (0, 0); glVertex2f (50.0f, getHeight() - 50.0f); - glTexCoord2i (1, 0); glVertex2f (getWidth() - 50.0f, getHeight() - 50.0f); - glTexCoord2i (1, 1); glVertex2f (getWidth() - 50.0f, 50.0f); - glTexCoord2i (0, 1); glVertex2f (50.0f, 50.0f); - glEnd(); + texture1.draw2D (50.0f, getHeight() - 50.0f, + getWidth() - 50.0f, getHeight() - 50.0f, + getWidth() - 50.0f, 50.0f, + 50.0f, 50.0f, + fabsf (::sinf (rotation / 100.0f))); - glMatrixMode (GL_PROJECTION); glLoadIdentity(); - glClear (GL_DEPTH_BUFFER_BIT); - gluPerspective (45.0f, - getWidth() / (GLfloat) getHeight(), - 0.1f, - 100.0f); + + setPerspective (45.0, getWidth() / (double) getHeight(), 0.1, 100.0); glMatrixMode (GL_MODELVIEW); - glLoadIdentity(); glPushMatrix(); + glTranslatef (0.0f, 0.0f, -5.0f); + glRotatef (rotation, 0.5f, 1.0f, 0.0f); - glTranslatef (0.0f, 0.0f, -5.0f); - glRotatef (rotation, 0.5f, 1.0f, 0.0f); - - glBegin (GL_QUADS); - - glColor3f (0.0f, 1.0f, 0.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); - glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); - glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); - - glColor3f (1.0f, 0.0f, 0.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); - glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); - - glColor3f (0.0f, 0.0f, 1.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, -1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); - glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); - glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, -1.0f); - - glColor3f (1.0f, 1.0f, 0.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); - glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); - - glColor3f (0.0f, 1.0f, 1.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); - glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); - - glColor3f (1.0f, 0.0f, 1.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); - glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); - glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, -1.0f); - - glEnd(); + // 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, 1.0f); + 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, 1.0f); + 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, 1.0f); + 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, 1.0f); + 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, 1.0f); + 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, 1.0f); glPopMatrix(); -#endif } void timerCallback() { rotation += delta; - repaint(); } private: + OpenGLTexture texture1, texture2; float rotation, delta; - Image image; + + // Utility function to do the same job as gluPerspective() + static void setPerspective (double fovy, double aspect, double zNear, double zFar) + { + const double ymax = zNear * tan (fovy * double_Pi / 360.0); + const double ymin = -ymax; + + #if JUCE_OPENGL_ES + glFrustumf (ymin * aspect, ymax * aspect, ymin, ymax, zNear, zFar); + #else + glFrustum (ymin * aspect, ymax * aspect, ymin, ymax, zNear, zFar); + #endif + } + + // Functions to create a couple of images to use as textures.. + static Image createImage1() + { + Image image (Image::ARGB, 256, 256, true, Image::SoftwareImage); + + Graphics g (image); + + g.fillAll (Colours::white.withAlpha (0.7f)); + g.drawImageWithin (ImageFileFormat::loadFrom (BinaryData::juce_png, BinaryData::juce_pngSize), + 0, 0, image.getWidth(), image.getHeight(), RectanglePlacement::stretchToFit); + + return image; + } + + static Image createImage2() + { + Image image (Image::ARGB, 128, 128, true, Image::SoftwareImage); + + 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); + + return image; + } }; @@ -266,11 +340,9 @@ private: class OpenGLDemo : public Component { public: - //============================================================================== OpenGLDemo() + : Component ("OpenGL") { - setName ("OpenGL"); - addAndMakeVisible (&canvas); } @@ -282,11 +354,9 @@ public: private: DemoOpenGLCanvas canvas; - OpenGLDemo (const OpenGLDemo&); - OpenGLDemo& operator= (const OpenGLDemo&); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLDemo); }; - //============================================================================== Component* createOpenGLDemo() { diff --git a/modules/juce_gui_basics/juce_gui_basics.cpp b/modules/juce_gui_basics/juce_gui_basics.cpp index 968712874d..9a6b714fb7 100644 --- a/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/modules/juce_gui_basics/juce_gui_basics.cpp @@ -49,12 +49,6 @@ #undef Point #undef Component -#elif JUCE_IOS - #if JUCE_OPENGL - #include - #include - #endif - //============================================================================== #elif JUCE_WINDOWS #include @@ -72,8 +66,6 @@ #endif #if JUCE_OPENGL - #include - #if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES #pragma comment(lib, "OpenGL32.Lib") #pragma comment(lib, "GlU32.Lib") diff --git a/modules/juce_opengl/juce_opengl.cpp b/modules/juce_opengl/juce_opengl.cpp index 8e019626a3..0b1c973d4c 100644 --- a/modules/juce_opengl/juce_opengl.cpp +++ b/modules/juce_opengl/juce_opengl.cpp @@ -43,8 +43,6 @@ //============================================================================== #if JUCE_IOS #import - #include - #include //============================================================================== #elif JUCE_WINDOWS @@ -62,8 +60,6 @@ #pragma comment(lib, "imm32.lib") #endif - #include - #if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES #pragma comment(lib, "OpenGL32.Lib") #pragma comment(lib, "GlU32.Lib") diff --git a/modules/juce_opengl/juce_opengl.h b/modules/juce_opengl/juce_opengl.h index 199c0a09b9..d843f9b112 100644 --- a/modules/juce_opengl/juce_opengl.h +++ b/modules/juce_opengl/juce_opengl.h @@ -29,10 +29,47 @@ #include "../juce_gui_extra/juce_gui_extra.h" #undef JUCE_OPENGL + #if ! JUCE_ANDROID #define JUCE_OPENGL 1 #endif +#if JUCE_IOS || JUCE_ANDROID + #define JUCE_OPENGL_ES 1 +#endif + +#if JUCE_WINDOWS + #ifndef APIENTRY + #define APIENTRY __stdcall + #define CLEAR_TEMP_APIENTRY 1 + #endif + #ifndef WINGDIAPI + #define WINGDIAPI __declspec(dllimport) + #define CLEAR_TEMP_WINGDIAPI 1 + #endif + #include + #ifdef CLEAR_TEMP_WINGDIAPI + #undef WINGDIAPI + #undef CLEAR_TEMP_WINGDIAPI + #endif + #ifdef CLEAR_TEMP_APIENTRY + #undef APIENTRY + #undef CLEAR_TEMP_APIENTRY + #endif +#elif JUCE_LINUX + #include + #undef KeyPress +#elif JUCE_IOS + #include + #include +#elif JUCE_MAC + #include +#endif + +#ifndef GL_BGRA_EXT + #define GL_BGRA_EXT 0x80e1 +#endif + //============================================================================= BEGIN_JUCE_NAMESPACE diff --git a/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm b/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm index f1744ebf99..b631370139 100644 --- a/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm +++ b/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm @@ -117,8 +117,10 @@ public: void updateWindowPosition (const Rectangle& bounds) { + // For some strange reason, the view seems to fail unless its width is a multiple of 8... view.frame = CGRectMake ((CGFloat) bounds.getX(), (CGFloat) bounds.getY(), - (CGFloat) bounds.getWidth(), (CGFloat) bounds.getHeight()); + (CGFloat) (bounds.getWidth() & ~7), + (CGFloat) bounds.getHeight()); if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight()) {