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.

2333 lines
85KB

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