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.

1210 lines
45KB

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