/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-9 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../jucedemo_headers.h" #if JUCE_OPENGL //============================================================================== class DemoOpenGLCanvas : public OpenGLComponent, public Timer { public: DemoOpenGLCanvas() : OpenGLComponent (openGLDefault), rotation (0.0f), textScrollPos (200) { infoLabel.setText ("These sliders demonstrate how components can be added as children " "of an OpenGLComponent, in which case, their content will be rendered into " "an OpenGL framebuffer and efficiently overlaid onto your GL content.", false); infoLabel.setInterceptsMouseClicks (false, false); addAndMakeVisible (&infoLabel); infoLabel.setBounds ("parent.width * 0.05, bottom - 150, parent.width * 0.4, parent.height - 60"); speedSlider.setRange (-10.0, 10.0, 0.1); speedSlider.setPopupMenuEnabled (true); speedSlider.setValue (Random::getSystemRandom().nextDouble() * 3.0, false, false); speedSlider.setSliderStyle (Slider::LinearHorizontal); speedSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); addAndMakeVisible (&speedSlider); speedSlider.setBounds ("parent.width * 0.05, parent.height - 65, parent.width * 0.6, top + 24"); sizeSlider.setRange (0.2, 2.0, 0.01); sizeSlider.setPopupMenuEnabled (true); sizeSlider.setValue (Random::getSystemRandom().nextDouble() + 0.5, false, false); sizeSlider.setSliderStyle (Slider::LinearHorizontal); sizeSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); addAndMakeVisible (&sizeSlider); sizeSlider.setBounds ("parent.width * 0.05, parent.height - 35, parent.width * 0.6, top + 24"); startTimer (1000 / 30); } // when the component creates a new internal context, this is called, and // we'll use the opportunity to create some images to use as textures. void newOpenGLContextCreated() { logoImage = createLogoImage(); dynamicTextureImage = Image (Image::ARGB, 128, 128, true, OpenGLImageType()); } void mouseDown (const MouseEvent& e) { draggableOrientation.mouseDown (e.getPosition()); } void mouseDrag (const MouseEvent& e) { draggableOrientation.mouseDrag (e.getPosition()); triggerRepaint(); } void resized() { draggableOrientation.setViewport (getLocalBounds()); } void renderOpenGL() { OpenGLHelpers::clear (Colours::darkgrey.withAlpha (1.0f)); updateTextureImage(); // this will update our dynamically-changing texture image. drawBackground2DStuff(); // draws some 2D content to demonstrate the OpenGLGraphicsContext class // 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::prepareFor2D (getWidth(), getHeight()); OpenGLHelpers::setPerspective (45.0, getWidth() / (double) getHeight(), 0.1, 100.0); glTranslatef (0.0f, 0.0f, -5.0f); draggableOrientation.applyToOpenGLMatrix(); // 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); } 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() { OpenGLGraphicsContext glRenderer (*this); // Create an OpenGLGraphicsContext 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 (Point (getWidth() * 0.7f, getHeight() * 0.4f), 7, scale * (float) sizeSlider.getValue(), scale, 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 timerCallback() { rotation += (float) speedSlider.getValue(); textScrollPos += 1.4f; triggerRepaint(); } private: Image logoImage, dynamicTextureImage; float rotation, textScrollPos; Draggable3DOrientation draggableOrientation; Slider speedSlider, sizeSlider; Label infoLabel; // Functions to create a couple of images to use as textures.. static Image createLogoImage() { Image image (Image::ARGB, 256, 256, true, OpenGLImageType()); Graphics g (image); 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 void drawRandomStars (Graphics& g, int w, int h) { Random r; for (int i = 10; --i >= 0;) { Path pp; pp.addStar (Point (r.nextFloat() * w, r.nextFloat() * h), r.nextInt (8) + 3, 10.0f, 20.0f, 0.0f); g.setColour (Colours::pink.withAlpha (0.4f)); g.fillPath (pp); } } void drawScrollingMessage (Graphics& g, int y) const { g.drawSingleLineText ("The background, foreground and texture are all being drawn using the OpenGLGraphicsContext 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); } }; //============================================================================== class OpenGLDemo : public Component { public: OpenGLDemo() : Component ("OpenGL") { addAndMakeVisible (&canvas); } void resized() { canvas.setBounds (10, 10, getWidth() - 20, getHeight() - 50); } private: DemoOpenGLCanvas canvas; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLDemo); }; //============================================================================== Component* createOpenGLDemo() { return new OpenGLDemo(); } #endif