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.

251 lines
8.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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 "../JuceDemoHeader.h"
  18. #if JUCE_OPENGL
  19. //==============================================================================
  20. class OpenGL2DShaderDemo : public Component,
  21. private CodeDocument::Listener,
  22. private ComboBox::Listener,
  23. private Timer
  24. {
  25. public:
  26. OpenGL2DShaderDemo()
  27. : fragmentEditorComp (fragmentDocument, nullptr)
  28. {
  29. setOpaque (true);
  30. if (MainAppWindow* mw = MainAppWindow::getMainAppWindow())
  31. mw->setOpenGLRenderingEngine();
  32. addAndMakeVisible (statusLabel);
  33. statusLabel.setJustificationType (Justification::topLeft);
  34. statusLabel.setColour (Label::textColourId, Colours::black);
  35. statusLabel.setFont (Font (14.0f));
  36. Array<ShaderPreset> 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.addListener (this);
  45. Colour editorBackground (Colours::white.withAlpha (0.6f));
  46. fragmentEditorComp.setColour (CodeEditorComponent::backgroundColourId, editorBackground);
  47. fragmentEditorComp.setOpaque (false);
  48. fragmentDocument.addListener (this);
  49. addAndMakeVisible (fragmentEditorComp);
  50. presetBox.setSelectedItemIndex (0);
  51. }
  52. ~OpenGL2DShaderDemo()
  53. {
  54. shader = nullptr;
  55. }
  56. void paint (Graphics& g) override
  57. {
  58. g.fillCheckerBoard (getLocalBounds(), 48, 48, Colours::lightgrey, Colours::white);
  59. if (shader == nullptr || shader->getFragmentShaderCode() != fragmentCode)
  60. {
  61. shader = nullptr;
  62. if (fragmentCode.isNotEmpty())
  63. {
  64. shader = new OpenGLGraphicsContextCustomShader (fragmentCode);
  65. Result result (shader->checkCompilation (g.getInternalContext()));
  66. if (result.failed())
  67. {
  68. statusLabel.setText (result.getErrorMessage(), dontSendNotification);
  69. shader = nullptr;
  70. }
  71. }
  72. }
  73. if (shader != nullptr)
  74. {
  75. statusLabel.setText (String(), dontSendNotification);
  76. shader->fillRect (g.getInternalContext(), getLocalBounds());
  77. }
  78. }
  79. void resized() override
  80. {
  81. Rectangle<int> area (getLocalBounds().reduced (4));
  82. statusLabel.setBounds (area.removeFromTop (75));
  83. area.removeFromTop (area.getHeight() / 2);
  84. Rectangle<int> presets (area.removeFromTop (25));
  85. presets.removeFromLeft (100);
  86. presetBox.setBounds (presets.removeFromLeft (150));
  87. area.removeFromTop (4);
  88. fragmentEditorComp.setBounds (area);
  89. }
  90. void selectPreset (int preset)
  91. {
  92. fragmentDocument.replaceAllContent (getPresets()[preset].fragmentShader);
  93. startTimer (1);
  94. }
  95. ScopedPointer<OpenGLGraphicsContextCustomShader> shader;
  96. Label statusLabel, presetLabel;
  97. ComboBox presetBox;
  98. CodeDocument fragmentDocument;
  99. CodeEditorComponent fragmentEditorComp;
  100. String fragmentCode;
  101. private:
  102. enum { shaderLinkDelay = 500 };
  103. void codeDocumentTextInserted (const String& /*newText*/, int /*insertIndex*/) override
  104. {
  105. startTimer (shaderLinkDelay);
  106. }
  107. void codeDocumentTextDeleted (int /*startIndex*/, int /*endIndex*/) override
  108. {
  109. startTimer (shaderLinkDelay);
  110. }
  111. void timerCallback() override
  112. {
  113. stopTimer();
  114. fragmentCode = fragmentDocument.getAllContent();
  115. repaint();
  116. }
  117. void comboBoxChanged (ComboBox*) override
  118. {
  119. selectPreset (presetBox.getSelectedItemIndex());
  120. }
  121. struct ShaderPreset
  122. {
  123. const char* name;
  124. const char* fragmentShader;
  125. };
  126. static Array<ShaderPreset> getPresets()
  127. {
  128. #define SHADER_DEMO_HEADER \
  129. "/* This demo shows the use of the OpenGLGraphicsContextCustomShader,\n" \
  130. " which allows a 2D area to be filled using a GL shader program.\n" \
  131. "\n" \
  132. " Edit the shader program below and it will be \n" \
  133. " recompiled in real-time!\n" \
  134. "*/\n\n"
  135. ShaderPreset presets[] =
  136. {
  137. {
  138. "Simple Gradient",
  139. SHADER_DEMO_HEADER
  140. "void main()\n"
  141. "{\n"
  142. " " JUCE_MEDIUMP " vec4 colour1 = vec4 (1.0, 0.4, 0.6, 1.0);\n"
  143. " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.0, 0.8, 0.6, 1.0);\n"
  144. " " JUCE_MEDIUMP " float alpha = pixelPos.x / 1000.0;\n"
  145. " gl_FragColor = pixelAlpha * mix (colour1, colour2, alpha);\n"
  146. "}\n"
  147. },
  148. {
  149. "Circular Gradient",
  150. SHADER_DEMO_HEADER
  151. "void main()\n"
  152. "{\n"
  153. " " JUCE_MEDIUMP " vec4 colour1 = vec4 (1.0, 0.4, 0.6, 1.0);\n"
  154. " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.3, 0.4, 0.4, 1.0);\n"
  155. " " JUCE_MEDIUMP " float alpha = distance (pixelPos, vec2 (600.0, 500.0)) / 400.0;\n"
  156. " gl_FragColor = pixelAlpha * mix (colour1, colour2, alpha);\n"
  157. "}\n"
  158. },
  159. {
  160. "Circle",
  161. SHADER_DEMO_HEADER
  162. "void main()\n"
  163. "{\n"
  164. " " JUCE_MEDIUMP " vec4 colour1 = vec4 (0.1, 0.1, 0.9, 1.0);\n"
  165. " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.0, 0.8, 0.6, 1.0);\n"
  166. " " JUCE_MEDIUMP " float distance = distance (pixelPos, vec2 (600.0, 500.0));\n"
  167. "\n"
  168. " " JUCE_MEDIUMP " float innerRadius = 200.0;\n"
  169. " " JUCE_MEDIUMP " float outerRadius = 210.0;\n"
  170. "\n"
  171. " if (distance < innerRadius)\n"
  172. " gl_FragColor = colour1;\n"
  173. " else if (distance > outerRadius)\n"
  174. " gl_FragColor = colour2;\n"
  175. " else\n"
  176. " gl_FragColor = mix (colour1, colour2, (distance - innerRadius) / (outerRadius - innerRadius));\n"
  177. "\n"
  178. " gl_FragColor *= pixelAlpha;\n"
  179. "}\n"
  180. },
  181. {
  182. "Solid Colour",
  183. SHADER_DEMO_HEADER
  184. "void main()\n"
  185. "{\n"
  186. " gl_FragColor = vec4 (1.0, 0.6, 0.1, pixelAlpha);\n"
  187. "}\n"
  188. }
  189. };
  190. return Array<ShaderPreset> (presets, numElementsInArray (presets));
  191. }
  192. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGL2DShaderDemo)
  193. };
  194. //==============================================================================
  195. // This static object will register this demo type in a global list of demos..
  196. static JuceDemoType<OpenGL2DShaderDemo> demo ("20 Graphics: OpenGL 2D");
  197. #endif