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.

1241 lines
46KB

  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. #include "WavefrontObjParser.h"
  22. //==============================================================================
  23. struct OpenGLDemoClasses
  24. {
  25. /** Vertex data to be passed to the shaders.
  26. For the purposes of this demo, each vertex will have a 3D position, a colour and a
  27. 2D texture co-ordinate. Of course you can ignore these or manipulate them in the
  28. shader programs but are some useful defaults to work from.
  29. */
  30. struct Vertex
  31. {
  32. float position[3];
  33. float normal[3];
  34. float colour[4];
  35. float texCoord[2];
  36. };
  37. //==============================================================================
  38. // This class just manages the attributes that the demo shaders use.
  39. struct Attributes
  40. {
  41. Attributes (OpenGLContext& openGLContext, OpenGLShaderProgram& shader)
  42. {
  43. position = createAttribute (openGLContext, shader, "position");
  44. normal = createAttribute (openGLContext, shader, "normal");
  45. sourceColour = createAttribute (openGLContext, shader, "sourceColour");
  46. textureCoordIn = createAttribute (openGLContext, shader, "textureCoordIn");
  47. }
  48. void enable (OpenGLContext& openGLContext)
  49. {
  50. if (position != nullptr)
  51. {
  52. openGLContext.extensions.glVertexAttribPointer (position->attributeID, 3, GL_FLOAT, GL_FALSE, sizeof (Vertex), 0);
  53. openGLContext.extensions.glEnableVertexAttribArray (position->attributeID);
  54. }
  55. if (normal != nullptr)
  56. {
  57. openGLContext.extensions.glVertexAttribPointer (normal->attributeID, 3, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 3));
  58. openGLContext.extensions.glEnableVertexAttribArray (normal->attributeID);
  59. }
  60. if (sourceColour != nullptr)
  61. {
  62. openGLContext.extensions.glVertexAttribPointer (sourceColour->attributeID, 4, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 6));
  63. openGLContext.extensions.glEnableVertexAttribArray (sourceColour->attributeID);
  64. }
  65. if (textureCoordIn != nullptr)
  66. {
  67. openGLContext.extensions.glVertexAttribPointer (textureCoordIn->attributeID, 2, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 10));
  68. openGLContext.extensions.glEnableVertexAttribArray (textureCoordIn->attributeID);
  69. }
  70. }
  71. void disable (OpenGLContext& openGLContext)
  72. {
  73. if (position != nullptr) openGLContext.extensions.glDisableVertexAttribArray (position->attributeID);
  74. if (normal != nullptr) openGLContext.extensions.glDisableVertexAttribArray (normal->attributeID);
  75. if (sourceColour != nullptr) openGLContext.extensions.glDisableVertexAttribArray (sourceColour->attributeID);
  76. if (textureCoordIn != nullptr) openGLContext.extensions.glDisableVertexAttribArray (textureCoordIn->attributeID);
  77. }
  78. ScopedPointer<OpenGLShaderProgram::Attribute> position, normal, sourceColour, textureCoordIn;
  79. private:
  80. static OpenGLShaderProgram::Attribute* createAttribute (OpenGLContext& openGLContext,
  81. OpenGLShaderProgram& shader,
  82. const char* attributeName)
  83. {
  84. if (openGLContext.extensions.glGetAttribLocation (shader.getProgramID(), attributeName) < 0)
  85. return nullptr;
  86. return new OpenGLShaderProgram::Attribute (shader, attributeName);
  87. }
  88. };
  89. //==============================================================================
  90. // This class just manages the uniform values that the demo shaders use.
  91. struct Uniforms
  92. {
  93. Uniforms (OpenGLContext& openGLContext, OpenGLShaderProgram& shader)
  94. {
  95. projectionMatrix = createUniform (openGLContext, shader, "projectionMatrix");
  96. viewMatrix = createUniform (openGLContext, shader, "viewMatrix");
  97. texture = createUniform (openGLContext, shader, "demoTexture");
  98. lightPosition = createUniform (openGLContext, shader, "lightPosition");
  99. bouncingNumber = createUniform (openGLContext, shader, "bouncingNumber");
  100. }
  101. ScopedPointer<OpenGLShaderProgram::Uniform> projectionMatrix, viewMatrix, texture, lightPosition, bouncingNumber;
  102. private:
  103. static OpenGLShaderProgram::Uniform* createUniform (OpenGLContext& openGLContext,
  104. OpenGLShaderProgram& shader,
  105. const char* uniformName)
  106. {
  107. if (openGLContext.extensions.glGetUniformLocation (shader.getProgramID(), uniformName) < 0)
  108. return nullptr;
  109. return new OpenGLShaderProgram::Uniform (shader, uniformName);
  110. }
  111. };
  112. //==============================================================================
  113. /** This loads a 3D model from an OBJ file and converts it into some vertex buffers
  114. that we can draw.
  115. */
  116. struct Shape
  117. {
  118. Shape (OpenGLContext& openGLContext)
  119. {
  120. if (shapeFile.load (BinaryData::teapot_obj).wasOk())
  121. for (int i = 0; i < shapeFile.shapes.size(); ++i)
  122. vertexBuffers.add (new VertexBuffer (openGLContext, *shapeFile.shapes.getUnchecked(i)));
  123. }
  124. void draw (OpenGLContext& openGLContext, Attributes& attributes)
  125. {
  126. for (int i = 0; i < vertexBuffers.size(); ++i)
  127. {
  128. VertexBuffer& vertexBuffer = *vertexBuffers.getUnchecked (i);
  129. vertexBuffer.bind();
  130. attributes.enable (openGLContext);
  131. glDrawElements (GL_TRIANGLES, vertexBuffer.numIndices, GL_UNSIGNED_INT, 0);
  132. attributes.disable (openGLContext);
  133. }
  134. }
  135. private:
  136. struct VertexBuffer
  137. {
  138. VertexBuffer (OpenGLContext& context, WavefrontObjFile::Shape& shape) : openGLContext (context)
  139. {
  140. numIndices = shape.mesh.indices.size();
  141. openGLContext.extensions.glGenBuffers (1, &vertexBuffer);
  142. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer);
  143. Array<Vertex> vertices;
  144. createVertexListFromMesh (shape.mesh, vertices, Colours::green);
  145. openGLContext.extensions.glBufferData (GL_ARRAY_BUFFER, vertices.size() * (int) sizeof (Vertex),
  146. vertices.getRawDataPointer(), GL_STATIC_DRAW);
  147. openGLContext.extensions.glGenBuffers (1, &indexBuffer);
  148. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
  149. openGLContext.extensions.glBufferData (GL_ELEMENT_ARRAY_BUFFER, numIndices * (int) sizeof (juce::uint32),
  150. shape.mesh.indices.getRawDataPointer(), GL_STATIC_DRAW);
  151. }
  152. ~VertexBuffer()
  153. {
  154. openGLContext.extensions.glDeleteBuffers (1, &vertexBuffer);
  155. openGLContext.extensions.glDeleteBuffers (1, &indexBuffer);
  156. }
  157. void bind()
  158. {
  159. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer);
  160. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
  161. }
  162. GLuint vertexBuffer, indexBuffer;
  163. int numIndices;
  164. OpenGLContext& openGLContext;
  165. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VertexBuffer)
  166. };
  167. WavefrontObjFile shapeFile;
  168. OwnedArray<VertexBuffer> vertexBuffers;
  169. static void createVertexListFromMesh (const WavefrontObjFile::Mesh& mesh, Array<Vertex>& list, Colour colour)
  170. {
  171. const float scale = 0.2f;
  172. WavefrontObjFile::TextureCoord defaultTexCoord = { 0.5f, 0.5f };
  173. WavefrontObjFile::Vertex defaultNormal = { 0.5f, 0.5f, 0.5f };
  174. for (int i = 0; i < mesh.vertices.size(); ++i)
  175. {
  176. const WavefrontObjFile::Vertex& v = mesh.vertices.getReference (i);
  177. const WavefrontObjFile::Vertex& n
  178. = i < mesh.normals.size() ? mesh.normals.getReference (i) : defaultNormal;
  179. const WavefrontObjFile::TextureCoord& tc
  180. = i < mesh.textureCoords.size() ? mesh.textureCoords.getReference (i) : defaultTexCoord;
  181. Vertex vert =
  182. {
  183. { scale * v.x, scale * v.y, scale * v.z, },
  184. { scale * n.x, scale * n.y, scale * n.z, },
  185. { colour.getFloatRed(), colour.getFloatGreen(), colour.getFloatBlue(), colour.getFloatAlpha() },
  186. { tc.x, tc.y }
  187. };
  188. list.add (vert);
  189. }
  190. }
  191. };
  192. //==============================================================================
  193. // These classes are used to load textures from the various sources that the demo uses..
  194. struct DemoTexture
  195. {
  196. virtual ~DemoTexture() {}
  197. virtual bool applyTo (OpenGLTexture&) = 0;
  198. String name;
  199. };
  200. struct DynamicTexture : public DemoTexture
  201. {
  202. DynamicTexture() { name = "Dynamically-generated texture"; }
  203. Image image;
  204. BouncingNumber x, y;
  205. bool applyTo (OpenGLTexture& texture) override
  206. {
  207. const int size = 128;
  208. if (! image.isValid())
  209. image = Image (Image::ARGB, size, size, true);
  210. {
  211. Graphics g (image);
  212. g.fillAll (Colours::lightcyan);
  213. g.setColour (Colours::darkred);
  214. g.drawRect (0, 0, size, size, 2);
  215. g.setColour (Colours::green);
  216. g.fillEllipse (x.getValue() * size * 0.9f, y.getValue() * size * 0.9f, size * 0.1f, size * 0.1f);
  217. g.setColour (Colours::black);
  218. g.setFont (40);
  219. g.drawFittedText (String (Time::getCurrentTime().getMilliseconds()), image.getBounds(), Justification::centred, 1);
  220. }
  221. texture.loadImage (image);
  222. return true;
  223. }
  224. };
  225. struct BuiltInTexture : public DemoTexture
  226. {
  227. BuiltInTexture (const char* nm, const void* imageData, size_t imageSize)
  228. : image (resizeImageToPowerOfTwo (ImageFileFormat::loadFrom (imageData, imageSize)))
  229. {
  230. name = nm;
  231. }
  232. Image image;
  233. bool applyTo (OpenGLTexture& texture) override
  234. {
  235. texture.loadImage (image);
  236. return false;
  237. }
  238. };
  239. struct TextureFromFile : public DemoTexture
  240. {
  241. TextureFromFile (const File& file)
  242. {
  243. name = file.getFileName();
  244. image = resizeImageToPowerOfTwo (ImageFileFormat::loadFrom (file));
  245. }
  246. Image image;
  247. bool applyTo (OpenGLTexture& texture) override
  248. {
  249. texture.loadImage (image);
  250. return false;
  251. }
  252. };
  253. static Image resizeImageToPowerOfTwo (Image image)
  254. {
  255. if (! (isPowerOfTwo (image.getWidth()) && isPowerOfTwo (image.getHeight())))
  256. return image.rescaled (jmin (1024, nextPowerOfTwo (image.getWidth())),
  257. jmin (1024, nextPowerOfTwo (image.getHeight())));
  258. return image;
  259. }
  260. class OpenGLDemo;
  261. //==============================================================================
  262. /**
  263. This component sits on top of the main GL demo, and contains all the sliders
  264. and widgets that control things.
  265. */
  266. class DemoControlsOverlay : public Component,
  267. private CodeDocument::Listener,
  268. private ComboBox::Listener,
  269. private Slider::Listener,
  270. private Button::Listener,
  271. private Timer
  272. {
  273. public:
  274. DemoControlsOverlay (OpenGLDemo& d)
  275. : demo (d),
  276. vertexEditorComp (vertexDocument, nullptr),
  277. fragmentEditorComp (fragmentDocument, nullptr),
  278. tabbedComp (TabbedButtonBar::TabsAtLeft),
  279. showBackgroundToggle ("Draw 2D graphics in background")
  280. {
  281. addAndMakeVisible (statusLabel);
  282. statusLabel.setJustificationType (Justification::topLeft);
  283. statusLabel.setFont (Font (14.0f));
  284. addAndMakeVisible (sizeSlider);
  285. sizeSlider.setRange (0.0, 1.0, 0.001);
  286. sizeSlider.addListener (this);
  287. addAndMakeVisible (zoomLabel);
  288. zoomLabel.setText ("Zoom:", dontSendNotification);
  289. zoomLabel.attachToComponent (&sizeSlider, true);
  290. addAndMakeVisible (speedSlider);
  291. speedSlider.setRange (0.0, 0.5, 0.001);
  292. speedSlider.addListener (this);
  293. speedSlider.setSkewFactor (0.5f);
  294. addAndMakeVisible (speedLabel);
  295. speedLabel.setText ("Speed:", dontSendNotification);
  296. speedLabel.attachToComponent (&speedSlider, true);
  297. addAndMakeVisible (showBackgroundToggle);
  298. showBackgroundToggle.addListener (this);
  299. addAndMakeVisible (tabbedComp);
  300. tabbedComp.setTabBarDepth (25);
  301. tabbedComp.setColour (TabbedButtonBar::tabTextColourId, Colours::grey);
  302. tabbedComp.addTab ("Vertex", Colours::transparentBlack, &vertexEditorComp, false);
  303. tabbedComp.addTab ("Fragment", Colours::transparentBlack, &fragmentEditorComp, false);
  304. vertexDocument.addListener (this);
  305. fragmentDocument.addListener (this);
  306. textures.add (new BuiltInTexture ("Portmeirion", BinaryData::portmeirion_jpg, BinaryData::portmeirion_jpgSize));
  307. textures.add (new BuiltInTexture ("Tiled Background", BinaryData::tile_background_png, BinaryData::tile_background_pngSize));
  308. textures.add (new BuiltInTexture ("JUCE logo", BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize));
  309. textures.add (new DynamicTexture());
  310. addAndMakeVisible (textureBox);
  311. textureBox.addListener (this);
  312. updateTexturesList();
  313. addAndMakeVisible (presetBox);
  314. presetBox.addListener (this);
  315. Array<ShaderPreset> presets (getPresets());
  316. StringArray presetNames;
  317. for (int i = 0; i < presets.size(); ++i)
  318. presetBox.addItem (presets[i].name, i + 1);
  319. addAndMakeVisible (presetLabel);
  320. presetLabel.setText ("Shader Preset:", dontSendNotification);
  321. presetLabel.attachToComponent (&presetBox, true);
  322. addAndMakeVisible (textureLabel);
  323. textureLabel.setText ("Texture:", dontSendNotification);
  324. textureLabel.attachToComponent (&textureBox, true);
  325. lookAndFeelChanged();
  326. }
  327. void initialise()
  328. {
  329. showBackgroundToggle.setToggleState (false, sendNotification);
  330. textureBox.setSelectedItemIndex (0);
  331. presetBox.setSelectedItemIndex (0);
  332. speedSlider.setValue (0.01);
  333. sizeSlider.setValue (0.5);
  334. }
  335. void resized() override
  336. {
  337. Rectangle<int> area (getLocalBounds().reduced (4));
  338. Rectangle<int> top (area.removeFromTop (75));
  339. Rectangle<int> sliders (top.removeFromRight (area.getWidth() / 2));
  340. showBackgroundToggle.setBounds (sliders.removeFromBottom (25));
  341. speedSlider.setBounds (sliders.removeFromBottom (25));
  342. sizeSlider.setBounds (sliders.removeFromBottom (25));
  343. top.removeFromRight (70);
  344. statusLabel.setBounds (top);
  345. Rectangle<int> shaderArea (area.removeFromBottom (area.getHeight() / 2));
  346. Rectangle<int> presets (shaderArea.removeFromTop (25));
  347. presets.removeFromLeft (100);
  348. presetBox.setBounds (presets.removeFromLeft (150));
  349. presets.removeFromLeft (100);
  350. textureBox.setBounds (presets);
  351. shaderArea.removeFromTop (4);
  352. tabbedComp.setBounds (shaderArea);
  353. }
  354. void mouseDown (const MouseEvent& e) override
  355. {
  356. demo.draggableOrientation.mouseDown (e.getPosition());
  357. }
  358. void mouseDrag (const MouseEvent& e) override
  359. {
  360. demo.draggableOrientation.mouseDrag (e.getPosition());
  361. }
  362. void mouseWheelMove (const MouseEvent&, const MouseWheelDetails& d) override
  363. {
  364. sizeSlider.setValue (sizeSlider.getValue() + d.deltaY);
  365. }
  366. void mouseMagnify (const MouseEvent&, float magnifyAmmount) override
  367. {
  368. sizeSlider.setValue (sizeSlider.getValue() + magnifyAmmount - 1.0f);
  369. }
  370. void selectPreset (int preset)
  371. {
  372. const ShaderPreset& p = getPresets()[preset];
  373. vertexDocument.replaceAllContent (p.vertexShader);
  374. fragmentDocument.replaceAllContent (p.fragmentShader);
  375. startTimer (1);
  376. }
  377. void selectTexture (int itemID)
  378. {
  379. #if JUCE_MODAL_LOOPS_PERMITTED
  380. if (itemID == 1000)
  381. {
  382. static File lastLocation = File::getSpecialLocation (File::userPicturesDirectory);
  383. FileChooser fc ("Choose an image to open...", lastLocation, "*.jpg;*.jpeg;*.png;*.gif");
  384. if (fc.browseForFileToOpen())
  385. {
  386. lastLocation = fc.getResult();
  387. textures.add (new TextureFromFile (fc.getResult()));
  388. updateTexturesList();
  389. textureBox.setSelectedId (textures.size());
  390. }
  391. }
  392. else
  393. #endif
  394. {
  395. if (DemoTexture* t = textures [itemID - 1])
  396. demo.setTexture (t);
  397. }
  398. }
  399. void updateTexturesList()
  400. {
  401. textureBox.clear();
  402. for (int i = 0; i < textures.size(); ++i)
  403. textureBox.addItem (textures.getUnchecked(i)->name, i + 1);
  404. #if JUCE_MODAL_LOOPS_PERMITTED
  405. textureBox.addSeparator();
  406. textureBox.addItem ("Load from a file...", 1000);
  407. #endif
  408. }
  409. void updateShader()
  410. {
  411. startTimer (10);
  412. }
  413. Label statusLabel;
  414. private:
  415. void sliderValueChanged (Slider*) override
  416. {
  417. demo.scale = (float) sizeSlider.getValue();
  418. demo.rotationSpeed = (float) speedSlider.getValue();
  419. }
  420. void buttonClicked (Button*) override
  421. {
  422. demo.doBackgroundDrawing = showBackgroundToggle.getToggleState();
  423. }
  424. enum { shaderLinkDelay = 500 };
  425. void codeDocumentTextInserted (const String& /*newText*/, int /*insertIndex*/) override
  426. {
  427. startTimer (shaderLinkDelay);
  428. }
  429. void codeDocumentTextDeleted (int /*startIndex*/, int /*endIndex*/) override
  430. {
  431. startTimer (shaderLinkDelay);
  432. }
  433. void timerCallback() override
  434. {
  435. stopTimer();
  436. demo.setShaderProgram (vertexDocument.getAllContent(),
  437. fragmentDocument.getAllContent());
  438. }
  439. void comboBoxChanged (ComboBox* box) override
  440. {
  441. if (box == &presetBox)
  442. selectPreset (presetBox.getSelectedItemIndex());
  443. else if (box == &textureBox)
  444. selectTexture (textureBox.getSelectedId());
  445. }
  446. void lookAndFeelChanged() override
  447. {
  448. auto editorBackground = getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground,
  449. Colours::white);
  450. for (int i = tabbedComp.getNumTabs(); i >= 0; --i)
  451. tabbedComp.setTabBackgroundColour (i, editorBackground);
  452. vertexEditorComp.setColour (CodeEditorComponent::backgroundColourId, editorBackground);
  453. fragmentEditorComp.setColour (CodeEditorComponent::backgroundColourId, editorBackground);
  454. }
  455. OpenGLDemo& demo;
  456. Label speedLabel, zoomLabel;
  457. CodeDocument vertexDocument, fragmentDocument;
  458. CodeEditorComponent vertexEditorComp, fragmentEditorComp;
  459. TabbedComponent tabbedComp;
  460. ComboBox presetBox, textureBox;
  461. Label presetLabel, textureLabel;
  462. Slider speedSlider, sizeSlider;
  463. ToggleButton showBackgroundToggle;
  464. OwnedArray<DemoTexture> textures;
  465. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoControlsOverlay)
  466. };
  467. //==============================================================================
  468. /** This is the main demo component - the GL context gets attached to it, and
  469. it implements the OpenGLRenderer callback so that it can do real GL work.
  470. */
  471. class OpenGLDemo : public Component,
  472. private OpenGLRenderer
  473. {
  474. public:
  475. OpenGLDemo()
  476. : doBackgroundDrawing (false),
  477. scale (0.5f), rotationSpeed (0.0f), rotation (0.0f),
  478. textureToUse (nullptr), lastTexture (nullptr)
  479. {
  480. if (MainAppWindow* mw = MainAppWindow::getMainAppWindow())
  481. mw->setRenderingEngine (0);
  482. setOpaque (true);
  483. addAndMakeVisible (controlsOverlay = new DemoControlsOverlay (*this));
  484. openGLContext.setRenderer (this);
  485. openGLContext.attachTo (*this);
  486. openGLContext.setContinuousRepainting (true);
  487. controlsOverlay->initialise();
  488. }
  489. ~OpenGLDemo()
  490. {
  491. openGLContext.detach();
  492. }
  493. void newOpenGLContextCreated() override
  494. {
  495. // nothing to do in this case - we'll initialise our shaders + textures
  496. // on demand, during the render callback.
  497. freeAllContextObjects();
  498. if (controlsOverlay != nullptr)
  499. controlsOverlay->updateShader();
  500. }
  501. void openGLContextClosing() override
  502. {
  503. // When the context is about to close, you must use this callback to delete
  504. // any GPU resources while the context is still current.
  505. freeAllContextObjects();
  506. if (lastTexture != nullptr)
  507. setTexture (lastTexture);
  508. }
  509. void freeAllContextObjects()
  510. {
  511. shape = nullptr;
  512. shader = nullptr;
  513. attributes = nullptr;
  514. uniforms = nullptr;
  515. texture.release();
  516. }
  517. // This is a virtual method in OpenGLRenderer, and is called when it's time
  518. // to do your GL rendering.
  519. void renderOpenGL() override
  520. {
  521. jassert (OpenGLHelpers::isContextActive());
  522. const float desktopScale = (float) openGLContext.getRenderingScale();
  523. OpenGLHelpers::clear (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground,
  524. Colours::lightblue));
  525. if (textureToUse != nullptr)
  526. if (! textureToUse->applyTo (texture))
  527. textureToUse = nullptr;
  528. // First draw our background graphics to demonstrate the OpenGLGraphicsContext class
  529. if (doBackgroundDrawing)
  530. drawBackground2DStuff (desktopScale);
  531. updateShader(); // Check whether we need to compile a new shader
  532. if (shader == nullptr)
  533. return;
  534. // Having used the juce 2D renderer, it will have messed-up a whole load of GL state, so
  535. // we need to initialise some important settings before doing our normal GL 3D drawing..
  536. glEnable (GL_DEPTH_TEST);
  537. glDepthFunc (GL_LESS);
  538. glEnable (GL_BLEND);
  539. glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  540. openGLContext.extensions.glActiveTexture (GL_TEXTURE0);
  541. glEnable (GL_TEXTURE_2D);
  542. glViewport (0, 0, roundToInt (desktopScale * getWidth()), roundToInt (desktopScale * getHeight()));
  543. texture.bind();
  544. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  545. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  546. shader->use();
  547. if (uniforms->projectionMatrix != nullptr)
  548. uniforms->projectionMatrix->setMatrix4 (getProjectionMatrix().mat, 1, false);
  549. if (uniforms->viewMatrix != nullptr)
  550. uniforms->viewMatrix->setMatrix4 (getViewMatrix().mat, 1, false);
  551. if (uniforms->texture != nullptr)
  552. uniforms->texture->set ((GLint) 0);
  553. if (uniforms->lightPosition != nullptr)
  554. uniforms->lightPosition->set (-15.0f, 10.0f, 15.0f, 0.0f);
  555. if (uniforms->bouncingNumber != nullptr)
  556. uniforms->bouncingNumber->set (bouncingNumber.getValue());
  557. shape->draw (openGLContext, *attributes);
  558. // Reset the element buffers so child Components draw correctly
  559. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
  560. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
  561. if (! controlsOverlay->isMouseButtonDown())
  562. rotation += (float) rotationSpeed;
  563. }
  564. Matrix3D<float> getProjectionMatrix() const
  565. {
  566. float w = 1.0f / (scale + 0.1f);
  567. float h = w * getLocalBounds().toFloat().getAspectRatio (false);
  568. return Matrix3D<float>::fromFrustum (-w, w, -h, h, 4.0f, 30.0f);
  569. }
  570. Matrix3D<float> getViewMatrix() const
  571. {
  572. Matrix3D<float> viewMatrix = draggableOrientation.getRotationMatrix()
  573. * Vector3D<float> (0.0f, 1.0f, -10.0f);
  574. Matrix3D<float> rotationMatrix = viewMatrix.rotated (Vector3D<float> (rotation, rotation, -0.3f));
  575. return rotationMatrix * viewMatrix;
  576. }
  577. void setTexture (DemoTexture* t)
  578. {
  579. lastTexture = textureToUse = t;
  580. }
  581. void setShaderProgram (const String& vertexShader, const String& fragmentShader)
  582. {
  583. newVertexShader = vertexShader;
  584. newFragmentShader = fragmentShader;
  585. }
  586. void paint (Graphics&) override {}
  587. void resized() override
  588. {
  589. controlsOverlay->setBounds (getLocalBounds());
  590. draggableOrientation.setViewport (getLocalBounds());
  591. }
  592. Draggable3DOrientation draggableOrientation;
  593. bool doBackgroundDrawing;
  594. float scale, rotationSpeed;
  595. BouncingNumber bouncingNumber;
  596. private:
  597. void drawBackground2DStuff (float desktopScale)
  598. {
  599. // Create an OpenGLGraphicsContext that will draw into this GL window..
  600. ScopedPointer<LowLevelGraphicsContext> glRenderer (createOpenGLGraphicsContext (openGLContext,
  601. roundToInt (desktopScale * getWidth()),
  602. roundToInt (desktopScale * getHeight())));
  603. if (glRenderer != nullptr)
  604. {
  605. Graphics g (*glRenderer);
  606. g.addTransform (AffineTransform::scale (desktopScale));
  607. for (int i = 0; i < numElementsInArray (stars); ++i)
  608. {
  609. float size = 0.25f;
  610. // This stuff just creates a spinning star shape and fills it..
  611. Path p;
  612. p.addStar (Point<float> (getWidth() * stars[i].x.getValue(),
  613. getHeight() * stars[i].y.getValue()), 7,
  614. getHeight() * size * 0.5f,
  615. getHeight() * size,
  616. stars[i].angle.getValue());
  617. float hue = stars[i].hue.getValue();
  618. g.setGradientFill (ColourGradient (Colours::green.withRotatedHue (hue).withAlpha (0.8f),
  619. 0, 0,
  620. Colours::red.withRotatedHue (hue).withAlpha (0.5f),
  621. 0, (float) getHeight(), false));
  622. g.fillPath (p);
  623. }
  624. }
  625. }
  626. OpenGLContext openGLContext;
  627. ScopedPointer<DemoControlsOverlay> controlsOverlay;
  628. float rotation;
  629. ScopedPointer<OpenGLShaderProgram> shader;
  630. ScopedPointer<Shape> shape;
  631. ScopedPointer<Attributes> attributes;
  632. ScopedPointer<Uniforms> uniforms;
  633. OpenGLTexture texture;
  634. DemoTexture* textureToUse, *lastTexture;
  635. String newVertexShader, newFragmentShader;
  636. struct BackgroundStar
  637. {
  638. SlowerBouncingNumber x, y, hue, angle;
  639. };
  640. BackgroundStar stars[3];
  641. //==============================================================================
  642. void updateShader()
  643. {
  644. if (newVertexShader.isNotEmpty() || newFragmentShader.isNotEmpty())
  645. {
  646. ScopedPointer<OpenGLShaderProgram> newShader (new OpenGLShaderProgram (openGLContext));
  647. String statusText;
  648. if (newShader->addVertexShader (OpenGLHelpers::translateVertexShaderToV3 (newVertexShader))
  649. && newShader->addFragmentShader (OpenGLHelpers::translateFragmentShaderToV3 (newFragmentShader))
  650. && newShader->link())
  651. {
  652. shape = nullptr;
  653. attributes = nullptr;
  654. uniforms = nullptr;
  655. shader = newShader;
  656. shader->use();
  657. shape = new Shape (openGLContext);
  658. attributes = new Attributes (openGLContext, *shader);
  659. uniforms = new Uniforms (openGLContext, *shader);
  660. statusText = "GLSL: v" + String (OpenGLShaderProgram::getLanguageVersion(), 2);
  661. }
  662. else
  663. {
  664. statusText = newShader->getLastError();
  665. }
  666. controlsOverlay->statusLabel.setText (statusText, dontSendNotification);
  667. newVertexShader = String();
  668. newFragmentShader = String();
  669. }
  670. }
  671. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLDemo)
  672. };
  673. //==============================================================================
  674. struct ShaderPreset
  675. {
  676. const char* name;
  677. const char* vertexShader;
  678. const char* fragmentShader;
  679. };
  680. static Array<ShaderPreset> getPresets()
  681. {
  682. #define SHADER_DEMO_HEADER \
  683. "/* This is a live OpenGL Shader demo.\n" \
  684. " Edit the shader program below and it will be \n" \
  685. " compiled and applied to the model above!\n" \
  686. "*/\n\n"
  687. ShaderPreset presets[] =
  688. {
  689. {
  690. "Texture + Lighting",
  691. SHADER_DEMO_HEADER
  692. "attribute vec4 position;\n"
  693. "attribute vec4 normal;\n"
  694. "attribute vec4 sourceColour;\n"
  695. "attribute vec2 textureCoordIn;\n"
  696. "\n"
  697. "uniform mat4 projectionMatrix;\n"
  698. "uniform mat4 viewMatrix;\n"
  699. "uniform vec4 lightPosition;\n"
  700. "\n"
  701. "varying vec4 destinationColour;\n"
  702. "varying vec2 textureCoordOut;\n"
  703. "varying float lightIntensity;\n"
  704. "\n"
  705. "void main()\n"
  706. "{\n"
  707. " destinationColour = sourceColour;\n"
  708. " textureCoordOut = textureCoordIn;\n"
  709. "\n"
  710. " vec4 light = viewMatrix * lightPosition;\n"
  711. " lightIntensity = dot (light, normal);\n"
  712. "\n"
  713. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  714. "}\n",
  715. SHADER_DEMO_HEADER
  716. #if JUCE_OPENGL_ES
  717. "varying lowp vec4 destinationColour;\n"
  718. "varying lowp vec2 textureCoordOut;\n"
  719. "varying highp float lightIntensity;\n"
  720. #else
  721. "varying vec4 destinationColour;\n"
  722. "varying vec2 textureCoordOut;\n"
  723. "varying float lightIntensity;\n"
  724. #endif
  725. "\n"
  726. "uniform sampler2D demoTexture;\n"
  727. "\n"
  728. "void main()\n"
  729. "{\n"
  730. #if JUCE_OPENGL_ES
  731. " highp float l = max (0.3, lightIntensity * 0.3);\n"
  732. " highp vec4 colour = vec4 (l, l, l, 1.0);\n"
  733. #else
  734. " float l = max (0.3, lightIntensity * 0.3);\n"
  735. " vec4 colour = vec4 (l, l, l, 1.0);\n"
  736. #endif
  737. " gl_FragColor = colour * texture2D (demoTexture, textureCoordOut);\n"
  738. "}\n"
  739. },
  740. {
  741. "Textured",
  742. SHADER_DEMO_HEADER
  743. "attribute vec4 position;\n"
  744. "attribute vec4 sourceColour;\n"
  745. "attribute vec2 textureCoordIn;\n"
  746. "\n"
  747. "uniform mat4 projectionMatrix;\n"
  748. "uniform mat4 viewMatrix;\n"
  749. "\n"
  750. "varying vec4 destinationColour;\n"
  751. "varying vec2 textureCoordOut;\n"
  752. "\n"
  753. "void main()\n"
  754. "{\n"
  755. " destinationColour = sourceColour;\n"
  756. " textureCoordOut = textureCoordIn;\n"
  757. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  758. "}\n",
  759. SHADER_DEMO_HEADER
  760. #if JUCE_OPENGL_ES
  761. "varying lowp vec4 destinationColour;\n"
  762. "varying lowp vec2 textureCoordOut;\n"
  763. #else
  764. "varying vec4 destinationColour;\n"
  765. "varying vec2 textureCoordOut;\n"
  766. #endif
  767. "\n"
  768. "uniform sampler2D demoTexture;\n"
  769. "\n"
  770. "void main()\n"
  771. "{\n"
  772. " gl_FragColor = texture2D (demoTexture, textureCoordOut);\n"
  773. "}\n"
  774. },
  775. {
  776. "Flat Colour",
  777. SHADER_DEMO_HEADER
  778. "attribute vec4 position;\n"
  779. "attribute vec4 sourceColour;\n"
  780. "attribute vec2 textureCoordIn;\n"
  781. "\n"
  782. "uniform mat4 projectionMatrix;\n"
  783. "uniform mat4 viewMatrix;\n"
  784. "\n"
  785. "varying vec4 destinationColour;\n"
  786. "varying vec2 textureCoordOut;\n"
  787. "\n"
  788. "void main()\n"
  789. "{\n"
  790. " destinationColour = sourceColour;\n"
  791. " textureCoordOut = textureCoordIn;\n"
  792. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  793. "}\n",
  794. SHADER_DEMO_HEADER
  795. #if JUCE_OPENGL_ES
  796. "varying lowp vec4 destinationColour;\n"
  797. "varying lowp vec2 textureCoordOut;\n"
  798. #else
  799. "varying vec4 destinationColour;\n"
  800. "varying vec2 textureCoordOut;\n"
  801. #endif
  802. "\n"
  803. "void main()\n"
  804. "{\n"
  805. " gl_FragColor = destinationColour;\n"
  806. "}\n"
  807. },
  808. {
  809. "Rainbow",
  810. SHADER_DEMO_HEADER
  811. "attribute vec4 position;\n"
  812. "attribute vec4 sourceColour;\n"
  813. "attribute vec2 textureCoordIn;\n"
  814. "\n"
  815. "uniform mat4 projectionMatrix;\n"
  816. "uniform mat4 viewMatrix;\n"
  817. "\n"
  818. "varying vec4 destinationColour;\n"
  819. "varying vec2 textureCoordOut;\n"
  820. "\n"
  821. "varying float xPos;\n"
  822. "varying float yPos;\n"
  823. "varying float zPos;\n"
  824. "\n"
  825. "void main()\n"
  826. "{\n"
  827. " vec4 v = vec4 (position);\n"
  828. " xPos = clamp (v.x, 0.0, 1.0);\n"
  829. " yPos = clamp (v.y, 0.0, 1.0);\n"
  830. " zPos = clamp (v.z, 0.0, 1.0);\n"
  831. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  832. "}",
  833. SHADER_DEMO_HEADER
  834. #if JUCE_OPENGL_ES
  835. "varying lowp vec4 destinationColour;\n"
  836. "varying lowp vec2 textureCoordOut;\n"
  837. "varying lowp float xPos;\n"
  838. "varying lowp float yPos;\n"
  839. "varying lowp float zPos;\n"
  840. #else
  841. "varying vec4 destinationColour;\n"
  842. "varying vec2 textureCoordOut;\n"
  843. "varying float xPos;\n"
  844. "varying float yPos;\n"
  845. "varying float zPos;\n"
  846. #endif
  847. "\n"
  848. "void main()\n"
  849. "{\n"
  850. " gl_FragColor = vec4 (xPos, yPos, zPos, 1.0);\n"
  851. "}"
  852. },
  853. {
  854. "Changing Colour",
  855. SHADER_DEMO_HEADER
  856. "attribute vec4 position;\n"
  857. "attribute vec2 textureCoordIn;\n"
  858. "\n"
  859. "uniform mat4 projectionMatrix;\n"
  860. "uniform mat4 viewMatrix;\n"
  861. "\n"
  862. "varying vec2 textureCoordOut;\n"
  863. "\n"
  864. "void main()\n"
  865. "{\n"
  866. " textureCoordOut = textureCoordIn;\n"
  867. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  868. "}\n",
  869. SHADER_DEMO_HEADER
  870. "#define PI 3.1415926535897932384626433832795\n"
  871. "\n"
  872. #if JUCE_OPENGL_ES
  873. "precision mediump float;\n"
  874. "varying lowp vec2 textureCoordOut;\n"
  875. #else
  876. "varying vec2 textureCoordOut;\n"
  877. #endif
  878. "uniform float bouncingNumber;\n"
  879. "\n"
  880. "void main()\n"
  881. "{\n"
  882. " float b = bouncingNumber;\n"
  883. " float n = b * PI * 2.0;\n"
  884. " float sn = (sin (n * textureCoordOut.x) * 0.5) + 0.5;\n"
  885. " float cn = (sin (n * textureCoordOut.y) * 0.5) + 0.5;\n"
  886. "\n"
  887. " vec4 col = vec4 (b, sn, cn, 1.0);\n"
  888. " gl_FragColor = col;\n"
  889. "}\n"
  890. },
  891. {
  892. "Simple Light",
  893. SHADER_DEMO_HEADER
  894. "attribute vec4 position;\n"
  895. "attribute vec4 normal;\n"
  896. "\n"
  897. "uniform mat4 projectionMatrix;\n"
  898. "uniform mat4 viewMatrix;\n"
  899. "uniform vec4 lightPosition;\n"
  900. "\n"
  901. "varying float lightIntensity;\n"
  902. "\n"
  903. "void main()\n"
  904. "{\n"
  905. " vec4 light = viewMatrix * lightPosition;\n"
  906. " lightIntensity = dot (light, normal);\n"
  907. "\n"
  908. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  909. "}\n",
  910. SHADER_DEMO_HEADER
  911. #if JUCE_OPENGL_ES
  912. "varying highp float lightIntensity;\n"
  913. #else
  914. "varying float lightIntensity;\n"
  915. #endif
  916. "\n"
  917. "void main()\n"
  918. "{\n"
  919. #if JUCE_OPENGL_ES
  920. " highp float l = lightIntensity * 0.25;\n"
  921. " highp vec4 colour = vec4 (l, l, l, 1.0);\n"
  922. #else
  923. " float l = lightIntensity * 0.25;\n"
  924. " vec4 colour = vec4 (l, l, l, 1.0);\n"
  925. #endif
  926. "\n"
  927. " gl_FragColor = colour;\n"
  928. "}\n"
  929. },
  930. {
  931. "Flattened",
  932. SHADER_DEMO_HEADER
  933. "attribute vec4 position;\n"
  934. "attribute vec4 normal;\n"
  935. "\n"
  936. "uniform mat4 projectionMatrix;\n"
  937. "uniform mat4 viewMatrix;\n"
  938. "uniform vec4 lightPosition;\n"
  939. "\n"
  940. "varying float lightIntensity;\n"
  941. "\n"
  942. "void main()\n"
  943. "{\n"
  944. " vec4 light = viewMatrix * lightPosition;\n"
  945. " lightIntensity = dot (light, normal);\n"
  946. "\n"
  947. " vec4 v = vec4 (position);\n"
  948. " v.z = v.z * 0.1;\n"
  949. "\n"
  950. " gl_Position = projectionMatrix * viewMatrix * v;\n"
  951. "}\n",
  952. SHADER_DEMO_HEADER
  953. #if JUCE_OPENGL_ES
  954. "varying highp float lightIntensity;\n"
  955. #else
  956. "varying float lightIntensity;\n"
  957. #endif
  958. "\n"
  959. "void main()\n"
  960. "{\n"
  961. #if JUCE_OPENGL_ES
  962. " highp float l = lightIntensity * 0.25;\n"
  963. " highp vec4 colour = vec4 (l, l, l, 1.0);\n"
  964. #else
  965. " float l = lightIntensity * 0.25;\n"
  966. " vec4 colour = vec4 (l, l, l, 1.0);\n"
  967. #endif
  968. "\n"
  969. " gl_FragColor = colour;\n"
  970. "}\n"
  971. },
  972. {
  973. "Toon Shader",
  974. SHADER_DEMO_HEADER
  975. "attribute vec4 position;\n"
  976. "attribute vec4 normal;\n"
  977. "\n"
  978. "uniform mat4 projectionMatrix;\n"
  979. "uniform mat4 viewMatrix;\n"
  980. "uniform vec4 lightPosition;\n"
  981. "\n"
  982. "varying float lightIntensity;\n"
  983. "\n"
  984. "void main()\n"
  985. "{\n"
  986. " vec4 light = viewMatrix * lightPosition;\n"
  987. " lightIntensity = dot (light, normal);\n"
  988. "\n"
  989. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  990. "}\n",
  991. SHADER_DEMO_HEADER
  992. #if JUCE_OPENGL_ES
  993. "varying highp float lightIntensity;\n"
  994. #else
  995. "varying float lightIntensity;\n"
  996. #endif
  997. "\n"
  998. "void main()\n"
  999. "{\n"
  1000. #if JUCE_OPENGL_ES
  1001. " highp float intensity = lightIntensity * 0.5;\n"
  1002. " highp vec4 colour;\n"
  1003. #else
  1004. " float intensity = lightIntensity * 0.5;\n"
  1005. " vec4 colour;\n"
  1006. #endif
  1007. "\n"
  1008. " if (intensity > 0.95)\n"
  1009. " colour = vec4 (1.0, 0.5, 0.5, 1.0);\n"
  1010. " else if (intensity > 0.5)\n"
  1011. " colour = vec4 (0.6, 0.3, 0.3, 1.0);\n"
  1012. " else if (intensity > 0.25)\n"
  1013. " colour = vec4 (0.4, 0.2, 0.2, 1.0);\n"
  1014. " else\n"
  1015. " colour = vec4 (0.2, 0.1, 0.1, 1.0);\n"
  1016. "\n"
  1017. " gl_FragColor = colour;\n"
  1018. "}\n"
  1019. }
  1020. };
  1021. return Array<ShaderPreset> (presets, numElementsInArray (presets));
  1022. }
  1023. };
  1024. // This static object will register this demo type in a global list of demos..
  1025. static JuceDemoType<OpenGLDemoClasses::OpenGLDemo> demo ("20 Graphics: OpenGL");
  1026. #endif