The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../jucedemo_headers.h"
  18. #if JUCE_OPENGL
  19. //==============================================================================
  20. class DemoOpenGLCanvas : public Component,
  21. public OpenGLRenderer,
  22. public Timer
  23. {
  24. public:
  25. DemoOpenGLCanvas()
  26. : rotation (0.0f),
  27. textScrollPos (200)
  28. {
  29. infoLabel.setText ("These sliders demonstrate how components and 2D graphics can be rendered "
  30. "using OpenGL by using the OpenGLContext class.", dontSendNotification);
  31. infoLabel.setInterceptsMouseClicks (false, false);
  32. addAndMakeVisible (&infoLabel);
  33. infoLabel.setBounds ("parent.width * 0.05, bottom - 150, parent.width * 0.4, parent.height - 60");
  34. speedSlider.setRange (-10.0, 10.0, 0.1);
  35. speedSlider.setPopupMenuEnabled (true);
  36. speedSlider.setValue (Random::getSystemRandom().nextDouble() * 3.0, dontSendNotification);
  37. speedSlider.setSliderStyle (Slider::LinearHorizontal);
  38. speedSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
  39. addAndMakeVisible (&speedSlider);
  40. speedSlider.setBounds ("parent.width * 0.05, parent.height - 65, parent.width * 0.6, top + 24");
  41. sizeSlider.setRange (0.2, 2.0, 0.01);
  42. sizeSlider.setPopupMenuEnabled (true);
  43. sizeSlider.setValue (Random::getSystemRandom().nextDouble() + 0.5, dontSendNotification);
  44. sizeSlider.setSliderStyle (Slider::LinearHorizontal);
  45. sizeSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
  46. addAndMakeVisible (&sizeSlider);
  47. sizeSlider.setBounds ("parent.width * 0.05, parent.height - 35, parent.width * 0.6, top + 24");
  48. openGLContext.setRenderer (this);
  49. openGLContext.setComponentPaintingEnabled (true);
  50. openGLContext.attachTo (*this);
  51. startTimer (1000 / 30);
  52. }
  53. ~DemoOpenGLCanvas()
  54. {
  55. openGLContext.detach();
  56. }
  57. // when the component creates a new internal context, this is called, and
  58. // we'll use the opportunity to create some images to use as textures.
  59. void newOpenGLContextCreated()
  60. {
  61. logoImage = createLogoImage();
  62. dynamicTextureImage = Image (Image::ARGB, 128, 128, true, OpenGLImageType());
  63. }
  64. void openGLContextClosing()
  65. {
  66. // We have to make sure we release any openGL images before the
  67. // GL context gets closed..
  68. logoImage = Image::null;
  69. dynamicTextureImage = Image::null;
  70. }
  71. void mouseDown (const MouseEvent& e)
  72. {
  73. draggableOrientation.mouseDown (e.getPosition());
  74. }
  75. void mouseDrag (const MouseEvent& e)
  76. {
  77. draggableOrientation.mouseDrag (e.getPosition());
  78. openGLContext.triggerRepaint();
  79. }
  80. void resized()
  81. {
  82. draggableOrientation.setViewport (getLocalBounds());
  83. }
  84. void paint (Graphics&) {}
  85. void renderOpenGL()
  86. {
  87. OpenGLHelpers::clear (Colours::darkgrey.withAlpha (1.0f));
  88. updateTextureImage(); // this will update our dynamically-changing texture image.
  89. drawBackground2DStuff(); // draws some 2D content to demonstrate the OpenGLGraphicsContext class
  90. // Having used the juce 2D renderer, it will have messed-up a whole load of GL state, so
  91. // we'll put back any important settings before doing our normal GL 3D drawing..
  92. glEnable (GL_DEPTH_TEST);
  93. glDepthFunc (GL_LESS);
  94. glEnable (GL_BLEND);
  95. glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  96. glEnable (GL_TEXTURE_2D);
  97. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  98. OpenGLHelpers::prepareFor2D (getContextWidth(), getContextHeight());
  99. OpenGLHelpers::setPerspective (45.0, getContextWidth() / (double) getContextHeight(), 0.1, 100.0);
  100. glTranslatef (0.0f, 0.0f, -5.0f);
  101. draggableOrientation.applyToOpenGLMatrix();
  102. // logoImage and dynamicTextureImage are actually OpenGL images, so we can use this utility function to
  103. // extract the frame buffer which is their backing store, and use it directly.
  104. OpenGLFrameBuffer* tex1 = OpenGLImageType::getFrameBufferFrom (logoImage);
  105. OpenGLFrameBuffer* tex2 = OpenGLImageType::getFrameBufferFrom (dynamicTextureImage);
  106. if (tex1 != nullptr && tex2 != nullptr)
  107. {
  108. // This draws the sides of our spinning cube.
  109. // I've used some of the juce helper functions, but you can also just use normal GL calls here too.
  110. 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);
  111. 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);
  112. 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);
  113. 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);
  114. 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);
  115. 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);
  116. }
  117. #endif
  118. }
  119. void updateTextureImage()
  120. {
  121. // This image is a special framebuffer-backed image, so when we draw to it, the context
  122. // will render directly into its framebuffer
  123. if (dynamicTextureImage.isValid())
  124. {
  125. dynamicTextureImage.clear (dynamicTextureImage.getBounds(),
  126. Colours::red.withRotatedHue (fabsf (::sinf (rotation / 300.0f))).withAlpha (0.7f));
  127. Graphics g (dynamicTextureImage);
  128. g.setFont (dynamicTextureImage.getHeight() / 3.0f);
  129. g.setColour (Colours::black);
  130. drawScrollingMessage (g, dynamicTextureImage.getHeight() / 2);
  131. }
  132. }
  133. void drawBackground2DStuff()
  134. {
  135. // Create an OpenGLGraphicsContext that will draw into this GL window..
  136. ScopedPointer<LowLevelGraphicsContext> glRenderer (createOpenGLGraphicsContext (openGLContext,
  137. getContextWidth(),
  138. getContextHeight()));
  139. if (glRenderer != nullptr)
  140. {
  141. Graphics g (glRenderer);
  142. g.addTransform (AffineTransform::scale ((float) getScale()));
  143. // This stuff just creates a spinning star shape and fills it..
  144. Path p;
  145. const float scale = getHeight() * 0.4f;
  146. p.addStar (Point<float> (getWidth() * 0.7f, getHeight() * 0.4f), 7,
  147. scale * (float) sizeSlider.getValue(), scale,
  148. rotation / 50.0f);
  149. g.setGradientFill (ColourGradient (Colours::green.withRotatedHue (fabsf (::sinf (rotation / 300.0f))),
  150. 0, 0,
  151. Colours::green.withRotatedHue (fabsf (::cosf (rotation / -431.0f))),
  152. 0, (float) getHeight(), false));
  153. g.fillPath (p);
  154. }
  155. }
  156. double getScale() const { return Desktop::getInstance().getDisplays().getDisplayContaining (getScreenBounds().getCentre()).scale; }
  157. int getContextWidth() const { return roundToInt (getScale() * getWidth()); }
  158. int getContextHeight() const { return roundToInt (getScale() * getHeight()); }
  159. void timerCallback()
  160. {
  161. rotation += (float) speedSlider.getValue();
  162. textScrollPos += 1.4f;
  163. openGLContext.triggerRepaint();
  164. }
  165. private:
  166. OpenGLContext openGLContext;
  167. Image logoImage, dynamicTextureImage;
  168. float rotation, textScrollPos;
  169. Draggable3DOrientation draggableOrientation;
  170. Slider speedSlider, sizeSlider;
  171. Label infoLabel;
  172. // Functions to create a couple of images to use as textures..
  173. static Image createLogoImage()
  174. {
  175. Image image (Image::ARGB, 256, 256, true, OpenGLImageType());
  176. if (image.isValid())
  177. {
  178. Graphics g (image);
  179. g.fillAll (Colours::lightgrey.withAlpha (0.8f));
  180. g.drawImageWithin (ImageFileFormat::loadFrom (BinaryData::juce_png, BinaryData::juce_pngSize),
  181. 0, 0, image.getWidth(), image.getHeight(), RectanglePlacement::stretchToFit);
  182. drawRandomStars (g, image.getWidth(), image.getHeight());
  183. }
  184. return image;
  185. }
  186. static void drawRandomStars (Graphics& g, int w, int h)
  187. {
  188. Random r;
  189. for (int i = 10; --i >= 0;)
  190. {
  191. Path pp;
  192. pp.addStar (Point<float> (r.nextFloat() * w, r.nextFloat() * h), r.nextInt (8) + 3, 10.0f, 20.0f, 0.0f);
  193. g.setColour (Colours::pink.withAlpha (0.4f));
  194. g.fillPath (pp);
  195. }
  196. }
  197. void drawScrollingMessage (Graphics& g, int y) const
  198. {
  199. g.drawSingleLineText ("The background, foreground and texture are all being drawn using the OpenGLGraphicsContext class, which "
  200. "lets you use a standard JUCE 2D graphics context to render directly onto an OpenGL window or framebuffer... ",
  201. (int) -std::fmod (textScrollPos, 2500.0f), y);
  202. }
  203. };
  204. //==============================================================================
  205. class OpenGLDemo : public Component
  206. {
  207. public:
  208. OpenGLDemo()
  209. : Component ("OpenGL")
  210. {
  211. addAndMakeVisible (&canvas);
  212. }
  213. void resized()
  214. {
  215. canvas.setBounds (10, 10, getWidth() - 20, getHeight() - 50);
  216. }
  217. private:
  218. DemoOpenGLCanvas canvas;
  219. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLDemo)
  220. };
  221. //==============================================================================
  222. Component* createOpenGLDemo()
  223. {
  224. return new OpenGLDemo();
  225. }
  226. #endif