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.

1234 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. Colour editorBackground = dynamic_cast<LookAndFeel_V4*> (&LookAndFeel::getDefaultLookAndFeel())
  300. ? getLookAndFeel().findColour (ResizableWindow::backgroundColourId)
  301. : Colours::white;
  302. addAndMakeVisible (tabbedComp);
  303. tabbedComp.setTabBarDepth (25);
  304. tabbedComp.setColour (TabbedButtonBar::tabTextColourId, Colours::grey);
  305. tabbedComp.addTab ("Vertex", editorBackground, &vertexEditorComp, false);
  306. tabbedComp.addTab ("Fragment", editorBackground, &fragmentEditorComp, false);
  307. vertexEditorComp.setColour (CodeEditorComponent::backgroundColourId, editorBackground);
  308. fragmentEditorComp.setColour (CodeEditorComponent::backgroundColourId, editorBackground);
  309. vertexDocument.addListener (this);
  310. fragmentDocument.addListener (this);
  311. textures.add (new BuiltInTexture ("Portmeirion", BinaryData::portmeirion_jpg, BinaryData::portmeirion_jpgSize));
  312. textures.add (new BuiltInTexture ("Tiled Background", BinaryData::tile_background_png, BinaryData::tile_background_pngSize));
  313. textures.add (new BuiltInTexture ("JUCE logo", BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize));
  314. textures.add (new DynamicTexture());
  315. addAndMakeVisible (textureBox);
  316. textureBox.addListener (this);
  317. updateTexturesList();
  318. addAndMakeVisible (presetBox);
  319. presetBox.addListener (this);
  320. Array<ShaderPreset> presets (getPresets());
  321. StringArray presetNames;
  322. for (int i = 0; i < presets.size(); ++i)
  323. presetBox.addItem (presets[i].name, i + 1);
  324. addAndMakeVisible (presetLabel);
  325. presetLabel.setText ("Shader Preset:", dontSendNotification);
  326. presetLabel.attachToComponent (&presetBox, true);
  327. addAndMakeVisible (textureLabel);
  328. textureLabel.setText ("Texture:", dontSendNotification);
  329. textureLabel.attachToComponent (&textureBox, true);
  330. }
  331. void initialise()
  332. {
  333. showBackgroundToggle.setToggleState (false, sendNotification);
  334. textureBox.setSelectedItemIndex (0);
  335. presetBox.setSelectedItemIndex (0);
  336. speedSlider.setValue (0.01);
  337. sizeSlider.setValue (0.5);
  338. }
  339. void resized() override
  340. {
  341. Rectangle<int> area (getLocalBounds().reduced (4));
  342. Rectangle<int> top (area.removeFromTop (75));
  343. Rectangle<int> sliders (top.removeFromRight (area.getWidth() / 2));
  344. showBackgroundToggle.setBounds (sliders.removeFromBottom (25));
  345. speedSlider.setBounds (sliders.removeFromBottom (25));
  346. sizeSlider.setBounds (sliders.removeFromBottom (25));
  347. top.removeFromRight (70);
  348. statusLabel.setBounds (top);
  349. Rectangle<int> shaderArea (area.removeFromBottom (area.getHeight() / 2));
  350. Rectangle<int> presets (shaderArea.removeFromTop (25));
  351. presets.removeFromLeft (100);
  352. presetBox.setBounds (presets.removeFromLeft (150));
  353. presets.removeFromLeft (100);
  354. textureBox.setBounds (presets);
  355. shaderArea.removeFromTop (4);
  356. tabbedComp.setBounds (shaderArea);
  357. }
  358. void mouseDown (const MouseEvent& e) override
  359. {
  360. demo.draggableOrientation.mouseDown (e.getPosition());
  361. }
  362. void mouseDrag (const MouseEvent& e) override
  363. {
  364. demo.draggableOrientation.mouseDrag (e.getPosition());
  365. }
  366. void mouseWheelMove (const MouseEvent&, const MouseWheelDetails& d) override
  367. {
  368. sizeSlider.setValue (sizeSlider.getValue() + d.deltaY);
  369. }
  370. void mouseMagnify (const MouseEvent&, float magnifyAmmount) override
  371. {
  372. sizeSlider.setValue (sizeSlider.getValue() + magnifyAmmount - 1.0f);
  373. }
  374. void selectPreset (int preset)
  375. {
  376. const ShaderPreset& p = getPresets()[preset];
  377. vertexDocument.replaceAllContent (p.vertexShader);
  378. fragmentDocument.replaceAllContent (p.fragmentShader);
  379. startTimer (1);
  380. }
  381. void selectTexture (int itemID)
  382. {
  383. #if JUCE_MODAL_LOOPS_PERMITTED
  384. if (itemID == 1000)
  385. {
  386. static File lastLocation = File::getSpecialLocation (File::userPicturesDirectory);
  387. FileChooser fc ("Choose an image to open...", lastLocation, "*.jpg;*.jpeg;*.png;*.gif");
  388. if (fc.browseForFileToOpen())
  389. {
  390. lastLocation = fc.getResult();
  391. textures.add (new TextureFromFile (fc.getResult()));
  392. updateTexturesList();
  393. textureBox.setSelectedId (textures.size());
  394. }
  395. }
  396. else
  397. #endif
  398. {
  399. if (DemoTexture* t = textures [itemID - 1])
  400. demo.setTexture (t);
  401. }
  402. }
  403. void updateTexturesList()
  404. {
  405. textureBox.clear();
  406. for (int i = 0; i < textures.size(); ++i)
  407. textureBox.addItem (textures.getUnchecked(i)->name, i + 1);
  408. #if JUCE_MODAL_LOOPS_PERMITTED
  409. textureBox.addSeparator();
  410. textureBox.addItem ("Load from a file...", 1000);
  411. #endif
  412. }
  413. void updateShader()
  414. {
  415. startTimer (10);
  416. }
  417. Label statusLabel;
  418. private:
  419. void sliderValueChanged (Slider*) override
  420. {
  421. demo.scale = (float) sizeSlider.getValue();
  422. demo.rotationSpeed = (float) speedSlider.getValue();
  423. }
  424. void buttonClicked (Button*) override
  425. {
  426. demo.doBackgroundDrawing = showBackgroundToggle.getToggleState();
  427. }
  428. enum { shaderLinkDelay = 500 };
  429. void codeDocumentTextInserted (const String& /*newText*/, int /*insertIndex*/) override
  430. {
  431. startTimer (shaderLinkDelay);
  432. }
  433. void codeDocumentTextDeleted (int /*startIndex*/, int /*endIndex*/) override
  434. {
  435. startTimer (shaderLinkDelay);
  436. }
  437. void timerCallback() override
  438. {
  439. stopTimer();
  440. demo.setShaderProgram (vertexDocument.getAllContent(),
  441. fragmentDocument.getAllContent());
  442. }
  443. void comboBoxChanged (ComboBox* box) override
  444. {
  445. if (box == &presetBox)
  446. selectPreset (presetBox.getSelectedItemIndex());
  447. else if (box == &textureBox)
  448. selectTexture (textureBox.getSelectedId());
  449. }
  450. OpenGLDemo& demo;
  451. Label speedLabel, zoomLabel;
  452. CodeDocument vertexDocument, fragmentDocument;
  453. CodeEditorComponent vertexEditorComp, fragmentEditorComp;
  454. TabbedComponent tabbedComp;
  455. ComboBox presetBox, textureBox;
  456. Label presetLabel, textureLabel;
  457. Slider speedSlider, sizeSlider;
  458. ToggleButton showBackgroundToggle;
  459. OwnedArray<DemoTexture> textures;
  460. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoControlsOverlay)
  461. };
  462. //==============================================================================
  463. /** This is the main demo component - the GL context gets attached to it, and
  464. it implements the OpenGLRenderer callback so that it can do real GL work.
  465. */
  466. class OpenGLDemo : public Component,
  467. private OpenGLRenderer
  468. {
  469. public:
  470. OpenGLDemo()
  471. : doBackgroundDrawing (false),
  472. scale (0.5f), rotationSpeed (0.0f), rotation (0.0f),
  473. textureToUse (nullptr), lastTexture (nullptr)
  474. {
  475. if (MainAppWindow* mw = MainAppWindow::getMainAppWindow())
  476. mw->setRenderingEngine (0);
  477. setOpaque (true);
  478. addAndMakeVisible (controlsOverlay = new DemoControlsOverlay (*this));
  479. openGLContext.setRenderer (this);
  480. openGLContext.attachTo (*this);
  481. openGLContext.setContinuousRepainting (true);
  482. controlsOverlay->initialise();
  483. }
  484. ~OpenGLDemo()
  485. {
  486. openGLContext.detach();
  487. }
  488. void newOpenGLContextCreated() override
  489. {
  490. // nothing to do in this case - we'll initialise our shaders + textures
  491. // on demand, during the render callback.
  492. freeAllContextObjects();
  493. if (controlsOverlay != nullptr)
  494. controlsOverlay->updateShader();
  495. }
  496. void openGLContextClosing() override
  497. {
  498. // When the context is about to close, you must use this callback to delete
  499. // any GPU resources while the context is still current.
  500. freeAllContextObjects();
  501. if (lastTexture != nullptr)
  502. setTexture (lastTexture);
  503. }
  504. void freeAllContextObjects()
  505. {
  506. shape = nullptr;
  507. shader = nullptr;
  508. attributes = nullptr;
  509. uniforms = nullptr;
  510. texture.release();
  511. }
  512. // This is a virtual method in OpenGLRenderer, and is called when it's time
  513. // to do your GL rendering.
  514. void renderOpenGL() override
  515. {
  516. jassert (OpenGLHelpers::isContextActive());
  517. const float desktopScale = (float) openGLContext.getRenderingScale();
  518. OpenGLHelpers::clear (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground,
  519. Colours::lightblue));
  520. if (textureToUse != nullptr)
  521. if (! textureToUse->applyTo (texture))
  522. textureToUse = nullptr;
  523. // First draw our background graphics to demonstrate the OpenGLGraphicsContext class
  524. if (doBackgroundDrawing)
  525. drawBackground2DStuff (desktopScale);
  526. updateShader(); // Check whether we need to compile a new shader
  527. if (shader == nullptr)
  528. return;
  529. // Having used the juce 2D renderer, it will have messed-up a whole load of GL state, so
  530. // we need to initialise some important settings before doing our normal GL 3D drawing..
  531. glEnable (GL_DEPTH_TEST);
  532. glDepthFunc (GL_LESS);
  533. glEnable (GL_BLEND);
  534. glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  535. openGLContext.extensions.glActiveTexture (GL_TEXTURE0);
  536. glEnable (GL_TEXTURE_2D);
  537. glViewport (0, 0, roundToInt (desktopScale * getWidth()), roundToInt (desktopScale * getHeight()));
  538. texture.bind();
  539. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  540. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  541. shader->use();
  542. if (uniforms->projectionMatrix != nullptr)
  543. uniforms->projectionMatrix->setMatrix4 (getProjectionMatrix().mat, 1, false);
  544. if (uniforms->viewMatrix != nullptr)
  545. uniforms->viewMatrix->setMatrix4 (getViewMatrix().mat, 1, false);
  546. if (uniforms->texture != nullptr)
  547. uniforms->texture->set ((GLint) 0);
  548. if (uniforms->lightPosition != nullptr)
  549. uniforms->lightPosition->set (-15.0f, 10.0f, 15.0f, 0.0f);
  550. if (uniforms->bouncingNumber != nullptr)
  551. uniforms->bouncingNumber->set (bouncingNumber.getValue());
  552. shape->draw (openGLContext, *attributes);
  553. // Reset the element buffers so child Components draw correctly
  554. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
  555. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
  556. if (! controlsOverlay->isMouseButtonDown())
  557. rotation += (float) rotationSpeed;
  558. }
  559. Matrix3D<float> getProjectionMatrix() const
  560. {
  561. float w = 1.0f / (scale + 0.1f);
  562. float h = w * getLocalBounds().toFloat().getAspectRatio (false);
  563. return Matrix3D<float>::fromFrustum (-w, w, -h, h, 4.0f, 30.0f);
  564. }
  565. Matrix3D<float> getViewMatrix() const
  566. {
  567. Matrix3D<float> viewMatrix = draggableOrientation.getRotationMatrix()
  568. * Vector3D<float> (0.0f, 1.0f, -10.0f);
  569. Matrix3D<float> rotationMatrix = viewMatrix.rotated (Vector3D<float> (rotation, rotation, -0.3f));
  570. return rotationMatrix * viewMatrix;
  571. }
  572. void setTexture (DemoTexture* t)
  573. {
  574. lastTexture = textureToUse = t;
  575. }
  576. void setShaderProgram (const String& vertexShader, const String& fragmentShader)
  577. {
  578. newVertexShader = vertexShader;
  579. newFragmentShader = fragmentShader;
  580. }
  581. void paint (Graphics&) override {}
  582. void resized() override
  583. {
  584. controlsOverlay->setBounds (getLocalBounds());
  585. draggableOrientation.setViewport (getLocalBounds());
  586. }
  587. Draggable3DOrientation draggableOrientation;
  588. bool doBackgroundDrawing;
  589. float scale, rotationSpeed;
  590. BouncingNumber bouncingNumber;
  591. private:
  592. void drawBackground2DStuff (float desktopScale)
  593. {
  594. // Create an OpenGLGraphicsContext that will draw into this GL window..
  595. ScopedPointer<LowLevelGraphicsContext> glRenderer (createOpenGLGraphicsContext (openGLContext,
  596. roundToInt (desktopScale * getWidth()),
  597. roundToInt (desktopScale * getHeight())));
  598. if (glRenderer != nullptr)
  599. {
  600. Graphics g (*glRenderer);
  601. g.addTransform (AffineTransform::scale (desktopScale));
  602. for (int i = 0; i < numElementsInArray (stars); ++i)
  603. {
  604. float size = 0.25f;
  605. // This stuff just creates a spinning star shape and fills it..
  606. Path p;
  607. p.addStar (Point<float> (getWidth() * stars[i].x.getValue(),
  608. getHeight() * stars[i].y.getValue()), 7,
  609. getHeight() * size * 0.5f,
  610. getHeight() * size,
  611. stars[i].angle.getValue());
  612. float hue = stars[i].hue.getValue();
  613. g.setGradientFill (ColourGradient (Colours::green.withRotatedHue (hue).withAlpha (0.8f),
  614. 0, 0,
  615. Colours::red.withRotatedHue (hue).withAlpha (0.5f),
  616. 0, (float) getHeight(), false));
  617. g.fillPath (p);
  618. }
  619. }
  620. }
  621. OpenGLContext openGLContext;
  622. ScopedPointer<DemoControlsOverlay> controlsOverlay;
  623. float rotation;
  624. ScopedPointer<OpenGLShaderProgram> shader;
  625. ScopedPointer<Shape> shape;
  626. ScopedPointer<Attributes> attributes;
  627. ScopedPointer<Uniforms> uniforms;
  628. OpenGLTexture texture;
  629. DemoTexture* textureToUse, *lastTexture;
  630. String newVertexShader, newFragmentShader;
  631. struct BackgroundStar
  632. {
  633. SlowerBouncingNumber x, y, hue, angle;
  634. };
  635. BackgroundStar stars[3];
  636. //==============================================================================
  637. void updateShader()
  638. {
  639. if (newVertexShader.isNotEmpty() || newFragmentShader.isNotEmpty())
  640. {
  641. ScopedPointer<OpenGLShaderProgram> newShader (new OpenGLShaderProgram (openGLContext));
  642. String statusText;
  643. if (newShader->addVertexShader (OpenGLHelpers::translateVertexShaderToV3 (newVertexShader))
  644. && newShader->addFragmentShader (OpenGLHelpers::translateFragmentShaderToV3 (newFragmentShader))
  645. && newShader->link())
  646. {
  647. shape = nullptr;
  648. attributes = nullptr;
  649. uniforms = nullptr;
  650. shader = newShader;
  651. shader->use();
  652. shape = new Shape (openGLContext);
  653. attributes = new Attributes (openGLContext, *shader);
  654. uniforms = new Uniforms (openGLContext, *shader);
  655. statusText = "GLSL: v" + String (OpenGLShaderProgram::getLanguageVersion(), 2);
  656. }
  657. else
  658. {
  659. statusText = newShader->getLastError();
  660. }
  661. controlsOverlay->statusLabel.setText (statusText, dontSendNotification);
  662. newVertexShader = String();
  663. newFragmentShader = String();
  664. }
  665. }
  666. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLDemo)
  667. };
  668. //==============================================================================
  669. struct ShaderPreset
  670. {
  671. const char* name;
  672. const char* vertexShader;
  673. const char* fragmentShader;
  674. };
  675. static Array<ShaderPreset> getPresets()
  676. {
  677. #define SHADER_DEMO_HEADER \
  678. "/* This is a live OpenGL Shader demo.\n" \
  679. " Edit the shader program below and it will be \n" \
  680. " compiled and applied to the model above!\n" \
  681. "*/\n\n"
  682. ShaderPreset presets[] =
  683. {
  684. {
  685. "Texture + Lighting",
  686. SHADER_DEMO_HEADER
  687. "attribute vec4 position;\n"
  688. "attribute vec4 normal;\n"
  689. "attribute vec4 sourceColour;\n"
  690. "attribute vec2 textureCoordIn;\n"
  691. "\n"
  692. "uniform mat4 projectionMatrix;\n"
  693. "uniform mat4 viewMatrix;\n"
  694. "uniform vec4 lightPosition;\n"
  695. "\n"
  696. "varying vec4 destinationColour;\n"
  697. "varying vec2 textureCoordOut;\n"
  698. "varying float lightIntensity;\n"
  699. "\n"
  700. "void main()\n"
  701. "{\n"
  702. " destinationColour = sourceColour;\n"
  703. " textureCoordOut = textureCoordIn;\n"
  704. "\n"
  705. " vec4 light = viewMatrix * lightPosition;\n"
  706. " lightIntensity = dot (light, normal);\n"
  707. "\n"
  708. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  709. "}\n",
  710. SHADER_DEMO_HEADER
  711. #if JUCE_OPENGL_ES
  712. "varying lowp vec4 destinationColour;\n"
  713. "varying lowp vec2 textureCoordOut;\n"
  714. "varying highp float lightIntensity;\n"
  715. #else
  716. "varying vec4 destinationColour;\n"
  717. "varying vec2 textureCoordOut;\n"
  718. "varying float lightIntensity;\n"
  719. #endif
  720. "\n"
  721. "uniform sampler2D demoTexture;\n"
  722. "\n"
  723. "void main()\n"
  724. "{\n"
  725. #if JUCE_OPENGL_ES
  726. " highp float l = max (0.3, lightIntensity * 0.3);\n"
  727. " highp vec4 colour = vec4 (l, l, l, 1.0);\n"
  728. #else
  729. " float l = max (0.3, lightIntensity * 0.3);\n"
  730. " vec4 colour = vec4 (l, l, l, 1.0);\n"
  731. #endif
  732. " gl_FragColor = colour * texture2D (demoTexture, textureCoordOut);\n"
  733. "}\n"
  734. },
  735. {
  736. "Textured",
  737. SHADER_DEMO_HEADER
  738. "attribute vec4 position;\n"
  739. "attribute vec4 sourceColour;\n"
  740. "attribute vec2 textureCoordIn;\n"
  741. "\n"
  742. "uniform mat4 projectionMatrix;\n"
  743. "uniform mat4 viewMatrix;\n"
  744. "\n"
  745. "varying vec4 destinationColour;\n"
  746. "varying vec2 textureCoordOut;\n"
  747. "\n"
  748. "void main()\n"
  749. "{\n"
  750. " destinationColour = sourceColour;\n"
  751. " textureCoordOut = textureCoordIn;\n"
  752. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  753. "}\n",
  754. SHADER_DEMO_HEADER
  755. #if JUCE_OPENGL_ES
  756. "varying lowp vec4 destinationColour;\n"
  757. "varying lowp vec2 textureCoordOut;\n"
  758. #else
  759. "varying vec4 destinationColour;\n"
  760. "varying vec2 textureCoordOut;\n"
  761. #endif
  762. "\n"
  763. "uniform sampler2D demoTexture;\n"
  764. "\n"
  765. "void main()\n"
  766. "{\n"
  767. " gl_FragColor = texture2D (demoTexture, textureCoordOut);\n"
  768. "}\n"
  769. },
  770. {
  771. "Flat Colour",
  772. SHADER_DEMO_HEADER
  773. "attribute vec4 position;\n"
  774. "attribute vec4 sourceColour;\n"
  775. "attribute vec2 textureCoordIn;\n"
  776. "\n"
  777. "uniform mat4 projectionMatrix;\n"
  778. "uniform mat4 viewMatrix;\n"
  779. "\n"
  780. "varying vec4 destinationColour;\n"
  781. "varying vec2 textureCoordOut;\n"
  782. "\n"
  783. "void main()\n"
  784. "{\n"
  785. " destinationColour = sourceColour;\n"
  786. " textureCoordOut = textureCoordIn;\n"
  787. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  788. "}\n",
  789. SHADER_DEMO_HEADER
  790. #if JUCE_OPENGL_ES
  791. "varying lowp vec4 destinationColour;\n"
  792. "varying lowp vec2 textureCoordOut;\n"
  793. #else
  794. "varying vec4 destinationColour;\n"
  795. "varying vec2 textureCoordOut;\n"
  796. #endif
  797. "\n"
  798. "void main()\n"
  799. "{\n"
  800. " gl_FragColor = destinationColour;\n"
  801. "}\n"
  802. },
  803. {
  804. "Rainbow",
  805. SHADER_DEMO_HEADER
  806. "attribute vec4 position;\n"
  807. "attribute vec4 sourceColour;\n"
  808. "attribute vec2 textureCoordIn;\n"
  809. "\n"
  810. "uniform mat4 projectionMatrix;\n"
  811. "uniform mat4 viewMatrix;\n"
  812. "\n"
  813. "varying vec4 destinationColour;\n"
  814. "varying vec2 textureCoordOut;\n"
  815. "\n"
  816. "varying float xPos;\n"
  817. "varying float yPos;\n"
  818. "varying float zPos;\n"
  819. "\n"
  820. "void main()\n"
  821. "{\n"
  822. " vec4 v = vec4 (position);\n"
  823. " xPos = clamp (v.x, 0.0, 1.0);\n"
  824. " yPos = clamp (v.y, 0.0, 1.0);\n"
  825. " zPos = clamp (v.z, 0.0, 1.0);\n"
  826. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  827. "}",
  828. SHADER_DEMO_HEADER
  829. #if JUCE_OPENGL_ES
  830. "varying lowp vec4 destinationColour;\n"
  831. "varying lowp vec2 textureCoordOut;\n"
  832. "varying lowp float xPos;\n"
  833. "varying lowp float yPos;\n"
  834. "varying lowp float zPos;\n"
  835. #else
  836. "varying vec4 destinationColour;\n"
  837. "varying vec2 textureCoordOut;\n"
  838. "varying float xPos;\n"
  839. "varying float yPos;\n"
  840. "varying float zPos;\n"
  841. #endif
  842. "\n"
  843. "void main()\n"
  844. "{\n"
  845. " gl_FragColor = vec4 (xPos, yPos, zPos, 1.0);\n"
  846. "}"
  847. },
  848. {
  849. "Changing Colour",
  850. SHADER_DEMO_HEADER
  851. "attribute vec4 position;\n"
  852. "attribute vec2 textureCoordIn;\n"
  853. "\n"
  854. "uniform mat4 projectionMatrix;\n"
  855. "uniform mat4 viewMatrix;\n"
  856. "\n"
  857. "varying vec2 textureCoordOut;\n"
  858. "\n"
  859. "void main()\n"
  860. "{\n"
  861. " textureCoordOut = textureCoordIn;\n"
  862. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  863. "}\n",
  864. SHADER_DEMO_HEADER
  865. "#define PI 3.1415926535897932384626433832795\n"
  866. "\n"
  867. #if JUCE_OPENGL_ES
  868. "precision mediump float;\n"
  869. "varying lowp vec2 textureCoordOut;\n"
  870. #else
  871. "varying vec2 textureCoordOut;\n"
  872. #endif
  873. "uniform float bouncingNumber;\n"
  874. "\n"
  875. "void main()\n"
  876. "{\n"
  877. " float b = bouncingNumber;\n"
  878. " float n = b * PI * 2.0;\n"
  879. " float sn = (sin (n * textureCoordOut.x) * 0.5) + 0.5;\n"
  880. " float cn = (sin (n * textureCoordOut.y) * 0.5) + 0.5;\n"
  881. "\n"
  882. " vec4 col = vec4 (b, sn, cn, 1.0);\n"
  883. " gl_FragColor = col;\n"
  884. "}\n"
  885. },
  886. {
  887. "Simple Light",
  888. SHADER_DEMO_HEADER
  889. "attribute vec4 position;\n"
  890. "attribute vec4 normal;\n"
  891. "\n"
  892. "uniform mat4 projectionMatrix;\n"
  893. "uniform mat4 viewMatrix;\n"
  894. "uniform vec4 lightPosition;\n"
  895. "\n"
  896. "varying float lightIntensity;\n"
  897. "\n"
  898. "void main()\n"
  899. "{\n"
  900. " vec4 light = viewMatrix * lightPosition;\n"
  901. " lightIntensity = dot (light, normal);\n"
  902. "\n"
  903. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  904. "}\n",
  905. SHADER_DEMO_HEADER
  906. #if JUCE_OPENGL_ES
  907. "varying highp float lightIntensity;\n"
  908. #else
  909. "varying float lightIntensity;\n"
  910. #endif
  911. "\n"
  912. "void main()\n"
  913. "{\n"
  914. #if JUCE_OPENGL_ES
  915. " highp float l = lightIntensity * 0.25;\n"
  916. " highp vec4 colour = vec4 (l, l, l, 1.0);\n"
  917. #else
  918. " float l = lightIntensity * 0.25;\n"
  919. " vec4 colour = vec4 (l, l, l, 1.0);\n"
  920. #endif
  921. "\n"
  922. " gl_FragColor = colour;\n"
  923. "}\n"
  924. },
  925. {
  926. "Flattened",
  927. SHADER_DEMO_HEADER
  928. "attribute vec4 position;\n"
  929. "attribute vec4 normal;\n"
  930. "\n"
  931. "uniform mat4 projectionMatrix;\n"
  932. "uniform mat4 viewMatrix;\n"
  933. "uniform vec4 lightPosition;\n"
  934. "\n"
  935. "varying float lightIntensity;\n"
  936. "\n"
  937. "void main()\n"
  938. "{\n"
  939. " vec4 light = viewMatrix * lightPosition;\n"
  940. " lightIntensity = dot (light, normal);\n"
  941. "\n"
  942. " vec4 v = vec4 (position);\n"
  943. " v.z = v.z * 0.1;\n"
  944. "\n"
  945. " gl_Position = projectionMatrix * viewMatrix * v;\n"
  946. "}\n",
  947. SHADER_DEMO_HEADER
  948. #if JUCE_OPENGL_ES
  949. "varying highp float lightIntensity;\n"
  950. #else
  951. "varying float lightIntensity;\n"
  952. #endif
  953. "\n"
  954. "void main()\n"
  955. "{\n"
  956. #if JUCE_OPENGL_ES
  957. " highp float l = lightIntensity * 0.25;\n"
  958. " highp vec4 colour = vec4 (l, l, l, 1.0);\n"
  959. #else
  960. " float l = lightIntensity * 0.25;\n"
  961. " vec4 colour = vec4 (l, l, l, 1.0);\n"
  962. #endif
  963. "\n"
  964. " gl_FragColor = colour;\n"
  965. "}\n"
  966. },
  967. {
  968. "Toon Shader",
  969. SHADER_DEMO_HEADER
  970. "attribute vec4 position;\n"
  971. "attribute vec4 normal;\n"
  972. "\n"
  973. "uniform mat4 projectionMatrix;\n"
  974. "uniform mat4 viewMatrix;\n"
  975. "uniform vec4 lightPosition;\n"
  976. "\n"
  977. "varying float lightIntensity;\n"
  978. "\n"
  979. "void main()\n"
  980. "{\n"
  981. " vec4 light = viewMatrix * lightPosition;\n"
  982. " lightIntensity = dot (light, normal);\n"
  983. "\n"
  984. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  985. "}\n",
  986. SHADER_DEMO_HEADER
  987. #if JUCE_OPENGL_ES
  988. "varying highp float lightIntensity;\n"
  989. #else
  990. "varying float lightIntensity;\n"
  991. #endif
  992. "\n"
  993. "void main()\n"
  994. "{\n"
  995. #if JUCE_OPENGL_ES
  996. " highp float intensity = lightIntensity * 0.5;\n"
  997. " highp vec4 colour;\n"
  998. #else
  999. " float intensity = lightIntensity * 0.5;\n"
  1000. " vec4 colour;\n"
  1001. #endif
  1002. "\n"
  1003. " if (intensity > 0.95)\n"
  1004. " colour = vec4 (1.0, 0.5, 0.5, 1.0);\n"
  1005. " else if (intensity > 0.5)\n"
  1006. " colour = vec4 (0.6, 0.3, 0.3, 1.0);\n"
  1007. " else if (intensity > 0.25)\n"
  1008. " colour = vec4 (0.4, 0.2, 0.2, 1.0);\n"
  1009. " else\n"
  1010. " colour = vec4 (0.2, 0.1, 0.1, 1.0);\n"
  1011. "\n"
  1012. " gl_FragColor = colour;\n"
  1013. "}\n"
  1014. }
  1015. };
  1016. return Array<ShaderPreset> (presets, numElementsInArray (presets));
  1017. }
  1018. };
  1019. // This static object will register this demo type in a global list of demos..
  1020. static JuceDemoType<OpenGLDemoClasses::OpenGLDemo> demo ("20 Graphics: OpenGL");
  1021. #endif