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.

406 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../JuceLibraryCode/JuceHeader.h"
  20. #include "Resources/WavefrontObjParser.h"
  21. //==============================================================================
  22. /*
  23. This component lives inside our window, and this is where you should put all
  24. your controls and content.
  25. */
  26. class MainContentComponent : public OpenGLAppComponent
  27. {
  28. public:
  29. //==============================================================================
  30. MainContentComponent()
  31. {
  32. setSize (800, 600);
  33. }
  34. ~MainContentComponent()
  35. {
  36. shutdownOpenGL();
  37. }
  38. void initialise() override
  39. {
  40. createShaders();
  41. }
  42. void shutdown() override
  43. {
  44. shader = nullptr;
  45. shape = nullptr;
  46. attributes = nullptr;
  47. uniforms = nullptr;
  48. }
  49. Matrix3D<float> getProjectionMatrix() const
  50. {
  51. float w = 1.0f / (0.5f + 0.1f);
  52. float h = w * getLocalBounds().toFloat().getAspectRatio (false);
  53. return Matrix3D<float>::fromFrustum (-w, w, -h, h, 4.0f, 30.0f);
  54. }
  55. Matrix3D<float> getViewMatrix() const
  56. {
  57. Matrix3D<float> viewMatrix (Vector3D<float> (0.0f, 0.0f, -10.0f));
  58. Matrix3D<float> rotationMatrix
  59. = viewMatrix.rotated (Vector3D<float> (-0.3f, 5.0f * std::sin (getFrameCounter() * 0.01f), 0.0f));
  60. return rotationMatrix * viewMatrix;
  61. }
  62. void render() override
  63. {
  64. jassert (OpenGLHelpers::isContextActive());
  65. const float desktopScale = (float) openGLContext.getRenderingScale();
  66. OpenGLHelpers::clear (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
  67. glEnable (GL_BLEND);
  68. glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  69. glViewport (0, 0, roundToInt (desktopScale * getWidth()), roundToInt (desktopScale * getHeight()));
  70. shader->use();
  71. if (uniforms->projectionMatrix != nullptr)
  72. uniforms->projectionMatrix->setMatrix4 (getProjectionMatrix().mat, 1, false);
  73. if (uniforms->viewMatrix != nullptr)
  74. uniforms->viewMatrix->setMatrix4 (getViewMatrix().mat, 1, false);
  75. shape->draw (openGLContext, *attributes);
  76. // Reset the element buffers so child Components draw correctly
  77. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
  78. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
  79. }
  80. void paint (Graphics& g) override
  81. {
  82. // You can add your component specific drawing code here!
  83. // This will draw over the top of the openGL background.
  84. g.setColour (getLookAndFeel().findColour (Label::textColourId));
  85. g.setFont (20);
  86. g.drawText ("OpenGL Example", 25, 20, 300, 30, Justification::left);
  87. g.drawLine (20, 20, 170, 20);
  88. g.drawLine (20, 50, 170, 50);
  89. }
  90. void resized() override
  91. {
  92. // This is called when the MainContentComponent is resized.
  93. // If you add any child components, this is where you should
  94. // update their positions.
  95. }
  96. void createShaders()
  97. {
  98. vertexShader =
  99. "attribute vec4 position;\n"
  100. "attribute vec4 sourceColour;\n"
  101. "attribute vec2 texureCoordIn;\n"
  102. "\n"
  103. "uniform mat4 projectionMatrix;\n"
  104. "uniform mat4 viewMatrix;\n"
  105. "\n"
  106. "varying vec4 destinationColour;\n"
  107. "varying vec2 textureCoordOut;\n"
  108. "\n"
  109. "void main()\n"
  110. "{\n"
  111. " destinationColour = sourceColour;\n"
  112. " textureCoordOut = texureCoordIn;\n"
  113. " gl_Position = projectionMatrix * viewMatrix * position;\n"
  114. "}\n";
  115. fragmentShader =
  116. #if JUCE_OPENGL_ES
  117. "varying lowp vec4 destinationColour;\n"
  118. "varying lowp vec2 textureCoordOut;\n"
  119. #else
  120. "varying vec4 destinationColour;\n"
  121. "varying vec2 textureCoordOut;\n"
  122. #endif
  123. "\n"
  124. "void main()\n"
  125. "{\n"
  126. #if JUCE_OPENGL_ES
  127. " lowp vec4 colour = vec4(0.95, 0.57, 0.03, 0.7);\n"
  128. #else
  129. " vec4 colour = vec4(0.95, 0.57, 0.03, 0.7);\n"
  130. #endif
  131. " gl_FragColor = colour;\n"
  132. "}\n";
  133. ScopedPointer<OpenGLShaderProgram> newShader (new OpenGLShaderProgram (openGLContext));
  134. String statusText;
  135. if (newShader->addVertexShader (OpenGLHelpers::translateVertexShaderToV3 (vertexShader))
  136. && newShader->addFragmentShader (OpenGLHelpers::translateFragmentShaderToV3 (fragmentShader))
  137. && newShader->link())
  138. {
  139. shape = nullptr;
  140. attributes = nullptr;
  141. uniforms = nullptr;
  142. shader = newShader;
  143. shader->use();
  144. shape = new Shape (openGLContext);
  145. attributes = new Attributes (openGLContext, *shader);
  146. uniforms = new Uniforms (openGLContext, *shader);
  147. statusText = "GLSL: v" + String (OpenGLShaderProgram::getLanguageVersion(), 2);
  148. }
  149. else
  150. {
  151. statusText = newShader->getLastError();
  152. }
  153. }
  154. private:
  155. //==============================================================================
  156. struct Vertex
  157. {
  158. float position[3];
  159. float normal[3];
  160. float colour[4];
  161. float texCoord[2];
  162. };
  163. //==============================================================================
  164. // This class just manages the attributes that the shaders use.
  165. struct Attributes
  166. {
  167. Attributes (OpenGLContext& openGLContext, OpenGLShaderProgram& shaderProgram)
  168. {
  169. position = createAttribute (openGLContext, shaderProgram, "position");
  170. normal = createAttribute (openGLContext, shaderProgram, "normal");
  171. sourceColour = createAttribute (openGLContext, shaderProgram, "sourceColour");
  172. texureCoordIn = createAttribute (openGLContext, shaderProgram, "texureCoordIn");
  173. }
  174. void enable (OpenGLContext& openGLContext)
  175. {
  176. if (position != nullptr)
  177. {
  178. openGLContext.extensions.glVertexAttribPointer (position->attributeID, 3, GL_FLOAT, GL_FALSE, sizeof (Vertex), 0);
  179. openGLContext.extensions.glEnableVertexAttribArray (position->attributeID);
  180. }
  181. if (normal != nullptr)
  182. {
  183. openGLContext.extensions.glVertexAttribPointer (normal->attributeID, 3, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 3));
  184. openGLContext.extensions.glEnableVertexAttribArray (normal->attributeID);
  185. }
  186. if (sourceColour != nullptr)
  187. {
  188. openGLContext.extensions.glVertexAttribPointer (sourceColour->attributeID, 4, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 6));
  189. openGLContext.extensions.glEnableVertexAttribArray (sourceColour->attributeID);
  190. }
  191. if (texureCoordIn != nullptr)
  192. {
  193. openGLContext.extensions.glVertexAttribPointer (texureCoordIn->attributeID, 2, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 10));
  194. openGLContext.extensions.glEnableVertexAttribArray (texureCoordIn->attributeID);
  195. }
  196. }
  197. void disable (OpenGLContext& openGLContext)
  198. {
  199. if (position != nullptr) openGLContext.extensions.glDisableVertexAttribArray (position->attributeID);
  200. if (normal != nullptr) openGLContext.extensions.glDisableVertexAttribArray (normal->attributeID);
  201. if (sourceColour != nullptr) openGLContext.extensions.glDisableVertexAttribArray (sourceColour->attributeID);
  202. if (texureCoordIn != nullptr) openGLContext.extensions.glDisableVertexAttribArray (texureCoordIn->attributeID);
  203. }
  204. ScopedPointer<OpenGLShaderProgram::Attribute> position, normal, sourceColour, texureCoordIn;
  205. private:
  206. static OpenGLShaderProgram::Attribute* createAttribute (OpenGLContext& openGLContext,
  207. OpenGLShaderProgram& shader,
  208. const char* attributeName)
  209. {
  210. if (openGLContext.extensions.glGetAttribLocation (shader.getProgramID(), attributeName) < 0)
  211. return nullptr;
  212. return new OpenGLShaderProgram::Attribute (shader, attributeName);
  213. }
  214. };
  215. //==============================================================================
  216. // This class just manages the uniform values that the demo shaders use.
  217. struct Uniforms
  218. {
  219. Uniforms (OpenGLContext& openGLContext, OpenGLShaderProgram& shaderProgram)
  220. {
  221. projectionMatrix = createUniform (openGLContext, shaderProgram, "projectionMatrix");
  222. viewMatrix = createUniform (openGLContext, shaderProgram, "viewMatrix");
  223. }
  224. ScopedPointer<OpenGLShaderProgram::Uniform> projectionMatrix, viewMatrix;
  225. private:
  226. static OpenGLShaderProgram::Uniform* createUniform (OpenGLContext& openGLContext,
  227. OpenGLShaderProgram& shaderProgram,
  228. const char* uniformName)
  229. {
  230. if (openGLContext.extensions.glGetUniformLocation (shaderProgram.getProgramID(), uniformName) < 0)
  231. return nullptr;
  232. return new OpenGLShaderProgram::Uniform (shaderProgram, uniformName);
  233. }
  234. };
  235. //==============================================================================
  236. /** This loads a 3D model from an OBJ file and converts it into some vertex buffers
  237. that we can draw.
  238. */
  239. struct Shape
  240. {
  241. Shape (OpenGLContext& openGLContext)
  242. {
  243. if (shapeFile.load (BinaryData::teapot_obj).wasOk())
  244. for (int i = 0; i < shapeFile.shapes.size(); ++i)
  245. vertexBuffers.add (new VertexBuffer (openGLContext, *shapeFile.shapes.getUnchecked(i)));
  246. }
  247. void draw (OpenGLContext& openGLContext, Attributes& glAttributes)
  248. {
  249. for (int i = 0; i < vertexBuffers.size(); ++i)
  250. {
  251. VertexBuffer& vertexBuffer = *vertexBuffers.getUnchecked (i);
  252. vertexBuffer.bind();
  253. glAttributes.enable (openGLContext);
  254. glDrawElements (GL_TRIANGLES, vertexBuffer.numIndices, GL_UNSIGNED_INT, 0);
  255. glAttributes.disable (openGLContext);
  256. }
  257. }
  258. private:
  259. struct VertexBuffer
  260. {
  261. VertexBuffer (OpenGLContext& context, WavefrontObjFile::Shape& aShape) : openGLContext (context)
  262. {
  263. numIndices = aShape.mesh.indices.size();
  264. openGLContext.extensions.glGenBuffers (1, &vertexBuffer);
  265. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer);
  266. Array<Vertex> vertices;
  267. createVertexListFromMesh (aShape.mesh, vertices, Colours::green);
  268. openGLContext.extensions.glBufferData (GL_ARRAY_BUFFER,
  269. static_cast<GLsizeiptr> (static_cast<size_t> (vertices.size()) * sizeof (Vertex)),
  270. vertices.getRawDataPointer(), GL_STATIC_DRAW);
  271. openGLContext.extensions.glGenBuffers (1, &indexBuffer);
  272. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
  273. openGLContext.extensions.glBufferData (GL_ELEMENT_ARRAY_BUFFER,
  274. static_cast<GLsizeiptr> (static_cast<size_t> (numIndices) * sizeof (juce::uint32)),
  275. aShape.mesh.indices.getRawDataPointer(), GL_STATIC_DRAW);
  276. }
  277. ~VertexBuffer()
  278. {
  279. openGLContext.extensions.glDeleteBuffers (1, &vertexBuffer);
  280. openGLContext.extensions.glDeleteBuffers (1, &indexBuffer);
  281. }
  282. void bind()
  283. {
  284. openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer);
  285. openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
  286. }
  287. GLuint vertexBuffer, indexBuffer;
  288. int numIndices;
  289. OpenGLContext& openGLContext;
  290. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VertexBuffer)
  291. };
  292. WavefrontObjFile shapeFile;
  293. OwnedArray<VertexBuffer> vertexBuffers;
  294. static void createVertexListFromMesh (const WavefrontObjFile::Mesh& mesh, Array<Vertex>& list, Colour colour)
  295. {
  296. const float scale = 0.2f;
  297. WavefrontObjFile::TextureCoord defaultTexCoord = { 0.5f, 0.5f };
  298. WavefrontObjFile::Vertex defaultNormal = { 0.5f, 0.5f, 0.5f };
  299. for (int i = 0; i < mesh.vertices.size(); ++i)
  300. {
  301. const WavefrontObjFile::Vertex& v = mesh.vertices.getReference (i);
  302. const WavefrontObjFile::Vertex& n
  303. = i < mesh.normals.size() ? mesh.normals.getReference (i) : defaultNormal;
  304. const WavefrontObjFile::TextureCoord& tc
  305. = i < mesh.textureCoords.size() ? mesh.textureCoords.getReference (i) : defaultTexCoord;
  306. Vertex vert =
  307. {
  308. { scale * v.x, scale * v.y, scale * v.z, },
  309. { scale * n.x, scale * n.y, scale * n.z, },
  310. { colour.getFloatRed(), colour.getFloatGreen(), colour.getFloatBlue(), colour.getFloatAlpha() },
  311. { tc.x, tc.y }
  312. };
  313. list.add (vert);
  314. }
  315. }
  316. };
  317. const char* vertexShader;
  318. const char* fragmentShader;
  319. ScopedPointer<OpenGLShaderProgram> shader;
  320. ScopedPointer<Shape> shape;
  321. ScopedPointer<Attributes> attributes;
  322. ScopedPointer<Uniforms> uniforms;
  323. String newVertexShader, newFragmentShader;
  324. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
  325. };
  326. // (This function is called by the app startup code to create our main component)
  327. Component* createMainContentComponent() { return new MainContentComponent(); }