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.

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