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.

1218 lines
46KB

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