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.

2283 lines
83KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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. BEGIN_JUCE_NAMESPACE
  19. namespace
  20. {
  21. #if JUCE_WINDOWS
  22. enum
  23. {
  24. GL_OPERAND0_RGB = 0x8590,
  25. GL_OPERAND1_RGB = 0x8591,
  26. GL_OPERAND0_ALPHA = 0x8598,
  27. GL_OPERAND1_ALPHA = 0x8599,
  28. GL_SRC0_RGB = 0x8580,
  29. GL_SRC1_RGB = 0x8581,
  30. GL_SRC0_ALPHA = 0x8588,
  31. GL_SRC1_ALPHA = 0x8589,
  32. GL_TEXTURE0 = 0x84C0,
  33. GL_TEXTURE1 = 0x84C1,
  34. GL_TEXTURE2 = 0x84C2,
  35. GL_COMBINE = 0x8570,
  36. GL_COMBINE_RGB = 0x8571,
  37. GL_COMBINE_ALPHA = 0x8572,
  38. GL_PREVIOUS = 0x8578,
  39. };
  40. #endif
  41. #if JUCE_WINDOWS || JUCE_LINUX
  42. JUCE_DECLARE_GL_EXTENSION_FUNCTION (glActiveTexture, void, (GLenum));
  43. JUCE_DECLARE_GL_EXTENSION_FUNCTION (glClientActiveTexture, void, (GLenum));
  44. void initialiseMultiTextureExtensions()
  45. {
  46. if (glActiveTexture == nullptr)
  47. {
  48. JUCE_INSTANTIATE_GL_EXTENSION (glActiveTexture);
  49. JUCE_INSTANTIATE_GL_EXTENSION (glClientActiveTexture);
  50. }
  51. }
  52. #else
  53. void initialiseMultiTextureExtensions() {}
  54. #endif
  55. }
  56. //==============================================================================
  57. struct OpenGLTarget
  58. {
  59. OpenGLTarget (GLuint frameBufferID_, int width_, int height_) noexcept
  60. : frameBuffer (nullptr), frameBufferID (frameBufferID_),
  61. x (0), y (0), width (width_), height (height_)
  62. {}
  63. OpenGLTarget (OpenGLFrameBuffer& frameBuffer_, const Point<int>& origin) noexcept
  64. : frameBuffer (&frameBuffer_), frameBufferID (0), x (origin.x), y (origin.y),
  65. width (frameBuffer_.getWidth()), height (frameBuffer_.getHeight())
  66. {}
  67. OpenGLTarget (const OpenGLTarget& other) noexcept
  68. : frameBuffer (other.frameBuffer), frameBufferID (other.frameBufferID),
  69. x (other.x), y (other.y), width (other.width), height (other.height)
  70. {}
  71. void makeActiveFor2D() const
  72. {
  73. if (frameBuffer != nullptr)
  74. frameBuffer->makeCurrentRenderingTarget();
  75. else
  76. OpenGLFrameBuffer::setCurrentFrameBufferTarget (frameBufferID);
  77. applyFlippedMatrix (x, y, width, height);
  78. glDisable (GL_DEPTH_TEST);
  79. }
  80. void scissor (Rectangle<int> r) const
  81. {
  82. r = r.translated (-x, -y);
  83. OpenGLHelpers::enableScissorTest (r.withY (height - r.getBottom()));
  84. }
  85. static void applyFlippedMatrix (const int x, const int y, const int width, const int height)
  86. {
  87. glMatrixMode (GL_PROJECTION);
  88. glLoadIdentity();
  89. #if JUCE_OPENGL_ES
  90. glOrthof ((GLfloat) x, (GLfloat) (x + width), (GLfloat) (y + height), (GLfloat) y, 0.0f, 1.0f);
  91. #else
  92. glOrtho (x, x + width, y + height, y, 0, 1);
  93. #endif
  94. glViewport (0, 0, width, height);
  95. }
  96. struct TargetSaver
  97. {
  98. TargetSaver()
  99. : oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  100. {
  101. glGetIntegerv (GL_VIEWPORT, oldViewport);
  102. glPushMatrix();
  103. }
  104. ~TargetSaver()
  105. {
  106. OpenGLFrameBuffer::setCurrentFrameBufferTarget (oldFramebuffer);
  107. glPopMatrix();
  108. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  109. }
  110. private:
  111. GLuint oldFramebuffer;
  112. GLint oldViewport[4];
  113. };
  114. OpenGLFrameBuffer* frameBuffer;
  115. GLuint frameBufferID;
  116. int x, y, width, height;
  117. };
  118. //==============================================================================
  119. class PositionedTexture
  120. {
  121. public:
  122. PositionedTexture (OpenGLTexture& texture, EdgeTable& et, const Rectangle<int>& clip_)
  123. {
  124. et.clipToRectangle (clip_);
  125. EdgeTableAlphaMap alphaMap (et);
  126. texture.loadAlpha (alphaMap.data, alphaMap.area.getWidth(), alphaMap.area.getHeight());
  127. textureID = texture.getTextureID();
  128. clip = et.getMaximumBounds();
  129. area = alphaMap.area;
  130. }
  131. PositionedTexture (GLuint textureID_, const Rectangle<int> area_, const Rectangle<int> clip_) noexcept
  132. : textureID (textureID_), area (area_), clip (clip_)
  133. {}
  134. template <typename ValueType>
  135. void getTextureCoordAt (ValueType x, ValueType y, GLfloat& resultX, GLfloat& resultY) const noexcept
  136. {
  137. resultX = (x - area.getX()) / (float) area.getWidth();
  138. resultY = (area.getBottom() - y) / (float) area.getHeight();
  139. }
  140. void prepareTextureCoords (const Rectangle<int>* const area, GLfloat* const textureCoords) const noexcept
  141. {
  142. if (area != nullptr)
  143. {
  144. getTextureCoordAt (area->getX(), area->getY(), textureCoords[0], textureCoords[1]);
  145. getTextureCoordAt (area->getRight(), area->getY(), textureCoords[2], textureCoords[3]);
  146. getTextureCoordAt (area->getX(), area->getBottom(), textureCoords[4], textureCoords[5]);
  147. getTextureCoordAt (area->getRight(), area->getBottom(), textureCoords[6], textureCoords[7]);
  148. }
  149. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  150. }
  151. GLuint textureID;
  152. Rectangle<int> area, clip;
  153. private:
  154. struct EdgeTableAlphaMap
  155. {
  156. EdgeTableAlphaMap (const EdgeTable& et)
  157. : area (et.getMaximumBounds().withSize (nextPowerOfTwo (et.getMaximumBounds().getWidth()),
  158. nextPowerOfTwo (et.getMaximumBounds().getHeight())))
  159. {
  160. data.calloc (area.getWidth() * area.getHeight());
  161. et.iterate (*this);
  162. }
  163. inline void setEdgeTableYPos (const int y) noexcept
  164. {
  165. currentLine = data + (area.getBottom() - 1 - y) * area.getWidth() - area.getX();
  166. }
  167. inline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
  168. {
  169. currentLine[x] = (uint8) alphaLevel;
  170. }
  171. inline void handleEdgeTablePixelFull (const int x) const noexcept
  172. {
  173. currentLine[x] = 255;
  174. }
  175. inline void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept
  176. {
  177. memset (currentLine + x, (uint8) alphaLevel, width);
  178. }
  179. inline void handleEdgeTableLineFull (int x, int width) const noexcept
  180. {
  181. memset (currentLine + x, 255, width);
  182. }
  183. HeapBlock<uint8> data;
  184. const Rectangle<int> area;
  185. private:
  186. uint8* currentLine;
  187. JUCE_DECLARE_NON_COPYABLE (EdgeTableAlphaMap);
  188. };
  189. };
  190. //==============================================================================
  191. namespace
  192. {
  193. struct TemporaryColourModulationMode
  194. {
  195. TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); }
  196. ~TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); }
  197. };
  198. }
  199. //==============================================================================
  200. #if JUCE_USE_OPENGL_SHADERS
  201. class GLShaderProgram
  202. {
  203. public:
  204. GLShaderProgram() noexcept
  205. : program (glCreateProgram())
  206. {
  207. }
  208. GLShaderProgram (const GLchar* fragment) noexcept
  209. : program (glCreateProgram())
  210. {
  211. addShader (fragment, GL_FRAGMENT_SHADER);
  212. link();
  213. }
  214. ~GLShaderProgram() noexcept
  215. {
  216. glDeleteProgram (program);
  217. }
  218. void addShader (const GLchar* const code, GLenum type)
  219. {
  220. GLuint shaderID = glCreateShader (type);
  221. glShaderSource (shaderID, 1, (const GLchar**) &code, nullptr);
  222. glCompileShader (shaderID);
  223. #if JUCE_DEBUG
  224. GLint status = 0;
  225. glGetShaderiv (shaderID, GL_COMPILE_STATUS, &status);
  226. if (status == GL_FALSE)
  227. {
  228. GLchar infoLog [16384];
  229. GLsizei infologLength = 0;
  230. glGetShaderInfoLog (shaderID, sizeof (infoLog), &infologLength, infoLog);
  231. DBG (String (infoLog, infologLength));
  232. jassertfalse;
  233. }
  234. #endif
  235. glAttachShader (program, shaderID);
  236. glDeleteShader (shaderID);
  237. }
  238. void link() noexcept
  239. {
  240. glLinkProgram (program);
  241. #if JUCE_DEBUG
  242. GLint status = 0;
  243. glGetProgramiv (program, GL_LINK_STATUS, &status);
  244. jassert (status != GL_FALSE);
  245. #endif
  246. }
  247. struct UniformLocation
  248. {
  249. UniformLocation (const GLShaderProgram& program, const GLchar* name)
  250. : uniformID (glGetUniformLocation (program.program, name))
  251. {
  252. jassert (uniformID >= 0);
  253. }
  254. void set (GLfloat n1) const noexcept { glUniform1f (uniformID, n1); }
  255. void set (GLint n1) const noexcept { glUniform1i (uniformID, n1); }
  256. void set (GLfloat n1, GLfloat n2) const noexcept { glUniform2f (uniformID, n1, n2); }
  257. void set (GLfloat n1, GLfloat n2, GLfloat n3) const noexcept { glUniform3f (uniformID, n1, n2, n3); }
  258. void set (GLfloat n1, GLfloat n2, GLfloat n3, float n4) const noexcept { glUniform4f (uniformID, n1, n2, n3, n4); }
  259. void set (GLint n1, GLint n2, GLint n3, GLint n4) const noexcept { glUniform4i (uniformID, n1, n2, n3, n4); }
  260. void set (const AffineTransform& t) const noexcept
  261. {
  262. const GLfloat f[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  263. glUniformMatrix2x3fv (uniformID, 1, false, f);
  264. }
  265. GLint uniformID;
  266. };
  267. GLuint program;
  268. };
  269. struct ShaderPrograms
  270. {
  271. ShaderPrograms()
  272. {
  273. String v ((const char*) glGetString (GL_SHADING_LANGUAGE_VERSION));
  274. v = v.upToFirstOccurrenceOf (" ", false, false);
  275. areShadersSupported = (v.getDoubleValue() >= 1.199);
  276. }
  277. bool areShadersSupported;
  278. struct SolidColourMaskedProgram
  279. {
  280. SolidColourMaskedProgram()
  281. : program ("#version 120\n"
  282. "uniform sampler2D maskTexture;"
  283. "uniform ivec4 maskBounds;"
  284. "const float textureY = 0.5;"
  285. ""
  286. "void main()"
  287. "{"
  288. " vec2 maskPos;"
  289. " maskPos.x = (gl_FragCoord.x - maskBounds.x) / maskBounds.z;"
  290. " maskPos.y = 1.0 - (gl_FragCoord.y - maskBounds.y) / maskBounds.w;"
  291. " gl_FragColor = gl_Color * texture2D (maskTexture, maskPos).w;"
  292. "}"),
  293. maskTexture (program, "maskTexture"),
  294. maskBounds (program, "maskBounds")
  295. {
  296. }
  297. GLShaderProgram program;
  298. GLShaderProgram::UniformLocation maskTexture, maskBounds;
  299. };
  300. struct RadialGradientProgram
  301. {
  302. RadialGradientProgram()
  303. : program ("#version 120\n"
  304. "uniform sampler2D gradientTexture;"
  305. "uniform mat2x3 matrix;"
  306. "const float textureY = 0.5;"
  307. ""
  308. "void main()"
  309. "{"
  310. " float dist = length (vec2 (matrix[0][0] * gl_FragCoord.x + matrix[0][1] * gl_FragCoord.y + matrix[0][2],"
  311. " matrix[1][0] * gl_FragCoord.x + matrix[1][1] * gl_FragCoord.y + matrix[1][2]));"
  312. " gl_FragColor = gl_Color.w * texture2D (gradientTexture, vec2 (dist, textureY));"
  313. "}"),
  314. gradientTexture (program, "gradientTexture"),
  315. matrix (program, "matrix")
  316. {
  317. }
  318. GLShaderProgram program;
  319. GLShaderProgram::UniformLocation gradientTexture, matrix;
  320. };
  321. struct RadialGradientMaskedProgram
  322. {
  323. RadialGradientMaskedProgram()
  324. : program ("#version 120\n"
  325. "uniform sampler2D gradientTexture;"
  326. "uniform mat2x3 matrix;"
  327. "uniform sampler2D maskTexture;"
  328. "uniform ivec4 maskBounds;"
  329. "const float textureY = 0.5;"
  330. ""
  331. "void main()"
  332. "{"
  333. " float dist = length (vec2 (matrix[0][0] * gl_FragCoord.x + matrix[0][1] * gl_FragCoord.y + matrix[0][2],"
  334. " matrix[1][0] * gl_FragCoord.x + matrix[1][1] * gl_FragCoord.y + matrix[1][2]));"
  335. " vec4 result = gl_Color.w * texture2D (gradientTexture, vec2 (dist, textureY));"
  336. ""
  337. " vec2 maskPos;"
  338. " maskPos.x = (gl_FragCoord.x - maskBounds.x) / maskBounds.z;"
  339. " maskPos.y = 1.0 - (gl_FragCoord.y - maskBounds.y) / maskBounds.w;"
  340. " result *= texture2D (maskTexture, maskPos).w;"
  341. ""
  342. " gl_FragColor = result;"
  343. "}"),
  344. gradientTexture (program, "gradientTexture"),
  345. matrix (program, "matrix"),
  346. maskTexture (program, "maskTexture"),
  347. maskBounds (program, "maskBounds")
  348. {
  349. }
  350. GLShaderProgram program;
  351. GLShaderProgram::UniformLocation gradientTexture, matrix;
  352. GLShaderProgram::UniformLocation maskTexture, maskBounds;
  353. };
  354. struct LinearGradient1Program
  355. {
  356. LinearGradient1Program()
  357. : program ("#version 120\n"
  358. "uniform sampler2D gradientTexture;"
  359. "uniform vec4 gradientInfo;" // x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  360. "const float textureY = 0.5;"
  361. ""
  362. "void main()"
  363. "{"
  364. " float dist = (gl_FragCoord.y - (gradientInfo.y + (gradientInfo.z * (gl_FragCoord.x - gradientInfo.x)))) / gradientInfo.w;"
  365. " gl_FragColor = gl_Color.w * texture2D (gradientTexture, vec2 (dist, textureY));"
  366. "}"),
  367. gradientTexture (program, "gradientTexture"),
  368. gradientInfo (program, "gradientInfo")
  369. {
  370. }
  371. GLShaderProgram program;
  372. GLShaderProgram::UniformLocation gradientTexture, gradientInfo;
  373. };
  374. struct LinearGradient1MaskedProgram
  375. {
  376. LinearGradient1MaskedProgram()
  377. : program ("#version 120\n"
  378. "uniform sampler2D gradientTexture;"
  379. "uniform vec3 gradientInfo;" // x = (x2 - x1) / (y2 - y1), y = x1, z = length
  380. "uniform sampler2D maskTexture;"
  381. "uniform ivec4 maskBounds;"
  382. "const float textureY = 0.5;"
  383. ""
  384. "void main()"
  385. "{"
  386. " float dist = (gl_FragCoord.y - (gradientInfo.y + (gradientInfo.x * (gl_FragCoord.x - gradientInfo.y)))) / gradientInfo.z;"
  387. " vec4 result = gl_Color.w * texture2D (gradientTexture, vec2 (dist, textureY));"
  388. ""
  389. " vec2 maskPos;"
  390. " maskPos.x = (gl_FragCoord.x - maskBounds.x) / maskBounds.z;"
  391. " maskPos.y = 1.0 - (gl_FragCoord.y - maskBounds.y) / maskBounds.w;"
  392. " result *= texture2D (maskTexture, maskPos).w;"
  393. " gl_FragColor = result;"
  394. "}"),
  395. gradientTexture (program, "gradientTexture"),
  396. gradientInfo (program, "gradientInfo"),
  397. maskTexture (program, "maskTexture"),
  398. maskBounds (program, "maskBounds")
  399. {
  400. }
  401. GLShaderProgram program;
  402. GLShaderProgram::UniformLocation gradientTexture, gradientInfo;
  403. GLShaderProgram::UniformLocation maskTexture, maskBounds;
  404. };
  405. struct LinearGradient2Program
  406. {
  407. LinearGradient2Program()
  408. : program ("#version 120\n"
  409. "uniform sampler2D gradientTexture;"
  410. "uniform vec4 gradientInfo;" // x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  411. "const float textureY = 0.5;"
  412. ""
  413. "void main()"
  414. "{"
  415. " float dist = (gl_FragCoord.x - (gradientInfo.x + (gradientInfo.z * (gl_FragCoord.y - gradientInfo.y)))) / gradientInfo.w;"
  416. " gl_FragColor = gl_Color.w * texture2D (gradientTexture, vec2 (dist, textureY));"
  417. "}"),
  418. gradientTexture (program, "gradientTexture"),
  419. gradientInfo (program, "gradientInfo")
  420. {
  421. }
  422. GLShaderProgram program;
  423. GLShaderProgram::UniformLocation gradientTexture, gradientInfo;
  424. };
  425. struct LinearGradient2MaskedProgram
  426. {
  427. LinearGradient2MaskedProgram()
  428. : program ("#version 120\n"
  429. "uniform sampler2D gradientTexture;"
  430. "uniform vec3 gradientInfo;" // x = (y2 - y1) / (x2 - x1), y = y1, z = length
  431. "uniform sampler2D maskTexture;"
  432. "uniform ivec4 maskBounds;"
  433. "const float textureY = 0.5;"
  434. ""
  435. "void main()"
  436. "{"
  437. " float dist = (gl_FragCoord.x - (gradientInfo.y + (gradientInfo.x * (gl_FragCoord.y - gradientInfo.y)))) / gradientInfo.z;"
  438. " vec4 result = gl_Color.w * texture2D (gradientTexture, vec2 (dist, textureY));"
  439. ""
  440. " vec2 maskPos;"
  441. " maskPos.x = (gl_FragCoord.x - maskBounds.x) / maskBounds.z;"
  442. " maskPos.y = 1.0 - (gl_FragCoord.y - maskBounds.y) / maskBounds.w;"
  443. " result *= texture2D (maskTexture, maskPos).w;"
  444. " gl_FragColor = result;"
  445. "}"),
  446. gradientTexture (program, "gradientTexture"),
  447. gradientInfo (program, "gradientInfo"),
  448. maskTexture (program, "maskTexture"),
  449. maskBounds (program, "maskBounds")
  450. {
  451. }
  452. GLShaderProgram program;
  453. GLShaderProgram::UniformLocation gradientTexture, gradientInfo;
  454. GLShaderProgram::UniformLocation maskTexture, maskBounds;
  455. };
  456. SolidColourMaskedProgram solidColourMasked;
  457. RadialGradientProgram radialGradient;
  458. RadialGradientMaskedProgram radialGradientMasked;
  459. LinearGradient1Program linearGradient1;
  460. LinearGradient1MaskedProgram linearGradient1Masked;
  461. LinearGradient2Program linearGradient2;
  462. LinearGradient2MaskedProgram linearGradient2Masked;
  463. };
  464. //static ScopedPointer<ShaderPrograms> programs;
  465. #endif
  466. class OpenGLRenderer::GLState
  467. {
  468. public:
  469. GLState (const OpenGLTarget& target_) noexcept
  470. : target (target_),
  471. previousFrameBufferTarget (OpenGLFrameBuffer::getCurrentFrameBufferTarget()),
  472. texturesEnabled (0),
  473. currentActiveTexture (0),
  474. blendingEnabled (false),
  475. blendEnabled (false),
  476. srcFunction (0), dstFunction (0),
  477. currentColour (0),
  478. quadQueueActive (false),
  479. numVertices (0),
  480. activeGradientIndex (0),
  481. gradientNeedsRefresh (true)
  482. #if JUCE_USE_OPENGL_SHADERS
  483. , activeShader (nullptr)
  484. #endif
  485. {
  486. // This object can only be created and used when the current thread has an active OpenGL context.
  487. jassert (OpenGLHelpers::isContextActive());
  488. initialiseMultiTextureExtensions();
  489. target.makeActiveFor2D();
  490. glDisableClientState (GL_COLOR_ARRAY);
  491. glDisableClientState (GL_NORMAL_ARRAY);
  492. glEnableClientState (GL_VERTEX_ARRAY);
  493. glDisable (GL_BLEND);
  494. glColor4f (0, 0, 0, 0);
  495. for (int i = 3; --i >= 0;)
  496. {
  497. setActiveTexture (i);
  498. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  499. }
  500. clearSelectedTextures();
  501. resetMultiTextureModes (false);
  502. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  503. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  504. #if JUCE_USE_OPENGL_SHADERS
  505. if (programs == nullptr)
  506. programs = new ShaderPrograms();
  507. canUseShaders = programs->areShadersSupported;
  508. #endif
  509. }
  510. ~GLState()
  511. {
  512. flushQuads();
  513. OpenGLFrameBuffer::setCurrentFrameBufferTarget (previousFrameBufferTarget);
  514. resetMultiTextureModes (true);
  515. glFlush();
  516. }
  517. #if JUCE_USE_OPENGL_SHADERS
  518. bool shadersAvailable() const
  519. {
  520. return canUseShaders;
  521. }
  522. #endif
  523. void setPremultipliedColour (const Colour& c) noexcept
  524. {
  525. setColour (c.getPixelARGB());
  526. }
  527. void setColour (const float alpha) noexcept
  528. {
  529. const uint8 v = (uint8) jmin (255, (int) (alpha * 255.0f));
  530. setColour (PixelARGB (v, v, v, v));
  531. }
  532. void setColour (const PixelARGB& c) noexcept
  533. {
  534. if (currentColour.getARGB() != c.getARGB())
  535. {
  536. currentColour = c;
  537. glColor4f (c.getRed() / 255.0f, c.getGreen() / 255.0f,
  538. c.getBlue() / 255.0f, c.getAlpha() / 255.0f);
  539. }
  540. }
  541. void setSolidColour() noexcept
  542. {
  543. if (currentColour.getARGB() != 0xffffffff)
  544. {
  545. currentColour = PixelARGB (0xffffffff);
  546. glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
  547. }
  548. }
  549. void setPremultipliedBlendingMode() noexcept
  550. {
  551. setBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  552. }
  553. void setBlendFunc (GLenum src, GLenum dst)
  554. {
  555. if (! blendingEnabled)
  556. {
  557. flushQuads();
  558. blendingEnabled = true;
  559. glEnable (GL_BLEND);
  560. }
  561. if (srcFunction != src || dstFunction != dst)
  562. {
  563. flushQuads();
  564. srcFunction = src;
  565. dstFunction = dst;
  566. glBlendFunc (src, dst);
  567. }
  568. }
  569. void disableBlend() noexcept
  570. {
  571. if (blendingEnabled)
  572. {
  573. flushQuads();
  574. blendingEnabled = false;
  575. glDisable (GL_BLEND);
  576. }
  577. }
  578. void setBlendMode (const bool replaceExistingContents) noexcept
  579. {
  580. if (replaceExistingContents)
  581. disableBlend();
  582. else
  583. setPremultipliedBlendingMode();
  584. }
  585. void scissor (const Rectangle<int>& r)
  586. {
  587. flushQuads();
  588. target.scissor (r);
  589. }
  590. void disableScissor()
  591. {
  592. flushQuads();
  593. glDisable (GL_SCISSOR_TEST);
  594. }
  595. OpenGLTexture* getTexture (int w, int h)
  596. {
  597. if (textures.size() < numTexturesToCache)
  598. {
  599. clearSelectedTextures();
  600. return new OpenGLTexture();
  601. }
  602. for (int i = 0; i < numTexturesToCache - 2; ++i)
  603. {
  604. const OpenGLTexture* const t = textures.getUnchecked(i);
  605. if (t->getWidth() == w && t->getHeight() == h)
  606. return textures.removeAndReturn (i);
  607. }
  608. return textures.removeAndReturn (0);
  609. }
  610. void releaseTexture (OpenGLTexture* texture)
  611. {
  612. currentTextureID [currentActiveTexture] = 0;
  613. textures.add (texture);
  614. }
  615. void resetGradient() noexcept
  616. {
  617. gradientNeedsRefresh = true;
  618. }
  619. void bindTexture (const GLuint textureID) noexcept
  620. {
  621. if (currentTextureID [currentActiveTexture] != textureID)
  622. {
  623. currentTextureID [currentActiveTexture] = textureID;
  624. glBindTexture (GL_TEXTURE_2D, textureID);
  625. }
  626. else
  627. {
  628. GLint t = 0;
  629. glGetIntegerv (GL_TEXTURE_BINDING_2D, &t);
  630. jassert (t == (GLint) textureID);
  631. }
  632. }
  633. void bindTextureForGradient (const ColourGradient& gradient)
  634. {
  635. if (gradientNeedsRefresh)
  636. {
  637. gradientNeedsRefresh = false;
  638. if (gradientTextures.size() < numGradientTexturesToCache)
  639. {
  640. activeGradientIndex = gradientTextures.size();
  641. clearSelectedTextures();
  642. gradientTextures.add (new OpenGLTexture());
  643. }
  644. else
  645. {
  646. activeGradientIndex = (activeGradientIndex + 1) % numGradientTexturesToCache;
  647. }
  648. PixelARGB lookup [gradientTextureSize];
  649. gradient.createLookupTable (lookup, gradientTextureSize);
  650. gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1);
  651. }
  652. bindTexture (gradientTextures.getUnchecked (activeGradientIndex)->getTextureID());
  653. }
  654. void setTexturesEnabled (const int textureIndexMask) noexcept
  655. {
  656. if (texturesEnabled != textureIndexMask)
  657. {
  658. flushQuads();
  659. for (int i = 3; --i >= 0;)
  660. {
  661. if ((texturesEnabled & (1 << i)) != (textureIndexMask & (1 << i)))
  662. {
  663. setActiveTexture (i);
  664. if ((textureIndexMask & (1 << i)) != 0)
  665. glEnable (GL_TEXTURE_2D);
  666. else
  667. glDisable (GL_TEXTURE_2D);
  668. }
  669. }
  670. texturesEnabled = textureIndexMask;
  671. }
  672. }
  673. void setActiveTexture (const int index) noexcept
  674. {
  675. if (currentActiveTexture != index)
  676. {
  677. currentActiveTexture = index;
  678. glActiveTexture (GL_TEXTURE0 + index);
  679. glClientActiveTexture (GL_TEXTURE0 + index);
  680. }
  681. }
  682. void setSingleTextureMode() noexcept
  683. {
  684. setTexturesEnabled (1);
  685. setActiveTexture (0);
  686. }
  687. void prepareMasks (const PositionedTexture* const mask1, const PositionedTexture* const mask2,
  688. GLfloat* const textureCoords1, GLfloat* const textureCoords2, const Rectangle<int>* const area)
  689. {
  690. if (mask1 != nullptr)
  691. {
  692. setTexturesEnabled (mask2 != nullptr ? 7 : 3);
  693. setActiveTexture (0);
  694. mask1->prepareTextureCoords (area, textureCoords1);
  695. bindTexture (mask1->textureID);
  696. setActiveTexture (1);
  697. if (mask2 != nullptr)
  698. {
  699. mask2->prepareTextureCoords (area, textureCoords2);
  700. bindTexture (mask2->textureID);
  701. setActiveTexture (2);
  702. }
  703. }
  704. else
  705. {
  706. setSingleTextureMode();
  707. }
  708. }
  709. void checkQuadQueueActive()
  710. {
  711. if (! quadQueueActive)
  712. {
  713. jassert (numVertices == 0);
  714. setTexturesEnabled (0);
  715. glEnableClientState (GL_COLOR_ARRAY);
  716. glVertexPointer (2, GL_SHORT, 0, vertices);
  717. glColorPointer (4, GL_UNSIGNED_BYTE, 0, colours);
  718. setSolidColour();
  719. quadQueueActive = true; // (careful to do this last, as the preceding calls may change it)
  720. }
  721. }
  722. void addQuadToList (const int x, const int y, const int w, const int h, const PixelARGB& colour) noexcept
  723. {
  724. jassert (quadQueueActive && w > 0 && h > 0);
  725. const GLshort x1 = (GLshort) x;
  726. const GLshort y1 = (GLshort) y;
  727. const GLshort x2 = (GLshort) (x + w);
  728. const GLshort y2 = (GLshort) (y + h);
  729. GLshort* const v = vertices + numVertices * 2;
  730. v[0] = x1; v[1] = y1; v[2] = x2; v[3] = y1; v[4] = x1; v[5] = y2;
  731. v[6] = x2; v[7] = y1; v[8] = x1; v[9] = y2; v[10] = x2; v[11] = y2;
  732. const uint32 rgba = colour.getInRGBAMemoryOrder();
  733. uint32* const c = colours + numVertices;
  734. for (int i = 0; i < 6; ++i)
  735. c[i] = rgba;
  736. numVertices += 6;
  737. if (numVertices > maxVerticesPerBlock - 6)
  738. {
  739. glDrawArrays (GL_TRIANGLES, 0, numVertices);
  740. numVertices = 0;
  741. }
  742. }
  743. void fillRect (const Rectangle<float>& r, const PixelARGB& colour) noexcept
  744. {
  745. jassert (! r.isEmpty());
  746. FloatRectangleRenderer frr (*this, colour);
  747. RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (frr);
  748. }
  749. void fillRectangleList (const RectangleList& list, const PixelARGB& colour)
  750. {
  751. checkQuadQueueActive();
  752. for (RectangleList::Iterator i (list); i.next();)
  753. addQuadToList (i.getRectangle()->getX(), i.getRectangle()->getY(),
  754. i.getRectangle()->getWidth(), i.getRectangle()->getHeight(), colour);
  755. }
  756. void fillRectangleList (const RectangleList& list, const Rectangle<int>& clip, const PixelARGB& colour)
  757. {
  758. checkQuadQueueActive();
  759. for (RectangleList::Iterator i (list); i.next();)
  760. {
  761. const Rectangle<int> r (i.getRectangle()->getIntersection (clip));
  762. if (! r.isEmpty())
  763. addQuadToList (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  764. }
  765. }
  766. void drawTriangleStrip (const GLfloat* const vertices, const GLfloat* const textureCoords, const int numVertices) noexcept
  767. {
  768. glVertexPointer (2, GL_FLOAT, 0, vertices);
  769. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  770. glDrawArrays (GL_TRIANGLE_STRIP, 0, numVertices);
  771. }
  772. void fillEdgeTable (const EdgeTable& et, const PixelARGB& colour)
  773. {
  774. EdgeTableRenderer etr (*this, colour);
  775. et.iterate (etr);
  776. }
  777. void renderImage (const OpenGLTextureFromImage& image,
  778. const Rectangle<int>& clip, const AffineTransform& transform, float alpha,
  779. const PositionedTexture* mask1, const PositionedTexture* mask2,
  780. const bool replaceExistingContents, const bool isTiled)
  781. {
  782. flushQuads();
  783. setBlendMode (replaceExistingContents);
  784. setColour (alpha);
  785. GLfloat textureCoords1[8], textureCoords2[8];
  786. if ((! isTiled) || (isPowerOfTwo (image.imageWidth) && isPowerOfTwo (image.imageHeight)))
  787. {
  788. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &clip);
  789. bindTexture (image.textureID);
  790. TemporaryColourModulationMode tmm;
  791. if (isTiled)
  792. {
  793. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  794. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  795. }
  796. const GLfloat clipX = (GLfloat) clip.getX();
  797. const GLfloat clipY = (GLfloat) clip.getY();
  798. const GLfloat clipR = (GLfloat) clip.getRight();
  799. const GLfloat clipB = (GLfloat) clip.getBottom();
  800. const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  801. GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  802. {
  803. const AffineTransform t (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  804. image.fullHeightProportion / image.imageHeight));
  805. t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  806. t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  807. textureCoords[1] = 1.0f - textureCoords[1];
  808. textureCoords[3] = 1.0f - textureCoords[3];
  809. textureCoords[5] = 1.0f - textureCoords[5];
  810. textureCoords[7] = 1.0f - textureCoords[7];
  811. }
  812. glVertexPointer (2, GL_FLOAT, 0, vertices);
  813. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  814. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  815. if (isTiled)
  816. {
  817. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  818. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  819. }
  820. }
  821. else
  822. {
  823. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, nullptr);
  824. bindTexture (image.textureID);
  825. TemporaryColourModulationMode tmm;
  826. scissor (clip);
  827. glPushMatrix();
  828. OpenGLHelpers::applyTransform (transform);
  829. GLfloat vertices[8];
  830. const GLfloat textureCoords[] = { 0, 1.0f, image.fullWidthProportion, 1.0f,
  831. 0, 1.0f - image.fullHeightProportion, image.fullWidthProportion, 1.0f - image.fullHeightProportion };
  832. glVertexPointer (2, GL_FLOAT, 0, vertices);
  833. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  834. const Rectangle<int> targetArea (clip.toFloat().transformed (transform.inverted()).getSmallestIntegerContainer());
  835. int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), image.imageWidth);
  836. int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), image.imageHeight);
  837. const int right = targetArea.getRight();
  838. const int bottom = targetArea.getBottom();
  839. while (y < bottom)
  840. {
  841. vertices[1] = vertices[3] = (GLfloat) y;
  842. vertices[5] = vertices[7] = (GLfloat) (y + image.imageHeight);
  843. for (int x1 = x; x1 < right; x1 += image.imageWidth)
  844. {
  845. vertices[0] = vertices[4] = (GLfloat) x1;
  846. vertices[2] = vertices[6] = (GLfloat) (x1 + image.imageWidth);
  847. if (mask1 != nullptr)
  848. {
  849. float t[] = { vertices[0], vertices[1], vertices[2], vertices[3],
  850. vertices[4], vertices[5], vertices[6], vertices[7] };
  851. transform.transformPoints (t[0], t[1], t[2], t[3]);
  852. transform.transformPoints (t[4], t[5], t[6], t[7]);
  853. mask1->getTextureCoordAt (t[0], t[1], textureCoords1[0], textureCoords1[1]);
  854. mask1->getTextureCoordAt (t[2], t[3], textureCoords1[2], textureCoords1[3]);
  855. mask1->getTextureCoordAt (t[4], t[5], textureCoords1[4], textureCoords1[5]);
  856. mask1->getTextureCoordAt (t[6], t[7], textureCoords1[6], textureCoords1[7]);
  857. if (mask2 != nullptr)
  858. {
  859. mask2->getTextureCoordAt (t[0], t[1], textureCoords2[0], textureCoords2[1]);
  860. mask2->getTextureCoordAt (t[2], t[3], textureCoords2[2], textureCoords2[3]);
  861. mask2->getTextureCoordAt (t[4], t[5], textureCoords2[4], textureCoords2[5]);
  862. mask2->getTextureCoordAt (t[6], t[7], textureCoords2[6], textureCoords2[7]);
  863. }
  864. }
  865. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  866. }
  867. y += image.imageHeight;
  868. }
  869. glPopMatrix();
  870. disableScissor();
  871. }
  872. }
  873. void fillTexture (const Rectangle<int>& area, const FillType& fill,
  874. const PositionedTexture* mask1, const PositionedTexture* mask2,
  875. const bool replaceExistingContents)
  876. {
  877. jassert (! (mask1 == nullptr && mask2 != nullptr));
  878. if (fill.isColour())
  879. {
  880. GLfloat textureCoords1[8], textureCoords2[8];
  881. if (mask1 != nullptr)
  882. {
  883. setBlendMode (replaceExistingContents);
  884. setTexturesEnabled (mask2 != nullptr ? 3 : 1);
  885. setActiveTexture (0);
  886. mask1->prepareTextureCoords (&area, textureCoords1);
  887. bindTexture (mask1->textureID);
  888. if (mask2 != nullptr)
  889. {
  890. setActiveTexture (1);
  891. mask2->prepareTextureCoords (&area, textureCoords2);
  892. bindTexture (mask2->textureID);
  893. }
  894. }
  895. else
  896. {
  897. setBlendMode (replaceExistingContents || fill.colour.isOpaque());
  898. setTexturesEnabled (0);
  899. }
  900. setPremultipliedColour (fill.colour);
  901. OpenGLHelpers::fillRect (area);
  902. }
  903. else if (fill.isGradient())
  904. {
  905. ColourGradient g2 (*(fill.gradient));
  906. g2.multiplyOpacity (fill.getOpacity());
  907. if (g2.point1 == g2.point2)
  908. {
  909. fillTexture (area, g2.getColourAtPosition (1.0), mask1, mask2, replaceExistingContents);
  910. }
  911. else
  912. {
  913. setBlendMode (replaceExistingContents || (mask1 == nullptr && fill.colour.isOpaque() && fill.gradient->isOpaque()));
  914. if (g2.isRadial)
  915. fillWithRadialGradient (area, g2, fill.transform, mask1, mask2);
  916. else
  917. fillWithLinearGradient (area, g2, fill.transform, mask1, mask2);
  918. }
  919. }
  920. else if (fill.isTiledImage())
  921. {
  922. renderImage (fill.image, area, fill.transform, fill.colour.getFloatAlpha(),
  923. mask1, mask2, replaceExistingContents, true);
  924. }
  925. }
  926. #if JUCE_USE_OPENGL_SHADERS
  927. void setShaderForGradientFill (const FillType& fill)
  928. {
  929. setPremultipliedBlendingMode();
  930. setSingleTextureMode();
  931. setSolidColour();
  932. const ColourGradient& g = *fill.gradient;
  933. bindTextureForGradient (g);
  934. const AffineTransform t (fill.transform.followedBy (AffineTransform::verticalFlip (target.height)));
  935. Point<float> p1 (g.point1.transformedBy (t));
  936. const Point<float> p2 (g.point2.transformedBy (t));
  937. const Point<float> p3 (Point<float> (g.point1.x + (g.point2.y - g.point1.y),
  938. g.point1.y - (g.point2.x - g.point1.x)).transformedBy (t));
  939. if (g.isRadial)
  940. {
  941. setShader (&(programs->radialGradient.program));
  942. programs->radialGradient.matrix.set (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  943. p2.x, p2.y, 1.0f, 0.0f,
  944. p3.x, p3.y, 0.0f, 1.0f));
  945. }
  946. else
  947. {
  948. p1 = Line<float> (p1, p3).findNearestPointTo (p2);
  949. const Point<float> delta (p2.x - p1.x, p1.y - p2.y);
  950. if (std::abs (delta.x) < std::abs (delta.y))
  951. {
  952. setShader (&(programs->linearGradient1.program));
  953. const float grad = delta.x / delta.y;
  954. programs->linearGradient1.gradientInfo.set (p1.x, p1.y, grad, (p2.y - grad * p2.x) - (p1.y - grad * p1.x));
  955. }
  956. else
  957. {
  958. setShader (&(programs->linearGradient2.program));
  959. const float grad = delta.y / delta.x;
  960. programs->linearGradient2.gradientInfo.set (p1.x, p1.y, grad, (p2.x - grad * p2.y) - (p1.x - grad * p1.y));
  961. }
  962. }
  963. }
  964. #endif
  965. void flushQuads() noexcept
  966. {
  967. if (quadQueueActive)
  968. {
  969. if (numVertices > 0)
  970. {
  971. glDrawArrays (GL_TRIANGLES, 0, numVertices);
  972. numVertices = 0;
  973. }
  974. quadQueueActive = false;
  975. glDisableClientState (GL_COLOR_ARRAY);
  976. }
  977. }
  978. void clearSelectedTextures() noexcept
  979. {
  980. for (int i = 0; i < numElementsInArray (currentTextureID); ++i)
  981. currentTextureID[i] = 0;
  982. }
  983. #if JUCE_USE_OPENGL_SHADERS
  984. void setShader (GLShaderProgram* newShader)
  985. {
  986. if (activeShader != newShader)
  987. {
  988. flushQuads();
  989. activeShader = newShader;
  990. glUseProgram (newShader != nullptr ? newShader->program : 0);
  991. }
  992. }
  993. #endif
  994. OpenGLTarget target;
  995. private:
  996. enum
  997. {
  998. maxVerticesPerBlock = 192,
  999. gradientTextureSize = 256,
  1000. numTexturesToCache = 8,
  1001. numGradientTexturesToCache = 6
  1002. };
  1003. GLuint previousFrameBufferTarget;
  1004. GLuint currentTextureID [3];
  1005. int texturesEnabled, currentActiveTexture;
  1006. bool blendingEnabled, blendEnabled;
  1007. GLenum srcFunction, dstFunction;
  1008. PixelARGB currentColour;
  1009. bool quadQueueActive;
  1010. GLshort vertices [maxVerticesPerBlock * 2];
  1011. uint32 colours [maxVerticesPerBlock];
  1012. int numVertices;
  1013. OwnedArray<OpenGLTexture> textures, gradientTextures;
  1014. int activeGradientIndex;
  1015. bool gradientNeedsRefresh;
  1016. #if JUCE_USE_OPENGL_SHADERS
  1017. GLShaderProgram* activeShader;
  1018. bool canUseShaders;
  1019. #endif
  1020. void resetMultiTextureMode (int index, const bool forRGBTextures)
  1021. {
  1022. setActiveTexture (index);
  1023. glDisable (GL_TEXTURE_2D);
  1024. glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  1025. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
  1026. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
  1027. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
  1028. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
  1029. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, forRGBTextures ? GL_SRC_COLOR : GL_SRC_ALPHA);
  1030. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
  1031. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
  1032. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
  1033. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
  1034. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
  1035. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1036. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1037. }
  1038. void resetMultiTextureModes (const bool forRGBTextures)
  1039. {
  1040. resetMultiTextureMode (2, forRGBTextures);
  1041. resetMultiTextureMode (1, forRGBTextures);
  1042. resetMultiTextureMode (0, forRGBTextures);
  1043. }
  1044. struct EdgeTableRenderer
  1045. {
  1046. EdgeTableRenderer (GLState& state_, const PixelARGB& colour_) noexcept
  1047. : state (state_), colour (colour_)
  1048. {
  1049. state.checkQuadQueueActive();
  1050. }
  1051. void setEdgeTableYPos (const int y) noexcept
  1052. {
  1053. currentY = y;
  1054. }
  1055. void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
  1056. {
  1057. PixelARGB c (colour);
  1058. c.multiplyAlpha (alphaLevel);
  1059. state.addQuadToList (x, currentY, 1, 1, c);
  1060. }
  1061. void handleEdgeTablePixelFull (const int x) noexcept
  1062. {
  1063. state.addQuadToList (x, currentY, 1, 1, colour);
  1064. }
  1065. void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept
  1066. {
  1067. PixelARGB c (colour);
  1068. c.multiplyAlpha (alphaLevel);
  1069. state.addQuadToList (x, currentY, width, 1, c);
  1070. }
  1071. void handleEdgeTableLineFull (const int x, const int width) noexcept
  1072. {
  1073. state.addQuadToList (x, currentY, width, 1, colour);
  1074. }
  1075. private:
  1076. GLState& state;
  1077. const PixelARGB colour;
  1078. int currentY;
  1079. JUCE_DECLARE_NON_COPYABLE (EdgeTableRenderer);
  1080. };
  1081. struct FloatRectangleRenderer
  1082. {
  1083. FloatRectangleRenderer (GLState& state_, const PixelARGB& colour_) noexcept
  1084. : state (state_), colour (colour_)
  1085. {
  1086. state.checkQuadQueueActive();
  1087. }
  1088. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  1089. {
  1090. if (w > 0 && h > 0)
  1091. {
  1092. PixelARGB c (colour);
  1093. c.multiplyAlpha (alpha);
  1094. state.addQuadToList (x, y, w, h, c);
  1095. }
  1096. }
  1097. private:
  1098. GLState& state;
  1099. const PixelARGB colour;
  1100. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  1101. };
  1102. void fillWithLinearGradient (const Rectangle<int>& rect, const ColourGradient& grad, const AffineTransform& transform,
  1103. const PositionedTexture* mask1, const PositionedTexture* mask2)
  1104. {
  1105. const Point<float> p1 (grad.point1.transformedBy (transform));
  1106. const Point<float> p2 (grad.point2.transformedBy (transform));
  1107. const Point<float> p3 (Point<float> (grad.point1.x - (grad.point2.y - grad.point1.y) / gradientTextureSize,
  1108. grad.point1.y + (grad.point2.x - grad.point1.x) / gradientTextureSize).transformedBy (transform));
  1109. const AffineTransform textureTransform (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  1110. p2.x, p2.y, 1.0f, 0.0f,
  1111. p3.x, p3.y, 0.0f, 1.0f));
  1112. const GLfloat l = (GLfloat) rect.getX();
  1113. const GLfloat r = (GLfloat) rect.getRight();
  1114. const GLfloat t = (GLfloat) rect.getY();
  1115. const GLfloat b = (GLfloat) rect.getBottom();
  1116. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  1117. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  1118. textureTransform.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1119. textureTransform.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1120. GLfloat textureCoords1[8], textureCoords2[8];
  1121. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &rect);
  1122. TemporaryColourModulationMode tmm;
  1123. bindTextureForGradient (grad);
  1124. setSolidColour();
  1125. drawTriangleStrip (vertices, textureCoords, 4);
  1126. }
  1127. void fillWithRadialGradient (const Rectangle<int>& rect, const ColourGradient& grad, const AffineTransform& transform,
  1128. const PositionedTexture* mask1, const PositionedTexture* mask2)
  1129. {
  1130. const Point<float> centre (grad.point1.transformedBy (transform));
  1131. const float screenRadius = centre.getDistanceFrom (rect.getCentre().toFloat())
  1132. + Point<int> (rect.getWidth() / 2,
  1133. rect.getHeight() / 2).getDistanceFromOrigin()
  1134. + 8.0f;
  1135. const AffineTransform inverse (transform.inverted());
  1136. const float sourceRadius = jmax (Point<float> (screenRadius, 0.0f).transformedBy (inverse).getDistanceFromOrigin(),
  1137. Point<float> (0.0f, screenRadius).transformedBy (inverse).getDistanceFromOrigin());
  1138. const int numDivisions = 90;
  1139. GLfloat vertices [4 + numDivisions * 2];
  1140. GLfloat textureCoords1 [4 + numDivisions * 2];
  1141. GLfloat textureCoords2 [4 + numDivisions * 2];
  1142. GLfloat textureCoords3 [4 + numDivisions * 2];
  1143. {
  1144. GLfloat* t = textureCoords1;
  1145. *t++ = 0.0f;
  1146. *t++ = 0.0f;
  1147. const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2);
  1148. for (int i = numDivisions + 1; --i >= 0;)
  1149. {
  1150. *t++ = texturePos;
  1151. *t++ = 0.0f;
  1152. }
  1153. }
  1154. {
  1155. GLfloat* v = vertices;
  1156. *v++ = centre.x;
  1157. *v++ = centre.y;
  1158. const Point<float> first (grad.point1.translated (0, -sourceRadius)
  1159. .transformedBy (transform));
  1160. *v++ = first.x;
  1161. *v++ = first.y;
  1162. for (int i = 1; i < numDivisions; ++i)
  1163. {
  1164. const float angle = i * (float_Pi * 2.0f / numDivisions);
  1165. const Point<float> p (grad.point1.translated (std::sin (angle) * sourceRadius,
  1166. std::cos (angle) * -sourceRadius)
  1167. .transformedBy (transform));
  1168. *v++ = p.x;
  1169. *v++ = p.y;
  1170. }
  1171. *v++ = first.x;
  1172. *v++ = first.y;
  1173. }
  1174. prepareMasks (mask1, mask2, textureCoords2, textureCoords3, nullptr);
  1175. if (mask1 != nullptr)
  1176. {
  1177. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  1178. mask1->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords2[i], textureCoords2[i + 1]);
  1179. if (mask2 != nullptr)
  1180. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  1181. mask2->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords3[i], textureCoords3[i + 1]);
  1182. }
  1183. scissor (rect);
  1184. bindTextureForGradient (grad);
  1185. setSolidColour();
  1186. TemporaryColourModulationMode tmm;
  1187. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1188. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords1);
  1189. glDrawArrays (GL_TRIANGLE_FAN, 0, numDivisions + 2);
  1190. disableScissor();
  1191. }
  1192. };
  1193. //==============================================================================
  1194. class ClipRegion_Mask;
  1195. //==============================================================================
  1196. class ClipRegionBase : public SingleThreadedReferenceCountedObject
  1197. {
  1198. public:
  1199. ClipRegionBase (OpenGLRenderer::GLState& state_) noexcept : state (state_) {}
  1200. virtual ~ClipRegionBase() {}
  1201. typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
  1202. virtual Ptr clone() const = 0;
  1203. virtual Ptr applyClipTo (const Ptr& target) = 0;
  1204. virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
  1205. virtual Ptr clipToRectangleList (const RectangleList&) = 0;
  1206. virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
  1207. virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
  1208. virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
  1209. virtual Ptr clipToTexture (const PositionedTexture&) = 0;
  1210. virtual Rectangle<int> getClipBounds() const = 0;
  1211. virtual void fillRect (const Rectangle<int>& area, const FillType&, bool replaceContents) = 0;
  1212. virtual void fillRect (const Rectangle<float>& area, const FillType&) = 0;
  1213. virtual void fillEdgeTable (EdgeTable& et, const FillType& fill) = 0;
  1214. virtual void drawImage (const OpenGLTextureFromImage&, const AffineTransform&, float alpha,
  1215. const Rectangle<int>& clip, const PositionedTexture* mask) = 0;
  1216. OpenGLRenderer::GLState& state;
  1217. private:
  1218. JUCE_DECLARE_NON_COPYABLE (ClipRegionBase);
  1219. };
  1220. //==============================================================================
  1221. class ClipRegion_Mask : public ClipRegionBase
  1222. {
  1223. public:
  1224. ClipRegion_Mask (const ClipRegion_Mask& other)
  1225. : ClipRegionBase (other.state),
  1226. clip (other.clip),
  1227. maskOrigin (other.clip.getPosition())
  1228. {
  1229. OpenGLTarget::TargetSaver ts;
  1230. state.flushQuads();
  1231. state.setSingleTextureMode();
  1232. state.clearSelectedTextures();
  1233. mask.initialise (clip.getWidth(), clip.getHeight());
  1234. OpenGLTarget m (mask, maskOrigin);
  1235. m.makeActiveFor2D();
  1236. state.disableBlend();
  1237. state.setSolidColour();
  1238. state.setSingleTextureMode();
  1239. OpenGLHelpers::drawTextureQuad (other.mask.getTextureID(), other.getMaskArea());
  1240. }
  1241. explicit ClipRegion_Mask (OpenGLRenderer::GLState& state_, const RectangleList& r)
  1242. : ClipRegionBase (state_),
  1243. clip (r.getBounds()),
  1244. maskOrigin (clip.getPosition())
  1245. {
  1246. OpenGLTarget::TargetSaver ts;
  1247. initialiseClear();
  1248. state.disableBlend();
  1249. state.fillRectangleList (r, PixelARGB (0xffffffff));
  1250. state.flushQuads();
  1251. }
  1252. Ptr clone() const { return new ClipRegion_Mask (*this); }
  1253. Rectangle<int> getClipBounds() const { return clip; }
  1254. Ptr applyClipTo (const Ptr& target)
  1255. {
  1256. return target->clipToTexture (PositionedTexture (mask.getTextureID(), getMaskArea(), clip));
  1257. }
  1258. Ptr clipToRectangle (const Rectangle<int>& r)
  1259. {
  1260. clip = clip.getIntersection (r);
  1261. return clip.isEmpty() ? nullptr : this;
  1262. }
  1263. Ptr clipToRectangleList (const RectangleList& r)
  1264. {
  1265. clip = clip.getIntersection (r.getBounds());
  1266. if (clip.isEmpty())
  1267. return nullptr;
  1268. RectangleList excluded (clip);
  1269. if (excluded.subtract (r))
  1270. {
  1271. if (excluded.getNumRectangles() == 1)
  1272. return excludeClipRectangle (excluded.getRectangle (0));
  1273. OpenGLTarget::TargetSaver ts;
  1274. makeMaskActive();
  1275. state.disableBlend();
  1276. state.fillRectangleList (excluded, PixelARGB (0));
  1277. state.flushQuads();
  1278. }
  1279. return this;
  1280. }
  1281. Ptr excludeClipRectangle (const Rectangle<int>& r)
  1282. {
  1283. if (r.contains (clip))
  1284. return nullptr;
  1285. OpenGLTarget::TargetSaver ts;
  1286. makeMaskActive();
  1287. state.setTexturesEnabled (0);
  1288. state.disableBlend();
  1289. state.setColour (PixelARGB (0));
  1290. OpenGLHelpers::fillRect (r);
  1291. return this;
  1292. }
  1293. Ptr clipToPath (const Path& p, const AffineTransform& t)
  1294. {
  1295. EdgeTable et (clip, p, t);
  1296. if (! et.isEmpty())
  1297. {
  1298. OpenGLTexture texture;
  1299. PositionedTexture pt (texture, et, et.getMaximumBounds());
  1300. return clipToTexture (pt);
  1301. }
  1302. return nullptr;
  1303. }
  1304. Ptr clipToTexture (const PositionedTexture& pt)
  1305. {
  1306. clip = clip.getIntersection (pt.clip);
  1307. if (clip.isEmpty())
  1308. return nullptr;
  1309. OpenGLTarget::TargetSaver ts;
  1310. makeMaskActive();
  1311. state.setBlendFunc (GL_ZERO, GL_SRC_ALPHA);
  1312. state.setSolidColour();
  1313. state.setSingleTextureMode();
  1314. OpenGLHelpers::drawTextureQuad (pt.textureID, pt.area);
  1315. return this;
  1316. }
  1317. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  1318. {
  1319. OpenGLTarget::TargetSaver ts;
  1320. makeMaskActive();
  1321. state.setBlendFunc (GL_ZERO, GL_SRC_ALPHA);
  1322. state.setSolidColour();
  1323. state.setSingleTextureMode();
  1324. state.bindTexture (image.textureID);
  1325. const GLfloat l = (GLfloat) maskOrigin.x;
  1326. const GLfloat t = (GLfloat) maskOrigin.y;
  1327. const GLfloat r = (GLfloat) (maskOrigin.x + mask.getWidth());
  1328. const GLfloat b = (GLfloat) (maskOrigin.y + mask.getHeight());
  1329. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  1330. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  1331. const AffineTransform inv (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  1332. image.fullHeightProportion / image.imageHeight));
  1333. inv.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1334. inv.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1335. textureCoords[1] = 1.0f - textureCoords[1];
  1336. textureCoords[3] = 1.0f - textureCoords[3];
  1337. textureCoords[5] = 1.0f - textureCoords[5];
  1338. textureCoords[7] = 1.0f - textureCoords[7];
  1339. state.drawTriangleStrip (vertices, textureCoords, 4);
  1340. return this;
  1341. }
  1342. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1343. {
  1344. jassert (! replaceContents);
  1345. const Rectangle<int> r (clip.getIntersection (area));
  1346. if (! r.isEmpty())
  1347. fillRectInternal (r, fill, false);
  1348. }
  1349. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1350. {
  1351. if (fill.isColour())
  1352. {
  1353. FloatRectangleRenderer frr (*this, fill);
  1354. RenderingHelpers::FloatRectangleRasterisingInfo (area).iterate (frr);
  1355. }
  1356. else
  1357. {
  1358. EdgeTable et (area);
  1359. fillEdgeTable (et, fill);
  1360. }
  1361. }
  1362. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1363. {
  1364. const Rectangle<int> r (et.getMaximumBounds().getIntersection (clip));
  1365. if (! r.isEmpty())
  1366. {
  1367. OpenGLTexture* texture = state.getTexture (r.getWidth(), r.getHeight());
  1368. PositionedTexture pt1 (*texture, et, r);
  1369. PositionedTexture pt2 (mask.getTextureID(), getMaskArea(), r);
  1370. state.fillTexture (r, fill, &pt2, &pt1, false);
  1371. state.releaseTexture (texture);
  1372. }
  1373. }
  1374. void fillRectInternal (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1375. {
  1376. PositionedTexture pt (mask.getTextureID(), getMaskArea(), area);
  1377. state.fillTexture (area, fill, &pt, nullptr, replaceContents);
  1378. }
  1379. void drawImage (const OpenGLTextureFromImage& source, const AffineTransform& transform,
  1380. float alpha, const Rectangle<int>& clipArea, const PositionedTexture* mask1)
  1381. {
  1382. const Rectangle<int> bufferArea (clipArea.getIntersection (clip));
  1383. if (! bufferArea.isEmpty())
  1384. {
  1385. PositionedTexture pt (mask.getTextureID(), getMaskArea(), bufferArea);
  1386. state.renderImage (source, bufferArea, transform, alpha, &pt, mask1, false, false);
  1387. }
  1388. }
  1389. private:
  1390. OpenGLFrameBuffer mask;
  1391. Rectangle<int> clip;
  1392. Point<int> maskOrigin;
  1393. Rectangle<int> getMaskArea() const noexcept { return Rectangle<int> (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()); }
  1394. void prepareFor2D() const { OpenGLTarget::applyFlippedMatrix (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()); }
  1395. void makeMaskActive()
  1396. {
  1397. state.flushQuads();
  1398. const bool b = mask.makeCurrentRenderingTarget();
  1399. (void) b; jassert (b);
  1400. prepareFor2D();
  1401. }
  1402. void initialiseClear()
  1403. {
  1404. state.flushQuads();
  1405. jassert (! clip.isEmpty());
  1406. state.setSingleTextureMode();
  1407. state.clearSelectedTextures();
  1408. mask.initialise (clip.getWidth(), clip.getHeight());
  1409. mask.makeCurrentAndClear();
  1410. state.setTexturesEnabled (0);
  1411. state.disableBlend();
  1412. prepareFor2D();
  1413. }
  1414. struct FloatRectangleRenderer
  1415. {
  1416. FloatRectangleRenderer (ClipRegion_Mask& mask_, const FillType& fill_) noexcept
  1417. : mask (mask_), fill (fill_), originalColour (fill_.colour)
  1418. {}
  1419. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  1420. {
  1421. if (w > 0 && h > 0)
  1422. {
  1423. fill.colour = originalColour.withMultipliedAlpha (alpha / 255.0f);
  1424. mask.fillRect (Rectangle<int> (x, y, w, h), fill, false);
  1425. }
  1426. }
  1427. private:
  1428. ClipRegion_Mask& mask;
  1429. FillType fill;
  1430. const Colour originalColour;
  1431. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  1432. };
  1433. ClipRegion_Mask& operator= (const ClipRegion_Mask&);
  1434. };
  1435. //==============================================================================
  1436. class ClipRegion_RectangleList : public ClipRegionBase
  1437. {
  1438. public:
  1439. explicit ClipRegion_RectangleList (OpenGLRenderer::GLState& state_, const Rectangle<int>& r) noexcept
  1440. : ClipRegionBase (state_), clip (r)
  1441. {}
  1442. explicit ClipRegion_RectangleList (OpenGLRenderer::GLState& state_, const RectangleList& r) noexcept
  1443. : ClipRegionBase (state_), clip (r)
  1444. {}
  1445. Ptr clone() const { return new ClipRegion_RectangleList (state, clip); }
  1446. Rectangle<int> getClipBounds() const { return clip.getBounds(); }
  1447. Ptr applyClipTo (const Ptr& target) { return target->clipToRectangleList (clip); }
  1448. Ptr clipToRectangle (const Rectangle<int>& r) { return clip.clipTo (r) ? this : nullptr; }
  1449. Ptr clipToRectangleList (const RectangleList& r) { return clip.clipTo (r) ? this : nullptr; }
  1450. Ptr excludeClipRectangle (const Rectangle<int>& r) { clip.subtract (r); return clip.isEmpty() ? nullptr : this; }
  1451. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  1452. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  1453. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  1454. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1455. {
  1456. if (fill.isColour())
  1457. {
  1458. state.setTexturesEnabled (0);
  1459. state.setBlendMode (replaceContents || fill.colour.isOpaque());
  1460. state.fillRectangleList (clip, area, fill.colour.getPixelARGB());
  1461. }
  1462. #if JUCE_USE_OPENGL_SHADERS
  1463. else if (state.shadersAvailable() && fill.isGradient())
  1464. {
  1465. state.setShaderForGradientFill (fill);
  1466. state.fillRectangleList (clip, area, fill.colour.getPixelARGB());
  1467. state.setShader (nullptr);
  1468. }
  1469. #endif
  1470. else
  1471. {
  1472. for (RectangleList::Iterator i (clip); i.next();)
  1473. {
  1474. const Rectangle<int> r (i.getRectangle()->getIntersection (area));
  1475. if (! r.isEmpty())
  1476. state.fillTexture (r, fill, nullptr, nullptr, replaceContents);
  1477. }
  1478. }
  1479. }
  1480. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1481. {
  1482. if (fill.isColour())
  1483. {
  1484. state.setTexturesEnabled (0);
  1485. state.setPremultipliedBlendingMode();
  1486. for (RectangleList::Iterator i (clip); i.next();)
  1487. {
  1488. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  1489. if (! r.isEmpty())
  1490. state.fillRect (r, fill.colour.getPixelARGB());
  1491. }
  1492. }
  1493. #if JUCE_USE_OPENGL_SHADERS
  1494. else if (state.shadersAvailable() && fill.isGradient())
  1495. {
  1496. state.setShaderForGradientFill (fill);
  1497. for (RectangleList::Iterator i (clip); i.next();)
  1498. {
  1499. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  1500. if (! r.isEmpty())
  1501. state.fillRect (r, fill.colour.getPixelARGB());
  1502. }
  1503. state.setShader (nullptr);
  1504. }
  1505. #endif
  1506. else
  1507. {
  1508. EdgeTable et (area);
  1509. fillEdgeTable (et, fill);
  1510. }
  1511. }
  1512. void drawImage (const OpenGLTextureFromImage& source, const AffineTransform& transform,
  1513. float alpha, const Rectangle<int>& clipArea, const PositionedTexture* mask)
  1514. {
  1515. for (RectangleList::Iterator i (clip); i.next();)
  1516. {
  1517. const Rectangle<int> bufferArea (i.getRectangle()->getIntersection (clipArea));
  1518. if (! bufferArea.isEmpty())
  1519. state.renderImage (source, bufferArea, transform, alpha, mask, nullptr, false, false);
  1520. }
  1521. }
  1522. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1523. {
  1524. if (fill.isColour())
  1525. {
  1526. state.setPremultipliedBlendingMode();
  1527. if (clip.containsRectangle (et.getMaximumBounds()))
  1528. {
  1529. state.fillEdgeTable (et, fill.colour.getPixelARGB());
  1530. }
  1531. else
  1532. {
  1533. EdgeTable et2 (clip);
  1534. et2.clipToEdgeTable (et);
  1535. state.fillEdgeTable (et2, fill.colour.getPixelARGB());
  1536. }
  1537. }
  1538. #if JUCE_USE_OPENGL_SHADERS
  1539. else if (state.shadersAvailable() && fill.isGradient())
  1540. {
  1541. state.setShaderForGradientFill (fill);
  1542. if (clip.containsRectangle (et.getMaximumBounds()))
  1543. {
  1544. state.fillEdgeTable (et, fill.colour.getPixelARGB());
  1545. }
  1546. else
  1547. {
  1548. EdgeTable et2 (clip);
  1549. et2.clipToEdgeTable (et);
  1550. state.fillEdgeTable (et2, fill.colour.getPixelARGB());
  1551. }
  1552. state.setShader (nullptr);
  1553. }
  1554. #endif
  1555. else
  1556. {
  1557. OpenGLTexture* texture = state.getTexture (clip.getBounds().getWidth(), clip.getBounds().getHeight());
  1558. PositionedTexture pt (*texture, et, clip.getBounds());
  1559. for (RectangleList::Iterator i (clip); i.next();)
  1560. {
  1561. const Rectangle<int> r (i.getRectangle()->getIntersection (pt.clip));
  1562. if (! r.isEmpty())
  1563. state.fillTexture (r, fill, &pt, nullptr, false);
  1564. }
  1565. state.releaseTexture (texture);
  1566. }
  1567. }
  1568. private:
  1569. RectangleList clip;
  1570. Ptr toMask() const
  1571. {
  1572. return new ClipRegion_Mask (state, clip);
  1573. }
  1574. ClipRegion_RectangleList& operator= (const ClipRegion_RectangleList&);
  1575. };
  1576. //==============================================================================
  1577. class OpenGLRenderer::SavedState
  1578. {
  1579. public:
  1580. SavedState (GLState* const state_)
  1581. : clip (new ClipRegion_RectangleList (*state_, Rectangle<int> (state_->target.width, state_->target.height))),
  1582. transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
  1583. state (state_), transparencyLayerAlpha (1.0f)
  1584. {
  1585. }
  1586. SavedState (const SavedState& other)
  1587. : clip (other.clip), transform (other.transform), font (other.font),
  1588. fillType (other.fillType), interpolationQuality (other.interpolationQuality),
  1589. state (other.state), transparencyLayerAlpha (other.transparencyLayerAlpha),
  1590. transparencyLayer (other.transparencyLayer), previousTarget (other.previousTarget.createCopy())
  1591. {
  1592. }
  1593. bool clipToRectangle (const Rectangle<int>& r)
  1594. {
  1595. if (clip != nullptr)
  1596. {
  1597. if (transform.isOnlyTranslated)
  1598. {
  1599. cloneClipIfMultiplyReferenced();
  1600. clip = clip->clipToRectangle (transform.translated (r));
  1601. }
  1602. else
  1603. {
  1604. Path p;
  1605. p.addRectangle (r);
  1606. clipToPath (p, AffineTransform::identity);
  1607. }
  1608. }
  1609. return clip != nullptr;
  1610. }
  1611. bool clipToRectangleList (const RectangleList& r)
  1612. {
  1613. if (clip != nullptr)
  1614. {
  1615. if (transform.isOnlyTranslated)
  1616. {
  1617. cloneClipIfMultiplyReferenced();
  1618. RectangleList offsetList (r);
  1619. offsetList.offsetAll (transform.xOffset, transform.yOffset);
  1620. clip = clip->clipToRectangleList (offsetList);
  1621. }
  1622. else
  1623. {
  1624. clipToPath (r.toPath(), AffineTransform::identity);
  1625. }
  1626. }
  1627. return clip != nullptr;
  1628. }
  1629. bool excludeClipRectangle (const Rectangle<int>& r)
  1630. {
  1631. if (clip != nullptr)
  1632. {
  1633. cloneClipIfMultiplyReferenced();
  1634. if (transform.isOnlyTranslated)
  1635. {
  1636. clip = clip->excludeClipRectangle (transform.translated (r));
  1637. }
  1638. else
  1639. {
  1640. Path p;
  1641. p.addRectangle (r.toFloat());
  1642. p.applyTransform (transform.complexTransform);
  1643. p.addRectangle (clip->getClipBounds().toFloat());
  1644. p.setUsingNonZeroWinding (false);
  1645. clip = clip->clipToPath (p, AffineTransform::identity);
  1646. }
  1647. }
  1648. return clip != nullptr;
  1649. }
  1650. void clipToPath (const Path& p, const AffineTransform& t)
  1651. {
  1652. if (clip != nullptr)
  1653. {
  1654. cloneClipIfMultiplyReferenced();
  1655. clip = clip->clipToPath (p, transform.getTransformWith (t));
  1656. }
  1657. }
  1658. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
  1659. {
  1660. if (clip != nullptr)
  1661. {
  1662. Path p;
  1663. p.addRectangle (sourceImage.getBounds());
  1664. clipToPath (p, t);
  1665. if (sourceImage.hasAlphaChannel() && clip != nullptr)
  1666. {
  1667. cloneClipIfMultiplyReferenced();
  1668. clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
  1669. }
  1670. }
  1671. }
  1672. bool clipRegionIntersects (const Rectangle<int>& r) const
  1673. {
  1674. return clip != nullptr
  1675. && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
  1676. : getClipBounds().intersects (r));
  1677. }
  1678. Rectangle<int> getClipBounds() const
  1679. {
  1680. return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
  1681. : Rectangle<int>();
  1682. }
  1683. SavedState* beginTransparencyLayer (float opacity)
  1684. {
  1685. SavedState* s = new SavedState (*this);
  1686. if (clip != nullptr)
  1687. {
  1688. const Rectangle<int> clipBounds (clip->getClipBounds());
  1689. state->flushQuads();
  1690. s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
  1691. s->previousTarget = new OpenGLTarget (state->target);
  1692. state->target = OpenGLTarget (*OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
  1693. s->transparencyLayerAlpha = opacity;
  1694. s->cloneClipIfMultiplyReferenced();
  1695. s->state->target.makeActiveFor2D();
  1696. }
  1697. return s;
  1698. }
  1699. void endTransparencyLayer (SavedState& finishedLayerState)
  1700. {
  1701. if (clip != nullptr)
  1702. {
  1703. jassert (finishedLayerState.previousTarget != nullptr);
  1704. state->flushQuads();
  1705. state->target = *finishedLayerState.previousTarget;
  1706. finishedLayerState.previousTarget = nullptr;
  1707. state->target.makeActiveFor2D();
  1708. const Rectangle<int> clipBounds (clip->getClipBounds());
  1709. clip->drawImage (finishedLayerState.transparencyLayer,
  1710. AffineTransform::translation ((float) clipBounds.getX(), (float) clipBounds.getY()),
  1711. finishedLayerState.transparencyLayerAlpha, clipBounds, nullptr);
  1712. }
  1713. }
  1714. //==============================================================================
  1715. void fillRect (const Rectangle<int>& r, const bool replaceContents)
  1716. {
  1717. if (clip != nullptr)
  1718. {
  1719. if (transform.isOnlyTranslated)
  1720. {
  1721. clip->fillRect (r.translated (transform.xOffset, transform.yOffset),
  1722. getFillType(), replaceContents);
  1723. }
  1724. else
  1725. {
  1726. Path p;
  1727. p.addRectangle (r);
  1728. fillPath (p, AffineTransform::identity);
  1729. }
  1730. }
  1731. }
  1732. void fillRect (const Rectangle<float>& r)
  1733. {
  1734. if (clip != nullptr)
  1735. {
  1736. if (transform.isOnlyTranslated)
  1737. {
  1738. const Rectangle<float> c (r.translated ((float) transform.xOffset, (float) transform.yOffset)
  1739. .getIntersection (clip->getClipBounds().toFloat()));
  1740. if (! c.isEmpty())
  1741. clip->fillRect (c, getFillType());
  1742. }
  1743. else
  1744. {
  1745. Path p;
  1746. p.addRectangle (r);
  1747. fillPath (p, AffineTransform::identity);
  1748. }
  1749. }
  1750. }
  1751. void fillPath (const Path& path, const AffineTransform& t)
  1752. {
  1753. if (clip != nullptr)
  1754. {
  1755. EdgeTable et (clip->getClipBounds(), path, transform.getTransformWith (t));
  1756. fillEdgeTable (et);
  1757. }
  1758. }
  1759. void drawGlyph (int glyphNumber, const AffineTransform& t)
  1760. {
  1761. if (clip != nullptr)
  1762. {
  1763. if (transform.isOnlyTranslated && t.isOnlyTranslation())
  1764. {
  1765. RenderingHelpers::GlyphCache <CachedGlyphEdgeTable, SavedState>::getInstance()
  1766. .drawGlyph (*this, font, glyphNumber,
  1767. transform.xOffset + t.getTranslationX(),
  1768. transform.yOffset + t.getTranslationY());
  1769. }
  1770. else
  1771. {
  1772. const float fontHeight = font.getHeight();
  1773. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph
  1774. (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  1775. .followedBy (t))));
  1776. if (et != nullptr)
  1777. fillEdgeTable (*et);
  1778. }
  1779. }
  1780. }
  1781. void fillEdgeTable (const EdgeTable& et, const float x, const int y)
  1782. {
  1783. if (clip != nullptr)
  1784. {
  1785. EdgeTable et2 (et);
  1786. et2.translate (x, y);
  1787. fillEdgeTable (et2);
  1788. }
  1789. }
  1790. void drawLine (const Line <float>& line)
  1791. {
  1792. Path p;
  1793. p.addLineSegment (line, 1.0f);
  1794. fillPath (p, AffineTransform::identity);
  1795. }
  1796. //==============================================================================
  1797. void drawImage (const Image& image, const AffineTransform& trans)
  1798. {
  1799. if (clip == nullptr || fillType.colour.isTransparent())
  1800. return;
  1801. const Rectangle<int> clipBounds (clip->getClipBounds());
  1802. const AffineTransform t (transform.getTransformWith (trans));
  1803. const float alpha = fillType.colour.getFloatAlpha();
  1804. if (t.isOnlyTranslation())
  1805. {
  1806. int tx = (int) (t.getTranslationX() * 256.0f);
  1807. int ty = (int) (t.getTranslationY() * 256.0f);
  1808. if (((tx | ty) & 0xf8) == 0)
  1809. {
  1810. tx = ((tx + 128) >> 8);
  1811. ty = ((ty + 128) >> 8);
  1812. clip->drawImage (image, t, alpha, Rectangle<int> (tx, ty, image.getWidth(), image.getHeight()), nullptr);
  1813. return;
  1814. }
  1815. }
  1816. if (! t.isSingularity())
  1817. {
  1818. Path p;
  1819. p.addRectangle (image.getBounds());
  1820. OpenGLTexture* texture = state->getTexture (clipBounds.getWidth(), clipBounds.getHeight());
  1821. EdgeTable et (clipBounds, p, t);
  1822. PositionedTexture pt (*texture, et, clipBounds);
  1823. clip->drawImage (image, t, alpha, clipBounds, &pt);
  1824. state->releaseTexture (texture);
  1825. }
  1826. }
  1827. void setFillType (const FillType& newFill)
  1828. {
  1829. fillType = newFill;
  1830. state->resetGradient();
  1831. }
  1832. //==============================================================================
  1833. ClipRegionBase::Ptr clip;
  1834. RenderingHelpers::TranslationOrTransform transform;
  1835. Font font;
  1836. FillType fillType;
  1837. Graphics::ResamplingQuality interpolationQuality;
  1838. GLState* state;
  1839. private:
  1840. float transparencyLayerAlpha;
  1841. Image transparencyLayer;
  1842. ScopedPointer<OpenGLTarget> previousTarget;
  1843. void cloneClipIfMultiplyReferenced()
  1844. {
  1845. if (clip->getReferenceCount() > 1)
  1846. clip = clip->clone();
  1847. }
  1848. FillType getFillType() const
  1849. {
  1850. return fillType.transformed (transform.getTransform());
  1851. }
  1852. void fillEdgeTable (EdgeTable& et)
  1853. {
  1854. clip->fillEdgeTable (et, getFillType());
  1855. }
  1856. class CachedGlyphEdgeTable
  1857. {
  1858. public:
  1859. CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}
  1860. void draw (OpenGLRenderer::SavedState& state, float x, const float y) const
  1861. {
  1862. if (snapToIntegerCoordinate)
  1863. x = std::floor (x + 0.5f);
  1864. if (edgeTable != nullptr)
  1865. state.fillEdgeTable (*edgeTable, x, roundToInt (y));
  1866. }
  1867. void generate (const Font& newFont, const int glyphNumber)
  1868. {
  1869. font = newFont;
  1870. snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
  1871. glyph = glyphNumber;
  1872. const float fontHeight = font.getHeight();
  1873. edgeTable = font.getTypeface()->getEdgeTableForGlyph (glyphNumber,
  1874. AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  1875. #if JUCE_MAC || JUCE_IOS
  1876. .translated (0.0f, -0.5f)
  1877. #endif
  1878. );
  1879. }
  1880. Font font;
  1881. int glyph, lastAccessCount;
  1882. bool snapToIntegerCoordinate;
  1883. private:
  1884. ScopedPointer <EdgeTable> edgeTable;
  1885. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable);
  1886. };
  1887. SavedState& operator= (const SavedState&);
  1888. };
  1889. //==============================================================================
  1890. OpenGLRenderer::OpenGLRenderer (OpenGLComponent& target)
  1891. : glState (new GLState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight()))),
  1892. stack (new SavedState (glState))
  1893. {
  1894. }
  1895. OpenGLRenderer::OpenGLRenderer (OpenGLFrameBuffer& target)
  1896. : glState (new GLState (OpenGLTarget (target, Point<int>()))),
  1897. stack (new SavedState (glState))
  1898. {
  1899. }
  1900. OpenGLRenderer::OpenGLRenderer (unsigned int frameBufferID, int width, int height)
  1901. : glState (new GLState (OpenGLTarget (frameBufferID, width, height))),
  1902. stack (new SavedState (glState))
  1903. {
  1904. }
  1905. OpenGLRenderer::~OpenGLRenderer()
  1906. {
  1907. }
  1908. bool OpenGLRenderer::isVectorDevice() const { return false; }
  1909. void OpenGLRenderer::setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
  1910. void OpenGLRenderer::addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
  1911. float OpenGLRenderer::getScaleFactor() { return stack->transform.getScaleFactor(); }
  1912. Rectangle<int> OpenGLRenderer::getClipBounds() const { return stack->getClipBounds(); }
  1913. bool OpenGLRenderer::isClipEmpty() const { return stack->clip == nullptr; }
  1914. bool OpenGLRenderer::clipRegionIntersects (const Rectangle<int>& r) { return stack->clipRegionIntersects (r); }
  1915. bool OpenGLRenderer::clipToRectangle (const Rectangle<int>& r) { return stack->clipToRectangle (r); }
  1916. bool OpenGLRenderer::clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
  1917. void OpenGLRenderer::excludeClipRectangle (const Rectangle<int>& r) { stack->excludeClipRectangle (r); }
  1918. void OpenGLRenderer::clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
  1919. void OpenGLRenderer::clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
  1920. void OpenGLRenderer::saveState() { stack.save(); }
  1921. void OpenGLRenderer::restoreState() { stack.restore(); }
  1922. void OpenGLRenderer::beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
  1923. void OpenGLRenderer::endTransparencyLayer() { stack.endTransparencyLayer(); }
  1924. void OpenGLRenderer::setFill (const FillType& fillType) { stack->setFillType (fillType); }
  1925. void OpenGLRenderer::setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
  1926. void OpenGLRenderer::setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
  1927. void OpenGLRenderer::fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
  1928. void OpenGLRenderer::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
  1929. void OpenGLRenderer::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
  1930. void OpenGLRenderer::drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
  1931. void OpenGLRenderer::drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
  1932. void OpenGLRenderer::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
  1933. void OpenGLRenderer::drawLine (const Line <float>& line) { stack->drawLine (line); }
  1934. void OpenGLRenderer::setFont (const Font& newFont) { stack->font = newFont; }
  1935. Font OpenGLRenderer::getFont() { return stack->font; }
  1936. END_JUCE_NAMESPACE