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.

244 lines
7.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../JuceDemoHeader.h"
  20. #if JUCE_OPENGL
  21. //==============================================================================
  22. class OpenGL2DShaderDemo : public Component,
  23. private CodeDocument::Listener,
  24. private Timer
  25. {
  26. public:
  27. OpenGL2DShaderDemo()
  28. : fragmentEditorComp (fragmentDocument, nullptr)
  29. {
  30. setOpaque (true);
  31. if (auto* mw = MainAppWindow::getMainAppWindow())
  32. mw->setOpenGLRenderingEngine();
  33. addAndMakeVisible (statusLabel);
  34. statusLabel.setJustificationType (Justification::topLeft);
  35. statusLabel.setFont (Font (14.0f));
  36. auto presets = getPresets();
  37. StringArray presetNames;
  38. for (int i = 0; i < presets.size(); ++i)
  39. presetBox.addItem (presets[i].name, i + 1);
  40. addAndMakeVisible (presetLabel);
  41. presetLabel.setText ("Shader Preset:", dontSendNotification);
  42. presetLabel.attachToComponent (&presetBox, true);
  43. addAndMakeVisible (presetBox);
  44. presetBox.onChange = [this] { selectPreset (presetBox.getSelectedItemIndex()); };
  45. fragmentEditorComp.setOpaque (false);
  46. fragmentDocument.addListener (this);
  47. addAndMakeVisible (fragmentEditorComp);
  48. presetBox.setSelectedItemIndex (0);
  49. }
  50. ~OpenGL2DShaderDemo()
  51. {
  52. shader.reset();
  53. }
  54. void paint (Graphics& g) override
  55. {
  56. g.fillCheckerBoard (getLocalBounds().toFloat(), 48.0f, 48.0f, Colours::lightgrey, Colours::white);
  57. if (shader == nullptr || shader->getFragmentShaderCode() != fragmentCode)
  58. {
  59. shader.reset();
  60. if (fragmentCode.isNotEmpty())
  61. {
  62. shader = new OpenGLGraphicsContextCustomShader (fragmentCode);
  63. Result result (shader->checkCompilation (g.getInternalContext()));
  64. if (result.failed())
  65. {
  66. statusLabel.setText (result.getErrorMessage(), dontSendNotification);
  67. shader.reset();
  68. }
  69. }
  70. }
  71. if (shader != nullptr)
  72. {
  73. statusLabel.setText (String(), dontSendNotification);
  74. shader->fillRect (g.getInternalContext(), getLocalBounds());
  75. }
  76. }
  77. void resized() override
  78. {
  79. Rectangle<int> area (getLocalBounds().reduced (4));
  80. statusLabel.setBounds (area.removeFromTop (75));
  81. area.removeFromTop (area.getHeight() / 2);
  82. Rectangle<int> presets (area.removeFromTop (25));
  83. presets.removeFromLeft (100);
  84. presetBox.setBounds (presets.removeFromLeft (150));
  85. area.removeFromTop (4);
  86. fragmentEditorComp.setBounds (area);
  87. }
  88. void selectPreset (int preset)
  89. {
  90. fragmentDocument.replaceAllContent (getPresets()[preset].fragmentShader);
  91. startTimer (1);
  92. }
  93. ScopedPointer<OpenGLGraphicsContextCustomShader> shader;
  94. Label statusLabel, presetLabel;
  95. ComboBox presetBox;
  96. CodeDocument fragmentDocument;
  97. CodeEditorComponent fragmentEditorComp;
  98. String fragmentCode;
  99. private:
  100. enum { shaderLinkDelay = 500 };
  101. void codeDocumentTextInserted (const String& /*newText*/, int /*insertIndex*/) override
  102. {
  103. startTimer (shaderLinkDelay);
  104. }
  105. void codeDocumentTextDeleted (int /*startIndex*/, int /*endIndex*/) override
  106. {
  107. startTimer (shaderLinkDelay);
  108. }
  109. void timerCallback() override
  110. {
  111. stopTimer();
  112. fragmentCode = fragmentDocument.getAllContent();
  113. repaint();
  114. }
  115. struct ShaderPreset
  116. {
  117. const char* name;
  118. const char* fragmentShader;
  119. };
  120. static Array<ShaderPreset> getPresets()
  121. {
  122. #define SHADER_DEMO_HEADER \
  123. "/* This demo shows the use of the OpenGLGraphicsContextCustomShader,\n" \
  124. " which allows a 2D area to be filled using a GL shader program.\n" \
  125. "\n" \
  126. " Edit the shader program below and it will be \n" \
  127. " recompiled in real-time!\n" \
  128. "*/\n\n"
  129. ShaderPreset presets[] =
  130. {
  131. {
  132. "Simple Gradient",
  133. SHADER_DEMO_HEADER
  134. "void main()\n"
  135. "{\n"
  136. " " JUCE_MEDIUMP " vec4 colour1 = vec4 (1.0, 0.4, 0.6, 1.0);\n"
  137. " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.0, 0.8, 0.6, 1.0);\n"
  138. " " JUCE_MEDIUMP " float alpha = pixelPos.x / 1000.0;\n"
  139. " gl_FragColor = pixelAlpha * mix (colour1, colour2, alpha);\n"
  140. "}\n"
  141. },
  142. {
  143. "Circular Gradient",
  144. SHADER_DEMO_HEADER
  145. "void main()\n"
  146. "{\n"
  147. " " JUCE_MEDIUMP " vec4 colour1 = vec4 (1.0, 0.4, 0.6, 1.0);\n"
  148. " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.3, 0.4, 0.4, 1.0);\n"
  149. " " JUCE_MEDIUMP " float alpha = distance (pixelPos, vec2 (600.0, 500.0)) / 400.0;\n"
  150. " gl_FragColor = pixelAlpha * mix (colour1, colour2, alpha);\n"
  151. "}\n"
  152. },
  153. {
  154. "Circle",
  155. SHADER_DEMO_HEADER
  156. "void main()\n"
  157. "{\n"
  158. " " JUCE_MEDIUMP " vec4 colour1 = vec4 (0.1, 0.1, 0.9, 1.0);\n"
  159. " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.0, 0.8, 0.6, 1.0);\n"
  160. " " JUCE_MEDIUMP " float distance = distance (pixelPos, vec2 (600.0, 500.0));\n"
  161. "\n"
  162. " " JUCE_MEDIUMP " float innerRadius = 200.0;\n"
  163. " " JUCE_MEDIUMP " float outerRadius = 210.0;\n"
  164. "\n"
  165. " if (distance < innerRadius)\n"
  166. " gl_FragColor = colour1;\n"
  167. " else if (distance > outerRadius)\n"
  168. " gl_FragColor = colour2;\n"
  169. " else\n"
  170. " gl_FragColor = mix (colour1, colour2, (distance - innerRadius) / (outerRadius - innerRadius));\n"
  171. "\n"
  172. " gl_FragColor *= pixelAlpha;\n"
  173. "}\n"
  174. },
  175. {
  176. "Solid Colour",
  177. SHADER_DEMO_HEADER
  178. "void main()\n"
  179. "{\n"
  180. " gl_FragColor = vec4 (1.0, 0.6, 0.1, pixelAlpha);\n"
  181. "}\n"
  182. }
  183. };
  184. return Array<ShaderPreset> (presets, numElementsInArray (presets));
  185. }
  186. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGL2DShaderDemo)
  187. };
  188. //==============================================================================
  189. // This static object will register this demo type in a global list of demos..
  190. static JuceDemoType<OpenGL2DShaderDemo> demo ("20 Graphics: OpenGL 2D");
  191. #endif