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.

3092 lines
116KB

  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. //==============================================================================
  19. struct OpenGLTarget
  20. {
  21. OpenGLTarget (GLuint frameBufferID_, int width_, int height_) noexcept
  22. : frameBuffer (nullptr), frameBufferID (frameBufferID_),
  23. x (0), y (0), width (width_), height (height_)
  24. {}
  25. OpenGLTarget (OpenGLFrameBuffer& frameBuffer_, const Point<int>& origin) noexcept
  26. : frameBuffer (&frameBuffer_), frameBufferID (0), x (origin.x), y (origin.y),
  27. width (frameBuffer_.getWidth()), height (frameBuffer_.getHeight())
  28. {}
  29. OpenGLTarget (const OpenGLTarget& other) noexcept
  30. : frameBuffer (other.frameBuffer), frameBufferID (other.frameBufferID),
  31. x (other.x), y (other.y), width (other.width), height (other.height)
  32. {}
  33. void makeActiveFor2D() const
  34. {
  35. if (frameBuffer != nullptr)
  36. frameBuffer->makeCurrentRenderingTarget();
  37. else
  38. OpenGLFrameBuffer::setCurrentFrameBufferTarget (frameBufferID);
  39. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  40. applyFlippedMatrix (x, y, width, height);
  41. #else
  42. glViewport (0, 0, width, height);
  43. #endif
  44. glDisable (GL_DEPTH_TEST);
  45. }
  46. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  47. void scissor (Rectangle<int> r) const
  48. {
  49. r = r.translated (-x, -y);
  50. OpenGLHelpers::enableScissorTest (r.withY (height - r.getBottom()));
  51. }
  52. static void applyFlippedMatrix (const int x, const int y, const int width, const int height)
  53. {
  54. glMatrixMode (GL_PROJECTION);
  55. glLoadIdentity();
  56. #if JUCE_OPENGL_ES
  57. glOrthof ((GLfloat) x, (GLfloat) (x + width), (GLfloat) (y + height), (GLfloat) y, 0.0f, 1.0f);
  58. #else
  59. glOrtho (x, x + width, y + height, y, 0, 1);
  60. #endif
  61. glViewport (0, 0, width, height);
  62. }
  63. #endif
  64. OpenGLFrameBuffer* frameBuffer;
  65. GLuint frameBufferID;
  66. int x, y, width, height;
  67. };
  68. struct ClippedEdgeTable
  69. {
  70. ClippedEdgeTable (const EdgeTable& et, const Rectangle<int>& clip)
  71. : table (&et)
  72. {
  73. if (! clip.contains (et.getMaximumBounds()))
  74. {
  75. clipped = new EdgeTable (clip);
  76. clipped->clipToEdgeTable (et);
  77. table = clipped;
  78. }
  79. }
  80. ClippedEdgeTable (const EdgeTable& et, const RectangleList& clip)
  81. : table (&et)
  82. {
  83. if (! clip.containsRectangle (et.getMaximumBounds()))
  84. {
  85. clipped = new EdgeTable (clip);
  86. clipped->clipToEdgeTable (et);
  87. table = clipped;
  88. }
  89. }
  90. const EdgeTable* table;
  91. ScopedPointer<EdgeTable> clipped;
  92. };
  93. //==============================================================================
  94. class PositionedTexture
  95. {
  96. public:
  97. PositionedTexture (OpenGLTexture& texture, const EdgeTable& et, const Rectangle<int>& clip_)
  98. : clip (clip_.getIntersection (et.getMaximumBounds()))
  99. {
  100. const ClippedEdgeTable clippedTable (et, clip);
  101. EdgeTableAlphaMap alphaMap (*(clippedTable.table));
  102. texture.loadAlpha (alphaMap.data, alphaMap.area.getWidth(), alphaMap.area.getHeight());
  103. textureID = texture.getTextureID();
  104. area = alphaMap.area;
  105. }
  106. PositionedTexture (GLuint textureID_, const Rectangle<int> area_, const Rectangle<int> clip_) noexcept
  107. : textureID (textureID_), area (area_), clip (clip_)
  108. {}
  109. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  110. template <typename ValueType>
  111. void getTextureCoordAt (ValueType x, ValueType y, GLfloat& resultX, GLfloat& resultY) const noexcept
  112. {
  113. resultX = (x - area.getX()) / (float) area.getWidth();
  114. resultY = (area.getBottom() - y) / (float) area.getHeight();
  115. }
  116. void prepareTextureCoords (const Rectangle<int>* const area, GLfloat* const textureCoords) const noexcept
  117. {
  118. if (area != nullptr)
  119. {
  120. getTextureCoordAt (area->getX(), area->getY(), textureCoords[0], textureCoords[1]);
  121. getTextureCoordAt (area->getRight(), area->getY(), textureCoords[2], textureCoords[3]);
  122. getTextureCoordAt (area->getX(), area->getBottom(), textureCoords[4], textureCoords[5]);
  123. getTextureCoordAt (area->getRight(), area->getBottom(), textureCoords[6], textureCoords[7]);
  124. }
  125. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  126. }
  127. #endif
  128. GLuint textureID;
  129. Rectangle<int> area, clip;
  130. private:
  131. struct EdgeTableAlphaMap
  132. {
  133. EdgeTableAlphaMap (const EdgeTable& et)
  134. : area (et.getMaximumBounds().withSize (nextPowerOfTwo (et.getMaximumBounds().getWidth()),
  135. nextPowerOfTwo (et.getMaximumBounds().getHeight())))
  136. {
  137. data.calloc (area.getWidth() * area.getHeight());
  138. et.iterate (*this);
  139. }
  140. inline void setEdgeTableYPos (const int y) noexcept
  141. {
  142. currentLine = data + (area.getBottom() - 1 - y) * area.getWidth() - area.getX();
  143. }
  144. inline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
  145. {
  146. currentLine[x] = (uint8) alphaLevel;
  147. }
  148. inline void handleEdgeTablePixelFull (const int x) const noexcept
  149. {
  150. currentLine[x] = 255;
  151. }
  152. inline void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept
  153. {
  154. memset (currentLine + x, (uint8) alphaLevel, width);
  155. }
  156. inline void handleEdgeTableLineFull (int x, int width) const noexcept
  157. {
  158. memset (currentLine + x, 255, width);
  159. }
  160. HeapBlock<uint8> data;
  161. const Rectangle<int> area;
  162. private:
  163. uint8* currentLine;
  164. JUCE_DECLARE_NON_COPYABLE (EdgeTableAlphaMap);
  165. };
  166. };
  167. //==============================================================================
  168. #if JUCE_USE_OPENGL_SHADERS
  169. class ShaderPrograms : public ReferenceCountedObject
  170. {
  171. public:
  172. ShaderPrograms()
  173. : areShadersSupported (OpenGLShaderProgram::getLanguageVersion() >= 1.199)
  174. {
  175. }
  176. const bool areShadersSupported;
  177. typedef ReferenceCountedObjectPtr<ShaderPrograms> Ptr;
  178. //==============================================================================
  179. struct ShaderProgramHolder
  180. {
  181. ShaderProgramHolder (const char* fragmentShader)
  182. {
  183. program.addShader ("attribute vec2 position;"
  184. "uniform vec4 screenBounds;"
  185. "void main()"
  186. "{"
  187. " gl_FrontColor = gl_Color;"
  188. " vec2 scaled = (position - screenBounds.xy) / screenBounds.zw;"
  189. " gl_Position = vec4 (scaled.x - 1.0, 1.0 - scaled.y, 0, 1.0);"
  190. "}", GL_VERTEX_SHADER);
  191. program.addShader (fragmentShader, GL_FRAGMENT_SHADER);
  192. program.link();
  193. }
  194. OpenGLShaderProgram program;
  195. };
  196. struct ShaderBase : public ShaderProgramHolder
  197. {
  198. ShaderBase (const char* fragmentShader)
  199. : ShaderProgramHolder (fragmentShader),
  200. screenBounds (program, "screenBounds")
  201. {}
  202. void set2DBounds (const Rectangle<float>& bounds)
  203. {
  204. screenBounds.set (bounds.getX(), bounds.getY(), 0.5f * bounds.getWidth(), 0.5f * bounds.getHeight());
  205. }
  206. private:
  207. OpenGLShaderProgram::Uniform screenBounds;
  208. };
  209. struct MaskedShaderParams
  210. {
  211. MaskedShaderParams (const OpenGLShaderProgram& program)
  212. : maskTexture (program, "maskTexture"),
  213. maskBounds (program, "maskBounds")
  214. {}
  215. void setBounds (const Rectangle<int>& area, const OpenGLTarget& target) const
  216. {
  217. maskBounds.set (area.getX() - target.x, target.height - (area.getBottom() - target.y),
  218. area.getWidth(), area.getHeight());
  219. }
  220. OpenGLShaderProgram::Uniform maskTexture, maskBounds;
  221. };
  222. //==============================================================================
  223. struct SolidColourProgram : public ShaderBase
  224. {
  225. SolidColourProgram()
  226. : ShaderBase ("void main()"
  227. "{"
  228. " gl_FragColor = gl_Color;"
  229. "}")
  230. {
  231. }
  232. };
  233. #define JUCE_DECLARE_SHADER_VERSION "#version 120\n"
  234. #define JUCE_DECLARE_MASK_UNIFORMS "uniform sampler2D maskTexture;" \
  235. "uniform ivec4 maskBounds;"
  236. #define JUCE_FRAGCOORD_TO_MASK_POS "vec2 ((gl_FragCoord.x - maskBounds.x) / maskBounds.z," \
  237. "(gl_FragCoord.y - maskBounds.y) / maskBounds.w)"
  238. #define JUCE_GET_MASK_ALPHA "texture2D (maskTexture, " JUCE_FRAGCOORD_TO_MASK_POS ").a"
  239. struct SolidColourMaskedProgram : public ShaderBase
  240. {
  241. SolidColourMaskedProgram()
  242. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  243. JUCE_DECLARE_MASK_UNIFORMS
  244. "void main()"
  245. "{"
  246. " gl_FragColor = gl_Color * " JUCE_GET_MASK_ALPHA ";"
  247. "}"),
  248. maskParams (program)
  249. {
  250. }
  251. MaskedShaderParams maskParams;
  252. };
  253. //==============================================================================
  254. struct RadialGradientParams
  255. {
  256. RadialGradientParams (const OpenGLShaderProgram& program)
  257. : gradientTexture (program, "gradientTexture"),
  258. matrix (program, "matrix")
  259. {}
  260. void setMatrix (const Point<float>& p1, const Point<float>& p2, const Point<float>& p3)
  261. {
  262. const AffineTransform t (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  263. p2.x, p2.y, 1.0f, 0.0f,
  264. p3.x, p3.y, 0.0f, 1.0f));
  265. const GLfloat m[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  266. matrix.set (m, 6);
  267. }
  268. OpenGLShaderProgram::Uniform gradientTexture, matrix;
  269. };
  270. #define JUCE_DECLARE_MATRIX_UNIFORM "uniform float matrix[6];"
  271. #define JUCE_DECLARE_RADIAL_UNIFORMS "uniform sampler2D gradientTexture;" JUCE_DECLARE_MATRIX_UNIFORM
  272. #define JUCE_MATRIX_TIMES_FRAGCOORD "(vec2 (matrix[0], matrix[3]) * gl_FragCoord.x" \
  273. " + vec2 (matrix[1], matrix[4]) * gl_FragCoord.y " \
  274. " + vec2 (matrix[2], matrix[5]))"
  275. #define JUCE_GET_TEXTURE_COLOUR "(gl_Color.w * texture2D (gradientTexture, vec2 (gradientPos, 0.5)))"
  276. struct RadialGradientProgram : public ShaderBase
  277. {
  278. RadialGradientProgram()
  279. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  280. JUCE_DECLARE_RADIAL_UNIFORMS
  281. "void main()"
  282. "{"
  283. " float gradientPos = length (" JUCE_MATRIX_TIMES_FRAGCOORD ");"
  284. " gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  285. "}"),
  286. gradientParams (program)
  287. {}
  288. RadialGradientParams gradientParams;
  289. };
  290. struct RadialGradientMaskedProgram : public ShaderBase
  291. {
  292. RadialGradientMaskedProgram()
  293. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  294. JUCE_DECLARE_RADIAL_UNIFORMS
  295. JUCE_DECLARE_MASK_UNIFORMS
  296. "void main()"
  297. "{"
  298. " float gradientPos = length (" JUCE_MATRIX_TIMES_FRAGCOORD ");"
  299. " gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  300. "}"),
  301. gradientParams (program),
  302. maskParams (program)
  303. {}
  304. RadialGradientParams gradientParams;
  305. MaskedShaderParams maskParams;
  306. };
  307. //==============================================================================
  308. struct LinearGradientParams
  309. {
  310. LinearGradientParams (const OpenGLShaderProgram& program)
  311. : gradientTexture (program, "gradientTexture"),
  312. gradientInfo (program, "gradientInfo")
  313. {}
  314. OpenGLShaderProgram::Uniform gradientTexture, gradientInfo;
  315. };
  316. #define JUCE_DECLARE_LINEAR_UNIFORMS "uniform sampler2D gradientTexture;" \
  317. "uniform vec4 gradientInfo;"
  318. struct LinearGradient1Program : public ShaderBase
  319. {
  320. LinearGradient1Program()
  321. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  322. JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  323. "void main()"
  324. "{"
  325. " float gradientPos = (gl_FragCoord.y - (gradientInfo.y + (gradientInfo.z * (gl_FragCoord.x - gradientInfo.x)))) / gradientInfo.w;"
  326. " gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  327. "}"),
  328. gradientParams (program)
  329. {}
  330. LinearGradientParams gradientParams;
  331. };
  332. struct LinearGradient1MaskedProgram : public ShaderBase
  333. {
  334. LinearGradient1MaskedProgram()
  335. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  336. JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  337. JUCE_DECLARE_MASK_UNIFORMS
  338. "void main()"
  339. "{"
  340. " float gradientPos = (gl_FragCoord.y - (gradientInfo.y + (gradientInfo.z * (gl_FragCoord.x - gradientInfo.x)))) / gradientInfo.w;"
  341. " gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  342. "}"),
  343. gradientParams (program),
  344. maskParams (program)
  345. {}
  346. LinearGradientParams gradientParams;
  347. MaskedShaderParams maskParams;
  348. };
  349. struct LinearGradient2Program : public ShaderBase
  350. {
  351. LinearGradient2Program()
  352. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  353. JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  354. "void main()"
  355. "{"
  356. " float gradientPos = (gl_FragCoord.x - (gradientInfo.x + (gradientInfo.z * (gl_FragCoord.y - gradientInfo.y)))) / gradientInfo.w;"
  357. " gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  358. "}"),
  359. gradientParams (program)
  360. {}
  361. LinearGradientParams gradientParams;
  362. };
  363. struct LinearGradient2MaskedProgram : public ShaderBase
  364. {
  365. LinearGradient2MaskedProgram()
  366. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  367. JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  368. JUCE_DECLARE_MASK_UNIFORMS
  369. "void main()"
  370. "{"
  371. " float gradientPos = (gl_FragCoord.x - (gradientInfo.x + (gradientInfo.z * (gl_FragCoord.y - gradientInfo.y)))) / gradientInfo.w;"
  372. " gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  373. "}"),
  374. gradientParams (program),
  375. maskParams (program)
  376. {}
  377. LinearGradientParams gradientParams;
  378. MaskedShaderParams maskParams;
  379. };
  380. //==============================================================================
  381. struct ImageParams
  382. {
  383. ImageParams (const OpenGLShaderProgram& program)
  384. : imageTexture (program, "imageTexture"),
  385. matrix (program, "matrix"),
  386. imageRepeatSize (program, "imageRepeatSize")
  387. {}
  388. void setMatrix (const AffineTransform& trans,
  389. const int imageWidth, const int imageHeight,
  390. const float fullWidthProportion, const float fullHeightProportion,
  391. const float targetX, const float targetY, const float targetHeight) const
  392. {
  393. const AffineTransform t (trans.translated (-targetX, -targetY)
  394. .followedBy (AffineTransform::verticalFlip (targetHeight))
  395. .inverted().scaled (fullWidthProportion / imageWidth,
  396. fullHeightProportion / imageHeight));
  397. const GLfloat m[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  398. matrix.set (m, 6);
  399. imageRepeatSize.set (fullWidthProportion, fullHeightProportion);
  400. }
  401. void setMatrix (const AffineTransform& trans, const OpenGLTextureFromImage& image,
  402. const float targetX, const float targetY, const float targetHeight) const
  403. {
  404. setMatrix (trans,
  405. image.imageWidth, image.imageHeight,
  406. image.fullWidthProportion, image.fullHeightProportion,
  407. targetX, targetY, targetHeight);
  408. }
  409. OpenGLShaderProgram::Uniform imageTexture, matrix, imageRepeatSize;
  410. };
  411. #define JUCE_DECLARE_IMAGE_UNIFORMS "uniform sampler2D imageTexture;" \
  412. "uniform vec2 imageRepeatSize;" JUCE_DECLARE_MATRIX_UNIFORM
  413. #define JUCE_GET_IMAGE_PIXEL "texture2D (imageTexture, vec2 (texturePos.x, 1.0 - texturePos.y))"
  414. struct ImageProgram : public ShaderBase
  415. {
  416. ImageProgram()
  417. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  418. JUCE_DECLARE_IMAGE_UNIFORMS
  419. "void main()"
  420. "{"
  421. " vec2 texturePos = clamp (" JUCE_MATRIX_TIMES_FRAGCOORD ", vec2 (0, 0), imageRepeatSize);"
  422. " gl_FragColor = gl_Color.w * " JUCE_GET_IMAGE_PIXEL ";"
  423. "}"),
  424. imageParams (program)
  425. {}
  426. ImageParams imageParams;
  427. };
  428. struct ImageMaskedProgram : public ShaderBase
  429. {
  430. ImageMaskedProgram()
  431. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  432. JUCE_DECLARE_IMAGE_UNIFORMS
  433. JUCE_DECLARE_MASK_UNIFORMS
  434. "void main()"
  435. "{"
  436. " vec2 texturePos = clamp (" JUCE_MATRIX_TIMES_FRAGCOORD ", vec2 (0, 0), imageRepeatSize);"
  437. " gl_FragColor = gl_Color.w * " JUCE_GET_IMAGE_PIXEL " * " JUCE_GET_MASK_ALPHA ";"
  438. "}"),
  439. imageParams (program),
  440. maskParams (program)
  441. {}
  442. ImageParams imageParams;
  443. MaskedShaderParams maskParams;
  444. };
  445. struct TiledImageProgram : public ShaderBase
  446. {
  447. TiledImageProgram()
  448. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  449. JUCE_DECLARE_IMAGE_UNIFORMS
  450. "void main()"
  451. "{"
  452. " vec2 texturePos = mod (" JUCE_MATRIX_TIMES_FRAGCOORD ", imageRepeatSize);"
  453. " gl_FragColor = gl_Color.w * " JUCE_GET_IMAGE_PIXEL ";"
  454. "}"),
  455. imageParams (program)
  456. {}
  457. ImageParams imageParams;
  458. };
  459. struct TiledImageMaskedProgram : public ShaderBase
  460. {
  461. TiledImageMaskedProgram()
  462. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  463. JUCE_DECLARE_IMAGE_UNIFORMS
  464. JUCE_DECLARE_MASK_UNIFORMS
  465. "void main()"
  466. "{"
  467. " vec2 texturePos = mod (" JUCE_MATRIX_TIMES_FRAGCOORD ", imageRepeatSize);"
  468. " gl_FragColor = gl_Color.w * " JUCE_GET_IMAGE_PIXEL " * " JUCE_GET_MASK_ALPHA ";"
  469. "}"),
  470. imageParams (program),
  471. maskParams (program)
  472. {}
  473. ImageParams imageParams;
  474. MaskedShaderParams maskParams;
  475. };
  476. struct CopyTextureProgram : public ShaderBase
  477. {
  478. CopyTextureProgram()
  479. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  480. JUCE_DECLARE_IMAGE_UNIFORMS
  481. "void main()"
  482. "{"
  483. " vec2 texturePos = mod (" JUCE_MATRIX_TIMES_FRAGCOORD ", imageRepeatSize);"
  484. " gl_FragColor = " JUCE_GET_IMAGE_PIXEL ";"
  485. "}"),
  486. imageParams (program)
  487. {}
  488. ImageParams imageParams;
  489. };
  490. struct MaskTextureProgram : public ShaderBase
  491. {
  492. MaskTextureProgram()
  493. : ShaderBase (JUCE_DECLARE_SHADER_VERSION
  494. JUCE_DECLARE_IMAGE_UNIFORMS
  495. "void main()"
  496. "{"
  497. " vec2 texturePos = " JUCE_MATRIX_TIMES_FRAGCOORD ";"
  498. " if (texturePos.x >= 0 && texturePos.y >= 0 && texturePos.x < imageRepeatSize.x && texturePos.y < imageRepeatSize.y)"
  499. " gl_FragColor = gl_Color * " JUCE_GET_IMAGE_PIXEL ".a;"
  500. " else"
  501. " gl_FragColor = vec4 (0, 0, 0, 0);"
  502. "}"),
  503. imageParams (program)
  504. {}
  505. ImageParams imageParams;
  506. };
  507. SolidColourProgram solidColourProgram;
  508. SolidColourMaskedProgram solidColourMasked;
  509. RadialGradientProgram radialGradient;
  510. RadialGradientMaskedProgram radialGradientMasked;
  511. LinearGradient1Program linearGradient1;
  512. LinearGradient1MaskedProgram linearGradient1Masked;
  513. LinearGradient2Program linearGradient2;
  514. LinearGradient2MaskedProgram linearGradient2Masked;
  515. ImageProgram image;
  516. ImageMaskedProgram imageMasked;
  517. TiledImageProgram tiledImage;
  518. TiledImageMaskedProgram tiledImageMasked;
  519. CopyTextureProgram copyTexture;
  520. MaskTextureProgram maskTexture;
  521. };
  522. #endif
  523. //==============================================================================
  524. struct StateHelpers
  525. {
  526. struct QuadQueue;
  527. struct ActiveTextures;
  528. //==============================================================================
  529. struct BlendingMode
  530. {
  531. BlendingMode() noexcept
  532. : blendingEnabled (false), srcFunction (0), dstFunction (0)
  533. {}
  534. void resync() noexcept
  535. {
  536. glDisable (GL_BLEND);
  537. srcFunction = dstFunction = 0;
  538. }
  539. void setPremultipliedBlendingMode (QuadQueue& quadQueue) noexcept
  540. {
  541. setBlendFunc (quadQueue, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  542. }
  543. void setBlendFunc (QuadQueue& quadQueue, GLenum src, GLenum dst)
  544. {
  545. if (! blendingEnabled)
  546. {
  547. quadQueue.flush();
  548. blendingEnabled = true;
  549. glEnable (GL_BLEND);
  550. }
  551. if (srcFunction != src || dstFunction != dst)
  552. {
  553. quadQueue.flush();
  554. srcFunction = src;
  555. dstFunction = dst;
  556. glBlendFunc (src, dst);
  557. }
  558. }
  559. void disableBlend (QuadQueue& quadQueue) noexcept
  560. {
  561. if (blendingEnabled)
  562. {
  563. quadQueue.flush();
  564. blendingEnabled = false;
  565. glDisable (GL_BLEND);
  566. }
  567. }
  568. void setBlendMode (QuadQueue& quadQueue, const bool replaceExistingContents) noexcept
  569. {
  570. if (replaceExistingContents)
  571. disableBlend (quadQueue);
  572. else
  573. setPremultipliedBlendingMode (quadQueue);
  574. }
  575. private:
  576. bool blendingEnabled;
  577. GLenum srcFunction, dstFunction;
  578. };
  579. //==============================================================================
  580. struct CurrentColour
  581. {
  582. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  583. CurrentColour() noexcept
  584. : currentColour (0xffffffff)
  585. {}
  586. void resync() noexcept
  587. {
  588. currentColour = PixelARGB (0xffffffff);
  589. glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
  590. }
  591. void setPremultipliedColour (const Colour& c) noexcept
  592. {
  593. setColour (c.getPixelARGB());
  594. }
  595. void setColour (const float alpha) noexcept
  596. {
  597. const uint8 v = (uint8) jmin (255, (int) (alpha * 255.0f));
  598. setColour (PixelARGB (v, v, v, v));
  599. }
  600. void setColour (const PixelARGB& c) noexcept
  601. {
  602. if (currentColour.getARGB() != c.getARGB())
  603. {
  604. currentColour = c;
  605. glColor4f (c.getRed() / 255.0f, c.getGreen() / 255.0f,
  606. c.getBlue() / 255.0f, c.getAlpha() / 255.0f);
  607. }
  608. }
  609. void setSolidColour() noexcept
  610. {
  611. if (currentColour.getARGB() != 0xffffffff)
  612. {
  613. currentColour = PixelARGB (0xffffffff);
  614. glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
  615. }
  616. }
  617. private:
  618. PixelARGB currentColour;
  619. #endif
  620. };
  621. //==============================================================================
  622. struct QuadQueue
  623. {
  624. QuadQueue() noexcept
  625. : numIndices (0), numVertices (0), isActive (false)
  626. {}
  627. void prepare (ActiveTextures& activeTextures, CurrentColour& currentColour)
  628. {
  629. if (! isActive)
  630. {
  631. jassert (numIndices == 0 && numVertices == 0);
  632. activeTextures.setTexturesEnabled (*this, 0);
  633. glEnableClientState (GL_COLOR_ARRAY);
  634. glVertexPointer (2, GL_SHORT, 0, vertices);
  635. glColorPointer (4, GL_UNSIGNED_BYTE, 0, colours);
  636. currentColour.setSolidColour();
  637. isActive = true; // (careful to do this last, as the preceding calls may change it)
  638. }
  639. }
  640. void add (const int x, const int y, const int w, const int h, const PixelARGB& colour) noexcept
  641. {
  642. jassert (isActive && w > 0 && h > 0);
  643. GLshort* const v = vertices + numVertices * 2;
  644. v[0] = v[4] = (GLshort) x;
  645. v[1] = v[3] = (GLshort) y;
  646. v[2] = v[6] = (GLshort) (x + w);
  647. v[5] = v[7] = (GLshort) (y + h);
  648. uint32* const c = colours + numVertices;
  649. c[0] = c[1] = c[2] = c[3] = colour.getInRGBAMemoryOrder();
  650. GLubyte* const i = indices + numIndices;
  651. i[0] = (GLubyte) numVertices;
  652. i[1] = i[3] = (GLubyte) (numVertices + 1);
  653. i[2] = i[4] = (GLubyte) (numVertices + 2);
  654. i[5] = (GLubyte) (numVertices + 3);
  655. numVertices += 4;
  656. numIndices += 6;
  657. if (numIndices > maxVerticesPerBlock - 6)
  658. draw();
  659. }
  660. void add (const Rectangle<float>& r, const PixelARGB& colour) noexcept
  661. {
  662. FloatRectangleRenderer frr (*this, colour);
  663. RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (frr);
  664. }
  665. void flush() noexcept
  666. {
  667. if (isActive)
  668. {
  669. if (numIndices > 0)
  670. draw();
  671. isActive = false;
  672. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  673. glDisableClientState (GL_COLOR_ARRAY);
  674. #endif
  675. }
  676. }
  677. void addEdgeTable (const EdgeTable& et, const PixelARGB& colour)
  678. {
  679. EdgeTableRenderer etr (*this, colour);
  680. et.iterate (etr);
  681. }
  682. private:
  683. enum { maxVerticesPerBlock = 192 }; // must not go over 256 because the indices are 8-bit.
  684. GLshort vertices [maxVerticesPerBlock * 2];
  685. GLubyte indices [maxVerticesPerBlock];
  686. uint32 colours [maxVerticesPerBlock];
  687. int numIndices, numVertices;
  688. bool isActive;
  689. void draw() noexcept
  690. {
  691. glDrawElements (GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices);
  692. numIndices = 0;
  693. numVertices = 0;
  694. }
  695. struct EdgeTableRenderer
  696. {
  697. EdgeTableRenderer (QuadQueue& quadQueue_, const PixelARGB& colour_) noexcept
  698. : quadQueue (quadQueue_), colour (colour_)
  699. {}
  700. void setEdgeTableYPos (const int y) noexcept
  701. {
  702. currentY = y;
  703. }
  704. void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
  705. {
  706. PixelARGB c (colour);
  707. c.multiplyAlpha (alphaLevel);
  708. quadQueue.add (x, currentY, 1, 1, c);
  709. }
  710. void handleEdgeTablePixelFull (const int x) noexcept
  711. {
  712. quadQueue.add (x, currentY, 1, 1, colour);
  713. }
  714. void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept
  715. {
  716. PixelARGB c (colour);
  717. c.multiplyAlpha (alphaLevel);
  718. quadQueue.add (x, currentY, width, 1, c);
  719. }
  720. void handleEdgeTableLineFull (const int x, const int width) noexcept
  721. {
  722. quadQueue.add (x, currentY, width, 1, colour);
  723. }
  724. private:
  725. QuadQueue& quadQueue;
  726. const PixelARGB colour;
  727. int currentY;
  728. JUCE_DECLARE_NON_COPYABLE (EdgeTableRenderer);
  729. };
  730. struct FloatRectangleRenderer
  731. {
  732. FloatRectangleRenderer (QuadQueue& quadQueue_, const PixelARGB& colour_) noexcept
  733. : quadQueue (quadQueue_), colour (colour_)
  734. {}
  735. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  736. {
  737. if (w > 0 && h > 0)
  738. {
  739. PixelARGB c (colour);
  740. c.multiplyAlpha (alpha);
  741. quadQueue.add (x, y, w, h, c);
  742. }
  743. }
  744. private:
  745. QuadQueue& quadQueue;
  746. const PixelARGB colour;
  747. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  748. };
  749. };
  750. //==============================================================================
  751. struct ActiveTextures
  752. {
  753. ActiveTextures() noexcept
  754. : texturesEnabled (0), currentActiveTexture (0)
  755. {}
  756. void clear() noexcept
  757. {
  758. for (int i = 0; i < numElementsInArray (currentTextureID); ++i)
  759. currentTextureID[i] = 0;
  760. }
  761. void clearCurrent() noexcept
  762. {
  763. currentTextureID [currentActiveTexture] = 0;
  764. }
  765. void setTexturesEnabled (QuadQueue& quadQueue, const int textureIndexMask) noexcept
  766. {
  767. if (texturesEnabled != textureIndexMask)
  768. {
  769. quadQueue.flush();
  770. for (int i = 3; --i >= 0;)
  771. {
  772. if ((texturesEnabled & (1 << i)) != (textureIndexMask & (1 << i)))
  773. {
  774. setActiveTexture (i);
  775. if ((textureIndexMask & (1 << i)) != 0)
  776. glEnable (GL_TEXTURE_2D);
  777. else
  778. {
  779. glDisable (GL_TEXTURE_2D);
  780. currentTextureID[i] = 0;
  781. }
  782. }
  783. }
  784. texturesEnabled = textureIndexMask;
  785. }
  786. }
  787. void setSingleTextureMode (QuadQueue& quadQueue) noexcept
  788. {
  789. setTexturesEnabled (quadQueue, 1);
  790. setActiveTexture (0);
  791. }
  792. void setActiveTexture (const int index) noexcept
  793. {
  794. if (currentActiveTexture != index)
  795. {
  796. currentActiveTexture = index;
  797. glActiveTexture (GL_TEXTURE0 + index);
  798. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  799. glClientActiveTexture (GL_TEXTURE0 + index);
  800. #endif
  801. }
  802. }
  803. void bindTexture (const GLuint textureID) noexcept
  804. {
  805. if (currentTextureID [currentActiveTexture] != textureID)
  806. {
  807. currentTextureID [currentActiveTexture] = textureID;
  808. glBindTexture (GL_TEXTURE_2D, textureID);
  809. }
  810. else
  811. {
  812. #if JUCE_DEBUG
  813. GLint t = 0;
  814. glGetIntegerv (GL_TEXTURE_BINDING_2D, &t);
  815. jassert (t == (GLint) textureID);
  816. #endif
  817. }
  818. }
  819. private:
  820. GLuint currentTextureID [3];
  821. int texturesEnabled, currentActiveTexture;
  822. };
  823. //==============================================================================
  824. struct TextureCache
  825. {
  826. TextureCache() noexcept
  827. : activeGradientIndex (0), gradientNeedsRefresh (true)
  828. {}
  829. OpenGLTexture* getTexture (ActiveTextures& activeTextures, int w, int h)
  830. {
  831. if (textures.size() < numTexturesToCache)
  832. {
  833. activeTextures.clear();
  834. return new OpenGLTexture();
  835. }
  836. for (int i = 0; i < numTexturesToCache - 2; ++i)
  837. {
  838. const OpenGLTexture* const t = textures.getUnchecked(i);
  839. if (t->getWidth() == w && t->getHeight() == h)
  840. return textures.removeAndReturn (i);
  841. }
  842. return textures.removeAndReturn (0);
  843. }
  844. void releaseTexture (ActiveTextures& activeTextures, OpenGLTexture* texture)
  845. {
  846. activeTextures.clearCurrent();
  847. textures.add (texture);
  848. }
  849. void resetGradient() noexcept
  850. {
  851. gradientNeedsRefresh = true;
  852. }
  853. void bindTextureForGradient (ActiveTextures& activeTextures, const ColourGradient& gradient)
  854. {
  855. if (gradientNeedsRefresh)
  856. {
  857. gradientNeedsRefresh = false;
  858. if (gradientTextures.size() < numGradientTexturesToCache)
  859. {
  860. activeGradientIndex = gradientTextures.size();
  861. activeTextures.clear();
  862. gradientTextures.add (new OpenGLTexture());
  863. }
  864. else
  865. {
  866. activeGradientIndex = (activeGradientIndex + 1) % numGradientTexturesToCache;
  867. }
  868. PixelARGB lookup [gradientTextureSize];
  869. gradient.createLookupTable (lookup, gradientTextureSize);
  870. gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1);
  871. }
  872. activeTextures.bindTexture (gradientTextures.getUnchecked (activeGradientIndex)->getTextureID());
  873. }
  874. enum { gradientTextureSize = 256 };
  875. private:
  876. enum { numTexturesToCache = 8, numGradientTexturesToCache = 10 };
  877. OwnedArray<OpenGLTexture> textures, gradientTextures;
  878. int activeGradientIndex;
  879. bool gradientNeedsRefresh;
  880. };
  881. #if JUCE_USE_OPENGL_SHADERS
  882. //==============================================================================
  883. struct CurrentShader
  884. {
  885. CurrentShader() noexcept
  886. : canUseShaders (false), activeShader (nullptr)
  887. {
  888. OpenGLContext* context = OpenGLContext::getCurrentContext();
  889. jassert (context != nullptr); // You can only use this class when you have an active GL context!
  890. const Identifier programValueID ("GraphicsContextPrograms");
  891. programs = dynamic_cast <ShaderPrograms*> (context->properties [programValueID].getObject());
  892. if (programs == nullptr)
  893. {
  894. programs = new ShaderPrograms();
  895. context->properties.set (programValueID, var (programs));
  896. }
  897. canUseShaders = programs->areShadersSupported;
  898. }
  899. void setShader (const Rectangle<int>& bounds, QuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  900. {
  901. if (activeShader != &(shader.program))
  902. {
  903. quadQueue.flush();
  904. activeShader = &(shader.program);
  905. glUseProgram (shader.program.programID);
  906. currentBounds = bounds;
  907. shader.set2DBounds (bounds.toFloat());
  908. }
  909. else if (bounds != currentBounds)
  910. {
  911. currentBounds = bounds;
  912. shader.set2DBounds (bounds.toFloat());
  913. }
  914. }
  915. void setShader (OpenGLTarget& target, QuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  916. {
  917. setShader (Rectangle<int> (target.x, target.y, target.width, target.height), quadQueue, shader);
  918. }
  919. void clearShader (QuadQueue& quadQueue)
  920. {
  921. if (activeShader != nullptr)
  922. {
  923. quadQueue.flush();
  924. activeShader = nullptr;
  925. glUseProgram (0);
  926. }
  927. }
  928. ShaderPrograms::Ptr programs;
  929. bool canUseShaders;
  930. private:
  931. OpenGLShaderProgram* activeShader;
  932. Rectangle<int> currentBounds;
  933. };
  934. #endif
  935. };
  936. //==============================================================================
  937. class OpenGLGraphicsContext::GLState
  938. {
  939. public:
  940. GLState (const OpenGLTarget& target_) noexcept
  941. : target (target_),
  942. previousFrameBufferTarget (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  943. {
  944. initialiseGLExtensions();
  945. // This object can only be created and used when the current thread has an active OpenGL context.
  946. jassert (OpenGLHelpers::isContextActive());
  947. target.makeActiveFor2D();
  948. blendMode.resync();
  949. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  950. currentColour.resync();
  951. glDisableClientState (GL_COLOR_ARRAY);
  952. glDisableClientState (GL_NORMAL_ARRAY);
  953. glEnableClientState (GL_VERTEX_ARRAY);
  954. for (int i = 3; --i >= 0;)
  955. {
  956. activeTextures.setActiveTexture (i);
  957. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  958. }
  959. #endif
  960. activeTextures.clear();
  961. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  962. resetMultiTextureModes (false);
  963. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  964. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  965. #endif
  966. }
  967. ~GLState()
  968. {
  969. #if JUCE_USE_OPENGL_SHADERS
  970. currentShader.clearShader (quadQueue);
  971. #endif
  972. quadQueue.flush();
  973. OpenGLFrameBuffer::setCurrentFrameBufferTarget (previousFrameBufferTarget);
  974. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  975. resetMultiTextureModes (true);
  976. #endif
  977. }
  978. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  979. void scissor (const Rectangle<int>& r)
  980. {
  981. quadQueue.flush();
  982. target.scissor (r);
  983. }
  984. void disableScissor()
  985. {
  986. quadQueue.flush();
  987. glDisable (GL_SCISSOR_TEST);
  988. }
  989. void prepareMasks (const PositionedTexture* const mask1, const PositionedTexture* const mask2,
  990. GLfloat* const textureCoords1, GLfloat* const textureCoords2, const Rectangle<int>* const area)
  991. {
  992. if (mask1 != nullptr)
  993. {
  994. activeTextures.setTexturesEnabled (quadQueue, mask2 != nullptr ? 7 : 3);
  995. activeTextures.setActiveTexture (0);
  996. mask1->prepareTextureCoords (area, textureCoords1);
  997. activeTextures.bindTexture (mask1->textureID);
  998. activeTextures.setActiveTexture (1);
  999. if (mask2 != nullptr)
  1000. {
  1001. mask2->prepareTextureCoords (area, textureCoords2);
  1002. activeTextures.bindTexture (mask2->textureID);
  1003. activeTextures.setActiveTexture (2);
  1004. }
  1005. }
  1006. else
  1007. {
  1008. activeTextures.setSingleTextureMode (quadQueue);
  1009. }
  1010. }
  1011. #endif
  1012. void fillRect (const Rectangle<int>& r, const PixelARGB& colour) noexcept
  1013. {
  1014. jassert (! r.isEmpty());
  1015. quadQueue.prepare (activeTextures, currentColour);
  1016. quadQueue.add (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  1017. }
  1018. void fillRect (const Rectangle<float>& r, const PixelARGB& colour) noexcept
  1019. {
  1020. jassert (! r.isEmpty());
  1021. quadQueue.prepare (activeTextures, currentColour);
  1022. quadQueue.add (r, colour);
  1023. }
  1024. void fillRectangleList (const RectangleList& list, const PixelARGB& colour)
  1025. {
  1026. quadQueue.prepare (activeTextures, currentColour);
  1027. for (RectangleList::Iterator i (list); i.next();)
  1028. quadQueue.add (i.getRectangle()->getX(), i.getRectangle()->getY(),
  1029. i.getRectangle()->getWidth(), i.getRectangle()->getHeight(), colour);
  1030. }
  1031. void fillRectangleList (const RectangleList& list, const Rectangle<int>& clip, const PixelARGB& colour)
  1032. {
  1033. quadQueue.prepare (activeTextures, currentColour);
  1034. for (RectangleList::Iterator i (list); i.next();)
  1035. {
  1036. const Rectangle<int> r (i.getRectangle()->getIntersection (clip));
  1037. if (! r.isEmpty())
  1038. quadQueue.add (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  1039. }
  1040. }
  1041. void fillEdgeTable (const EdgeTable& et, const PixelARGB& colour)
  1042. {
  1043. quadQueue.prepare (activeTextures, currentColour);
  1044. quadQueue.addEdgeTable (et, colour);
  1045. }
  1046. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1047. void drawTriangleStrip (const GLfloat* const vertices, const GLfloat* const textureCoords, const int numVertices) noexcept
  1048. {
  1049. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1050. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  1051. glDrawArrays (GL_TRIANGLE_STRIP, 0, numVertices);
  1052. }
  1053. void renderImage (const OpenGLTextureFromImage& image,
  1054. const Rectangle<int>& clip, const AffineTransform& transform, float alpha,
  1055. const PositionedTexture* mask1, const PositionedTexture* mask2,
  1056. const bool replaceExistingContents, const bool isTiled)
  1057. {
  1058. quadQueue.flush();
  1059. blendMode.setBlendMode (quadQueue, replaceExistingContents);
  1060. currentColour.setColour (alpha);
  1061. GLfloat textureCoords1[8], textureCoords2[8];
  1062. if ((! isTiled) || (isPowerOfTwo (image.imageWidth) && isPowerOfTwo (image.imageHeight)))
  1063. {
  1064. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &clip);
  1065. activeTextures.bindTexture (image.textureID);
  1066. TemporaryColourModulationMode tmm;
  1067. if (isTiled)
  1068. {
  1069. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  1070. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  1071. }
  1072. const GLfloat clipX = (GLfloat) clip.getX();
  1073. const GLfloat clipY = (GLfloat) clip.getY();
  1074. const GLfloat clipR = (GLfloat) clip.getRight();
  1075. const GLfloat clipB = (GLfloat) clip.getBottom();
  1076. const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  1077. GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  1078. {
  1079. const AffineTransform t (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  1080. image.fullHeightProportion / image.imageHeight));
  1081. t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1082. t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1083. textureCoords[1] = 1.0f - textureCoords[1];
  1084. textureCoords[3] = 1.0f - textureCoords[3];
  1085. textureCoords[5] = 1.0f - textureCoords[5];
  1086. textureCoords[7] = 1.0f - textureCoords[7];
  1087. }
  1088. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1089. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  1090. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  1091. if (isTiled)
  1092. {
  1093. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1094. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1095. }
  1096. }
  1097. else
  1098. {
  1099. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, nullptr);
  1100. activeTextures.bindTexture (image.textureID);
  1101. TemporaryColourModulationMode tmm;
  1102. scissor (clip);
  1103. glPushMatrix();
  1104. OpenGLHelpers::applyTransform (transform);
  1105. GLfloat vertices[8];
  1106. const GLfloat textureCoords[] = { 0, 1.0f, image.fullWidthProportion, 1.0f,
  1107. 0, 1.0f - image.fullHeightProportion, image.fullWidthProportion, 1.0f - image.fullHeightProportion };
  1108. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1109. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  1110. const Rectangle<int> targetArea (clip.toFloat().transformed (transform.inverted()).getSmallestIntegerContainer());
  1111. int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), image.imageWidth);
  1112. int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), image.imageHeight);
  1113. const int right = targetArea.getRight();
  1114. const int bottom = targetArea.getBottom();
  1115. while (y < bottom)
  1116. {
  1117. vertices[1] = vertices[3] = (GLfloat) y;
  1118. vertices[5] = vertices[7] = (GLfloat) (y + image.imageHeight);
  1119. for (int x1 = x; x1 < right; x1 += image.imageWidth)
  1120. {
  1121. vertices[0] = vertices[4] = (GLfloat) x1;
  1122. vertices[2] = vertices[6] = (GLfloat) (x1 + image.imageWidth);
  1123. if (mask1 != nullptr)
  1124. {
  1125. float t[] = { vertices[0], vertices[1], vertices[2], vertices[3],
  1126. vertices[4], vertices[5], vertices[6], vertices[7] };
  1127. transform.transformPoints (t[0], t[1], t[2], t[3]);
  1128. transform.transformPoints (t[4], t[5], t[6], t[7]);
  1129. mask1->getTextureCoordAt (t[0], t[1], textureCoords1[0], textureCoords1[1]);
  1130. mask1->getTextureCoordAt (t[2], t[3], textureCoords1[2], textureCoords1[3]);
  1131. mask1->getTextureCoordAt (t[4], t[5], textureCoords1[4], textureCoords1[5]);
  1132. mask1->getTextureCoordAt (t[6], t[7], textureCoords1[6], textureCoords1[7]);
  1133. if (mask2 != nullptr)
  1134. {
  1135. mask2->getTextureCoordAt (t[0], t[1], textureCoords2[0], textureCoords2[1]);
  1136. mask2->getTextureCoordAt (t[2], t[3], textureCoords2[2], textureCoords2[3]);
  1137. mask2->getTextureCoordAt (t[4], t[5], textureCoords2[4], textureCoords2[5]);
  1138. mask2->getTextureCoordAt (t[6], t[7], textureCoords2[6], textureCoords2[7]);
  1139. }
  1140. }
  1141. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  1142. }
  1143. y += image.imageHeight;
  1144. }
  1145. glPopMatrix();
  1146. disableScissor();
  1147. }
  1148. }
  1149. void fillTexture (const Rectangle<int>& area, const FillType& fill,
  1150. const PositionedTexture* mask1, const PositionedTexture* mask2,
  1151. const bool replaceExistingContents)
  1152. {
  1153. jassert (! (mask1 == nullptr && mask2 != nullptr));
  1154. if (fill.isColour())
  1155. {
  1156. GLfloat textureCoords1[8], textureCoords2[8];
  1157. if (mask1 != nullptr)
  1158. {
  1159. blendMode.setBlendMode (quadQueue, replaceExistingContents);
  1160. activeTextures.setTexturesEnabled (quadQueue, mask2 != nullptr ? 3 : 1);
  1161. activeTextures.setActiveTexture (0);
  1162. mask1->prepareTextureCoords (&area, textureCoords1);
  1163. activeTextures.bindTexture (mask1->textureID);
  1164. if (mask2 != nullptr)
  1165. {
  1166. activeTextures.setActiveTexture (1);
  1167. mask2->prepareTextureCoords (&area, textureCoords2);
  1168. activeTextures.bindTexture (mask2->textureID);
  1169. }
  1170. }
  1171. else
  1172. {
  1173. blendMode.setBlendMode (quadQueue, replaceExistingContents || fill.colour.isOpaque());
  1174. activeTextures.setTexturesEnabled (quadQueue, 0);
  1175. }
  1176. currentColour.setPremultipliedColour (fill.colour);
  1177. OpenGLHelpers::fillRect (area);
  1178. }
  1179. else if (fill.isGradient())
  1180. {
  1181. ColourGradient g2 (*(fill.gradient));
  1182. g2.multiplyOpacity (fill.getOpacity());
  1183. if (g2.point1 == g2.point2)
  1184. {
  1185. fillTexture (area, g2.getColourAtPosition (1.0), mask1, mask2, replaceExistingContents);
  1186. }
  1187. else
  1188. {
  1189. blendMode.setBlendMode (quadQueue, replaceExistingContents || (mask1 == nullptr && fill.colour.isOpaque() && fill.gradient->isOpaque()));
  1190. if (g2.isRadial)
  1191. fillWithRadialGradient (area, g2, fill.transform, mask1, mask2);
  1192. else
  1193. fillWithLinearGradient (area, g2, fill.transform, mask1, mask2);
  1194. }
  1195. }
  1196. else if (fill.isTiledImage())
  1197. {
  1198. renderImage (fill.image, area, fill.transform, fill.colour.getFloatAlpha(),
  1199. mask1, mask2, replaceExistingContents, true);
  1200. }
  1201. }
  1202. #endif
  1203. #if JUCE_USE_OPENGL_SHADERS
  1204. void setShaderForGradientFill (const ColourGradient& g, const AffineTransform& transform,
  1205. const int maskTextureID, const Rectangle<int>* const maskArea)
  1206. {
  1207. blendMode.setPremultipliedBlendingMode (quadQueue);
  1208. currentColour.setSolidColour();
  1209. if (maskArea != nullptr)
  1210. {
  1211. activeTextures.setTexturesEnabled (quadQueue, 3);
  1212. activeTextures.setActiveTexture (1);
  1213. activeTextures.bindTexture (maskTextureID);
  1214. activeTextures.setActiveTexture (0);
  1215. textureCache.bindTextureForGradient (activeTextures, g);
  1216. }
  1217. else
  1218. {
  1219. activeTextures.setSingleTextureMode (quadQueue);
  1220. textureCache.bindTextureForGradient (activeTextures, g);
  1221. }
  1222. const AffineTransform t (transform.translated ((float) -target.x, (float) -target.y)
  1223. .followedBy (AffineTransform::verticalFlip ((float) target.height)));
  1224. Point<float> p1 (g.point1.transformedBy (t));
  1225. const Point<float> p2 (g.point2.transformedBy (t));
  1226. const Point<float> p3 (Point<float> (g.point1.x + (g.point2.y - g.point1.y),
  1227. g.point1.y - (g.point2.x - g.point1.x)).transformedBy (t));
  1228. ShaderPrograms* const programs = currentShader.programs;
  1229. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1230. if (g.isRadial)
  1231. {
  1232. ShaderPrograms::RadialGradientParams* gradientParams;
  1233. if (maskArea == nullptr)
  1234. {
  1235. currentShader.setShader (target, quadQueue, programs->radialGradient);
  1236. gradientParams = &programs->radialGradient.gradientParams;
  1237. }
  1238. else
  1239. {
  1240. currentShader.setShader (target, quadQueue, programs->radialGradientMasked);
  1241. gradientParams = &programs->radialGradientMasked.gradientParams;
  1242. maskParams = &programs->radialGradientMasked.maskParams;
  1243. }
  1244. gradientParams->setMatrix (p1, p2, p3);
  1245. }
  1246. else
  1247. {
  1248. p1 = Line<float> (p1, p3).findNearestPointTo (p2);
  1249. const Point<float> delta (p2.x - p1.x, p1.y - p2.y);
  1250. const ShaderPrograms::LinearGradientParams* gradientParams;
  1251. float grad, length;
  1252. if (std::abs (delta.x) < std::abs (delta.y))
  1253. {
  1254. if (maskArea == nullptr)
  1255. {
  1256. currentShader.setShader (target, quadQueue, programs->linearGradient1);
  1257. gradientParams = &(programs->linearGradient1.gradientParams);
  1258. }
  1259. else
  1260. {
  1261. currentShader.setShader (target, quadQueue, programs->linearGradient1Masked);
  1262. gradientParams = &(programs->linearGradient1Masked.gradientParams);
  1263. maskParams = &programs->linearGradient1Masked.maskParams;
  1264. }
  1265. grad = delta.x / delta.y;
  1266. length = (p2.y - grad * p2.x) - (p1.y - grad * p1.x);
  1267. }
  1268. else
  1269. {
  1270. if (maskArea == nullptr)
  1271. {
  1272. currentShader.setShader (target, quadQueue, programs->linearGradient2);
  1273. gradientParams = &(programs->linearGradient2.gradientParams);
  1274. }
  1275. else
  1276. {
  1277. currentShader.setShader (target, quadQueue, programs->linearGradient2Masked);
  1278. gradientParams = &(programs->linearGradient2Masked.gradientParams);
  1279. maskParams = &programs->linearGradient2Masked.maskParams;
  1280. }
  1281. grad = delta.y / delta.x;
  1282. length = (p2.x - grad * p2.y) - (p1.x - grad * p1.y);
  1283. }
  1284. gradientParams->gradientInfo.set (p1.x, p1.y, grad, length);
  1285. }
  1286. if (maskParams != nullptr)
  1287. {
  1288. maskParams->maskTexture.set ((GLint) 1);
  1289. maskParams->setBounds (*maskArea, target);
  1290. }
  1291. }
  1292. void setShaderForTiledImageFill (const OpenGLTextureFromImage& image, const AffineTransform& transform,
  1293. const int maskTextureID, const Rectangle<int>* const maskArea, const bool clampTiledImages)
  1294. {
  1295. blendMode.setPremultipliedBlendingMode (quadQueue);
  1296. currentColour.setSolidColour();
  1297. ShaderPrograms* const programs = currentShader.programs;
  1298. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1299. const ShaderPrograms::ImageParams* imageParams;
  1300. if (maskArea != nullptr)
  1301. {
  1302. activeTextures.setTexturesEnabled (quadQueue, 3);
  1303. activeTextures.setActiveTexture (1);
  1304. activeTextures.bindTexture (maskTextureID);
  1305. activeTextures.setActiveTexture (0);
  1306. activeTextures.bindTexture (image.textureID);
  1307. if (clampTiledImages)
  1308. {
  1309. currentShader.setShader (target, quadQueue, programs->imageMasked);
  1310. imageParams = &programs->imageMasked.imageParams;
  1311. maskParams = &programs->imageMasked.maskParams;
  1312. }
  1313. else
  1314. {
  1315. currentShader.setShader (target, quadQueue, programs->tiledImageMasked);
  1316. imageParams = &programs->tiledImageMasked.imageParams;
  1317. maskParams = &programs->tiledImageMasked.maskParams;
  1318. }
  1319. }
  1320. else
  1321. {
  1322. activeTextures.setSingleTextureMode (quadQueue);
  1323. activeTextures.bindTexture (image.textureID);
  1324. if (clampTiledImages)
  1325. {
  1326. currentShader.setShader (target, quadQueue, programs->image);
  1327. imageParams = &programs->image.imageParams;
  1328. }
  1329. else
  1330. {
  1331. currentShader.setShader (target, quadQueue, programs->tiledImage);
  1332. imageParams = &programs->tiledImage.imageParams;
  1333. }
  1334. }
  1335. imageParams->setMatrix (transform, image, (float) target.x, (float) target.y, (float) target.height);
  1336. if (maskParams != nullptr)
  1337. {
  1338. maskParams->maskTexture.set ((GLint) 1);
  1339. maskParams->setBounds (*maskArea, target);
  1340. }
  1341. }
  1342. #endif
  1343. OpenGLTarget target;
  1344. StateHelpers::CurrentColour currentColour;
  1345. StateHelpers::BlendingMode blendMode;
  1346. StateHelpers::QuadQueue quadQueue;
  1347. StateHelpers::ActiveTextures activeTextures;
  1348. StateHelpers::TextureCache textureCache;
  1349. #if JUCE_USE_OPENGL_SHADERS
  1350. StateHelpers::CurrentShader currentShader;
  1351. #endif
  1352. private:
  1353. GLuint previousFrameBufferTarget;
  1354. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1355. void resetMultiTextureMode (int index, const bool forRGBTextures)
  1356. {
  1357. activeTextures.setActiveTexture (index);
  1358. glDisable (GL_TEXTURE_2D);
  1359. glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  1360. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
  1361. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
  1362. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
  1363. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
  1364. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, forRGBTextures ? GL_SRC_COLOR : GL_SRC_ALPHA);
  1365. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
  1366. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
  1367. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
  1368. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
  1369. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
  1370. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1371. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1372. }
  1373. void resetMultiTextureModes (const bool forRGBTextures)
  1374. {
  1375. resetMultiTextureMode (2, forRGBTextures);
  1376. resetMultiTextureMode (1, forRGBTextures);
  1377. resetMultiTextureMode (0, forRGBTextures);
  1378. }
  1379. void fillWithLinearGradient (const Rectangle<int>& rect, const ColourGradient& grad, const AffineTransform& transform,
  1380. const PositionedTexture* mask1, const PositionedTexture* mask2)
  1381. {
  1382. const Point<float> p1 (grad.point1.transformedBy (transform));
  1383. const Point<float> p2 (grad.point2.transformedBy (transform));
  1384. const Point<float> p3 (Point<float> (grad.point1.x - (grad.point2.y - grad.point1.y) / StateHelpers::TextureCache::gradientTextureSize,
  1385. grad.point1.y + (grad.point2.x - grad.point1.x) / StateHelpers::TextureCache::gradientTextureSize)
  1386. .transformedBy (transform));
  1387. const AffineTransform textureTransform (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  1388. p2.x, p2.y, 1.0f, 0.0f,
  1389. p3.x, p3.y, 0.0f, 1.0f));
  1390. const GLfloat l = (GLfloat) rect.getX();
  1391. const GLfloat r = (GLfloat) rect.getRight();
  1392. const GLfloat t = (GLfloat) rect.getY();
  1393. const GLfloat b = (GLfloat) rect.getBottom();
  1394. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  1395. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  1396. textureTransform.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1397. textureTransform.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1398. GLfloat textureCoords1[8], textureCoords2[8];
  1399. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &rect);
  1400. TemporaryColourModulationMode tmm;
  1401. textureCache.bindTextureForGradient (activeTextures, grad);
  1402. currentColour.setSolidColour();
  1403. drawTriangleStrip (vertices, textureCoords, 4);
  1404. }
  1405. void fillWithRadialGradient (const Rectangle<int>& rect, const ColourGradient& grad, const AffineTransform& transform,
  1406. const PositionedTexture* mask1, const PositionedTexture* mask2)
  1407. {
  1408. const Point<float> centre (grad.point1.transformedBy (transform));
  1409. const float screenRadius = centre.getDistanceFrom (rect.getCentre().toFloat())
  1410. + Point<int> (rect.getWidth() / 2,
  1411. rect.getHeight() / 2).getDistanceFromOrigin()
  1412. + 8.0f;
  1413. const AffineTransform inverse (transform.inverted());
  1414. const float sourceRadius = jmax (Point<float> (screenRadius, 0.0f).transformedBy (inverse).getDistanceFromOrigin(),
  1415. Point<float> (0.0f, screenRadius).transformedBy (inverse).getDistanceFromOrigin());
  1416. const int numDivisions = 90;
  1417. GLfloat vertices [4 + numDivisions * 2];
  1418. GLfloat textureCoords1 [4 + numDivisions * 2];
  1419. GLfloat textureCoords2 [4 + numDivisions * 2];
  1420. GLfloat textureCoords3 [4 + numDivisions * 2];
  1421. {
  1422. GLfloat* t = textureCoords1;
  1423. *t++ = 0.0f;
  1424. *t++ = 0.0f;
  1425. const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2);
  1426. for (int i = numDivisions + 1; --i >= 0;)
  1427. {
  1428. *t++ = texturePos;
  1429. *t++ = 0.0f;
  1430. }
  1431. }
  1432. {
  1433. GLfloat* v = vertices;
  1434. *v++ = centre.x;
  1435. *v++ = centre.y;
  1436. const Point<float> first (grad.point1.translated (0, -sourceRadius)
  1437. .transformedBy (transform));
  1438. *v++ = first.x;
  1439. *v++ = first.y;
  1440. for (int i = 1; i < numDivisions; ++i)
  1441. {
  1442. const float angle = i * (float_Pi * 2.0f / numDivisions);
  1443. const Point<float> p (grad.point1.translated (std::sin (angle) * sourceRadius,
  1444. std::cos (angle) * -sourceRadius)
  1445. .transformedBy (transform));
  1446. *v++ = p.x;
  1447. *v++ = p.y;
  1448. }
  1449. *v++ = first.x;
  1450. *v++ = first.y;
  1451. }
  1452. prepareMasks (mask1, mask2, textureCoords2, textureCoords3, nullptr);
  1453. if (mask1 != nullptr)
  1454. {
  1455. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  1456. mask1->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords2[i], textureCoords2[i + 1]);
  1457. if (mask2 != nullptr)
  1458. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  1459. mask2->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords3[i], textureCoords3[i + 1]);
  1460. }
  1461. scissor (rect);
  1462. textureCache.bindTextureForGradient (activeTextures, grad);
  1463. currentColour.setSolidColour();
  1464. TemporaryColourModulationMode tmm;
  1465. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1466. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords1);
  1467. glDrawArrays (GL_TRIANGLE_FAN, 0, numDivisions + 2);
  1468. disableScissor();
  1469. }
  1470. struct TemporaryColourModulationMode
  1471. {
  1472. TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); }
  1473. ~TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); }
  1474. };
  1475. #endif
  1476. };
  1477. //==============================================================================
  1478. class ClipRegion_Mask;
  1479. //==============================================================================
  1480. class ClipRegionBase : public SingleThreadedReferenceCountedObject
  1481. {
  1482. public:
  1483. ClipRegionBase (OpenGLGraphicsContext::GLState& state_) noexcept : state (state_) {}
  1484. virtual ~ClipRegionBase() {}
  1485. typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
  1486. virtual Ptr clone() const = 0;
  1487. virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
  1488. virtual Ptr clipToRectangleList (const RectangleList&) = 0;
  1489. virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
  1490. virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
  1491. virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
  1492. virtual Ptr clipToTexture (const PositionedTexture&) = 0;
  1493. virtual Rectangle<int> getClipBounds() const = 0;
  1494. virtual void fillRect (const Rectangle<int>& area, const FillType&, bool replaceContents) = 0;
  1495. virtual void fillRect (const Rectangle<float>& area, const FillType&) = 0;
  1496. virtual void fillEdgeTable (EdgeTable& et, const FillType& fill) = 0;
  1497. virtual void drawImage (const Image&, const AffineTransform&, float alpha,
  1498. const Rectangle<int>& clip, EdgeTable* mask) = 0;
  1499. OpenGLGraphicsContext::GLState& state;
  1500. private:
  1501. JUCE_DECLARE_NON_COPYABLE (ClipRegionBase);
  1502. };
  1503. //==============================================================================
  1504. class ClipRegion_RectangleListBase : public ClipRegionBase
  1505. {
  1506. public:
  1507. ClipRegion_RectangleListBase (OpenGLGraphicsContext::GLState& state_, const Rectangle<int>& r) noexcept
  1508. : ClipRegionBase (state_), clip (r)
  1509. {}
  1510. ClipRegion_RectangleListBase (OpenGLGraphicsContext::GLState& state_, const RectangleList& r) noexcept
  1511. : ClipRegionBase (state_), clip (r)
  1512. {}
  1513. Rectangle<int> getClipBounds() const { return clip.getBounds(); }
  1514. Ptr clipToRectangle (const Rectangle<int>& r) { return clip.clipTo (r) ? this : nullptr; }
  1515. Ptr clipToRectangleList (const RectangleList& r) { return clip.clipTo (r) ? this : nullptr; }
  1516. Ptr excludeClipRectangle (const Rectangle<int>& r) { clip.subtract (r); return clip.isEmpty() ? nullptr : this; }
  1517. protected:
  1518. RectangleList clip;
  1519. };
  1520. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1521. //==============================================================================
  1522. class ClipRegion_Mask : public ClipRegionBase
  1523. {
  1524. public:
  1525. ClipRegion_Mask (const ClipRegion_Mask& other)
  1526. : ClipRegionBase (other.state),
  1527. clip (other.clip),
  1528. maskOrigin (other.clip.getPosition())
  1529. {
  1530. TargetSaver ts;
  1531. clearShader();
  1532. state.quadQueue.flush();
  1533. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1534. state.activeTextures.clear();
  1535. mask.initialise (clip.getWidth(), clip.getHeight());
  1536. OpenGLTarget m (mask, maskOrigin);
  1537. m.makeActiveFor2D();
  1538. state.blendMode.disableBlend (state.quadQueue);
  1539. state.currentColour.setSolidColour();
  1540. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1541. OpenGLHelpers::drawTextureQuad (other.mask.getTextureID(), other.getMaskArea());
  1542. }
  1543. ClipRegion_Mask (OpenGLGraphicsContext::GLState& state_, const RectangleList& r)
  1544. : ClipRegionBase (state_),
  1545. clip (r.getBounds()),
  1546. maskOrigin (clip.getPosition())
  1547. {
  1548. TargetSaver ts;
  1549. initialiseClear();
  1550. state.blendMode.disableBlend (state.quadQueue);
  1551. state.fillRectangleList (r, PixelARGB (0xffffffff));
  1552. state.quadQueue.flush();
  1553. }
  1554. Ptr clone() const { return new ClipRegion_Mask (*this); }
  1555. Rectangle<int> getClipBounds() const { return clip; }
  1556. Ptr clipToRectangle (const Rectangle<int>& r)
  1557. {
  1558. clip = clip.getIntersection (r);
  1559. return clip.isEmpty() ? nullptr : this;
  1560. }
  1561. Ptr clipToRectangleList (const RectangleList& r)
  1562. {
  1563. clip = clip.getIntersection (r.getBounds());
  1564. if (clip.isEmpty())
  1565. return nullptr;
  1566. RectangleList excluded (clip);
  1567. if (excluded.subtract (r))
  1568. {
  1569. if (excluded.getNumRectangles() == 1)
  1570. return excludeClipRectangle (excluded.getRectangle (0));
  1571. TargetSaver ts;
  1572. makeMaskActive();
  1573. state.blendMode.disableBlend (state.quadQueue);
  1574. state.fillRectangleList (excluded, PixelARGB (0));
  1575. state.quadQueue.flush();
  1576. }
  1577. return this;
  1578. }
  1579. Ptr excludeClipRectangle (const Rectangle<int>& r)
  1580. {
  1581. if (r.contains (clip))
  1582. return nullptr;
  1583. TargetSaver ts;
  1584. makeMaskActive();
  1585. state.activeTextures.setTexturesEnabled (state.quadQueue, 0);
  1586. state.blendMode.disableBlend (state.quadQueue);
  1587. state.currentColour.setColour (PixelARGB (0));
  1588. OpenGLHelpers::fillRect (r);
  1589. return this;
  1590. }
  1591. Ptr clipToPath (const Path& p, const AffineTransform& t)
  1592. {
  1593. EdgeTable et (clip, p, t);
  1594. if (! et.isEmpty())
  1595. {
  1596. OpenGLTexture texture;
  1597. PositionedTexture pt (texture, et, et.getMaximumBounds());
  1598. return clipToTexture (pt);
  1599. }
  1600. return nullptr;
  1601. }
  1602. Ptr clipToTexture (const PositionedTexture& pt)
  1603. {
  1604. clip = clip.getIntersection (pt.clip);
  1605. if (clip.isEmpty())
  1606. return nullptr;
  1607. TargetSaver ts;
  1608. makeMaskActive();
  1609. state.blendMode.setBlendFunc (state.quadQueue, GL_ZERO, GL_SRC_ALPHA);
  1610. state.currentColour.setSolidColour();
  1611. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1612. OpenGLHelpers::drawTextureQuad (pt.textureID, pt.area);
  1613. return this;
  1614. }
  1615. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  1616. {
  1617. TargetSaver ts;
  1618. makeMaskActive();
  1619. state.blendMode.setBlendFunc (state.quadQueue, GL_ZERO, GL_SRC_ALPHA);
  1620. state.currentColour.setSolidColour();
  1621. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1622. state.activeTextures.bindTexture (image.textureID);
  1623. const GLfloat l = (GLfloat) maskOrigin.x;
  1624. const GLfloat t = (GLfloat) maskOrigin.y;
  1625. const GLfloat r = (GLfloat) (maskOrigin.x + mask.getWidth());
  1626. const GLfloat b = (GLfloat) (maskOrigin.y + mask.getHeight());
  1627. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  1628. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  1629. const AffineTransform inv (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  1630. image.fullHeightProportion / image.imageHeight));
  1631. inv.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1632. inv.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1633. textureCoords[1] = 1.0f - textureCoords[1];
  1634. textureCoords[3] = 1.0f - textureCoords[3];
  1635. textureCoords[5] = 1.0f - textureCoords[5];
  1636. textureCoords[7] = 1.0f - textureCoords[7];
  1637. state.drawTriangleStrip (vertices, textureCoords, 4);
  1638. return this;
  1639. }
  1640. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1641. {
  1642. jassert (! replaceContents);
  1643. const Rectangle<int> r (clip.getIntersection (area));
  1644. if (! r.isEmpty())
  1645. fillRectInternal (r, fill, false);
  1646. }
  1647. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1648. {
  1649. if (fill.isColour())
  1650. {
  1651. FloatRectangleRenderer frr (*this, fill);
  1652. RenderingHelpers::FloatRectangleRasterisingInfo (area).iterate (frr);
  1653. }
  1654. else
  1655. {
  1656. EdgeTable et (area);
  1657. fillEdgeTable (et, fill);
  1658. }
  1659. }
  1660. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1661. {
  1662. const Rectangle<int> r (et.getMaximumBounds().getIntersection (clip));
  1663. if (! r.isEmpty())
  1664. {
  1665. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures, r.getWidth(), r.getHeight());
  1666. PositionedTexture pt1 (*texture, et, r);
  1667. PositionedTexture pt2 (mask.getTextureID(), getMaskArea(), r);
  1668. state.fillTexture (r, fill, &pt2, &pt1, false);
  1669. state.textureCache.releaseTexture (state.activeTextures, texture);
  1670. }
  1671. }
  1672. void fillRectInternal (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1673. {
  1674. PositionedTexture pt (mask.getTextureID(), getMaskArea(), area);
  1675. state.fillTexture (area, fill, &pt, nullptr, replaceContents);
  1676. }
  1677. void drawImage (const Image& image, const AffineTransform& transform,
  1678. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  1679. {
  1680. const OpenGLTextureFromImage source (image);
  1681. const Rectangle<int> bufferArea (clipArea.getIntersection (clip));
  1682. if (! bufferArea.isEmpty())
  1683. {
  1684. PositionedTexture pt (mask.getTextureID(), getMaskArea(), bufferArea);
  1685. if (et != nullptr)
  1686. {
  1687. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures, clipArea.getWidth(), clipArea.getHeight());
  1688. PositionedTexture mask1 (*texture, *et, clipArea);
  1689. state.renderImage (source, bufferArea, transform, alpha, &pt, &mask1, false, false);
  1690. state.textureCache.releaseTexture (state.activeTextures, texture);
  1691. }
  1692. else
  1693. {
  1694. state.renderImage (source, bufferArea, transform, alpha, &pt, nullptr, false, false);
  1695. }
  1696. }
  1697. }
  1698. protected:
  1699. OpenGLFrameBuffer mask;
  1700. Rectangle<int> clip;
  1701. Point<int> maskOrigin;
  1702. Rectangle<int> getMaskArea() const noexcept { return Rectangle<int> (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()); }
  1703. void prepareFor2D() const { OpenGLTarget::applyFlippedMatrix (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()); }
  1704. void clearShader() const
  1705. {
  1706. #if JUCE_USE_OPENGL_SHADERS
  1707. state.currentShader.clearShader (state.quadQueue);
  1708. #endif
  1709. }
  1710. void makeMaskActive()
  1711. {
  1712. clearShader();
  1713. state.quadQueue.flush();
  1714. const bool b = mask.makeCurrentRenderingTarget();
  1715. (void) b; jassert (b);
  1716. prepareFor2D();
  1717. }
  1718. void initialiseClear()
  1719. {
  1720. clearShader();
  1721. state.quadQueue.flush();
  1722. jassert (! clip.isEmpty());
  1723. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1724. state.activeTextures.clear();
  1725. mask.initialise (clip.getWidth(), clip.getHeight());
  1726. mask.makeCurrentAndClear();
  1727. state.activeTextures.setTexturesEnabled (state.quadQueue, 0);
  1728. state.blendMode.disableBlend (state.quadQueue);
  1729. prepareFor2D();
  1730. }
  1731. struct TargetSaver
  1732. {
  1733. TargetSaver()
  1734. : oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  1735. {
  1736. glGetIntegerv (GL_VIEWPORT, oldViewport);
  1737. glPushMatrix();
  1738. }
  1739. ~TargetSaver()
  1740. {
  1741. OpenGLFrameBuffer::setCurrentFrameBufferTarget (oldFramebuffer);
  1742. glPopMatrix();
  1743. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  1744. }
  1745. private:
  1746. GLuint oldFramebuffer;
  1747. GLint oldViewport[4];
  1748. };
  1749. struct FloatRectangleRenderer
  1750. {
  1751. FloatRectangleRenderer (ClipRegion_Mask& owner_, const FillType& fill_) noexcept
  1752. : owner (owner_), fill (fill_), originalColour (fill_.colour)
  1753. {}
  1754. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  1755. {
  1756. if (w > 0 && h > 0)
  1757. {
  1758. fill.colour = originalColour.withMultipliedAlpha (alpha / 255.0f);
  1759. owner.fillRect (Rectangle<int> (x, y, w, h), fill, false);
  1760. }
  1761. }
  1762. private:
  1763. ClipRegion_Mask& owner;
  1764. FillType fill;
  1765. const Colour originalColour;
  1766. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  1767. };
  1768. ClipRegion_Mask& operator= (const ClipRegion_Mask&);
  1769. };
  1770. //==============================================================================
  1771. class ClipRegion_RectangleList : public ClipRegion_RectangleListBase
  1772. {
  1773. public:
  1774. ClipRegion_RectangleList (OpenGLGraphicsContext::GLState& state_, const Rectangle<int>& r) noexcept
  1775. : ClipRegion_RectangleListBase (state_, r)
  1776. {}
  1777. ClipRegion_RectangleList (OpenGLGraphicsContext::GLState& state_, const RectangleList& r) noexcept
  1778. : ClipRegion_RectangleListBase (state_, r)
  1779. {}
  1780. Ptr clone() const { return new ClipRegion_RectangleList (state, clip); }
  1781. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  1782. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  1783. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  1784. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1785. {
  1786. if (fill.isColour())
  1787. {
  1788. state.activeTextures.setTexturesEnabled (state.quadQueue, 0);
  1789. state.blendMode.setBlendMode (state.quadQueue, replaceContents || fill.colour.isOpaque());
  1790. state.fillRectangleList (clip, area, fill.colour.getPixelARGB());
  1791. }
  1792. else
  1793. {
  1794. for (RectangleList::Iterator i (clip); i.next();)
  1795. {
  1796. const Rectangle<int> r (i.getRectangle()->getIntersection (area));
  1797. if (! r.isEmpty())
  1798. state.fillTexture (r, fill, nullptr, nullptr, replaceContents);
  1799. }
  1800. }
  1801. }
  1802. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1803. {
  1804. if (fill.isColour())
  1805. {
  1806. state.activeTextures.setTexturesEnabled (state.quadQueue, 0);
  1807. state.blendMode.setPremultipliedBlendingMode (state.quadQueue);
  1808. for (RectangleList::Iterator i (clip); i.next();)
  1809. {
  1810. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  1811. if (! r.isEmpty())
  1812. state.fillRect (r, fill.colour.getPixelARGB());
  1813. }
  1814. }
  1815. else
  1816. {
  1817. EdgeTable et (area);
  1818. fillEdgeTable (et, fill);
  1819. }
  1820. }
  1821. void drawImage (const Image& image, const AffineTransform& transform,
  1822. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  1823. {
  1824. const OpenGLTextureFromImage source (image);
  1825. for (RectangleList::Iterator i (clip); i.next();)
  1826. {
  1827. const Rectangle<int> bufferArea (i.getRectangle()->getIntersection (clipArea));
  1828. if (! bufferArea.isEmpty())
  1829. {
  1830. if (et != nullptr)
  1831. {
  1832. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures, clipArea.getWidth(), clipArea.getHeight());
  1833. PositionedTexture mask (*texture, *et, clipArea);
  1834. state.renderImage (source, bufferArea, transform, alpha, &mask, nullptr, false, false);
  1835. state.textureCache.releaseTexture (state.activeTextures, texture);
  1836. }
  1837. else
  1838. {
  1839. state.renderImage (source, bufferArea, transform, alpha, nullptr, nullptr, false, false);
  1840. }
  1841. }
  1842. }
  1843. }
  1844. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1845. {
  1846. if (fill.isColour())
  1847. {
  1848. state.blendMode.setPremultipliedBlendingMode (state.quadQueue);
  1849. if (! clip.containsRectangle (et.getMaximumBounds()))
  1850. et.clipToEdgeTable (EdgeTable (clip));
  1851. state.fillEdgeTable (et, fill.colour.getPixelARGB());
  1852. }
  1853. else
  1854. {
  1855. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures,
  1856. clip.getBounds().getWidth(), clip.getBounds().getHeight());
  1857. PositionedTexture pt (*texture, et, clip.getBounds());
  1858. for (RectangleList::Iterator i (clip); i.next();)
  1859. {
  1860. const Rectangle<int> r (i.getRectangle()->getIntersection (pt.clip));
  1861. if (! r.isEmpty())
  1862. state.fillTexture (r, fill, &pt, nullptr, false);
  1863. }
  1864. state.textureCache.releaseTexture (state.activeTextures, texture);
  1865. }
  1866. }
  1867. protected:
  1868. Ptr toMask() const { return new ClipRegion_Mask (state, clip); }
  1869. JUCE_DECLARE_NON_COPYABLE (ClipRegion_RectangleList);
  1870. };
  1871. #endif
  1872. //==============================================================================
  1873. #if JUCE_USE_OPENGL_SHADERS
  1874. class ClipRegion_Mask_Shader : public ClipRegionBase
  1875. {
  1876. public:
  1877. ClipRegion_Mask_Shader (const ClipRegion_Mask_Shader& other)
  1878. : ClipRegionBase (other.state),
  1879. clip (other.clip),
  1880. maskArea (other.clip)
  1881. {
  1882. TargetSaver ts;
  1883. state.currentShader.clearShader (state.quadQueue);
  1884. state.quadQueue.flush();
  1885. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1886. state.activeTextures.clear();
  1887. mask.initialise (maskArea.getWidth(), maskArea.getHeight());
  1888. makeActive();
  1889. state.blendMode.disableBlend (state.quadQueue);
  1890. state.currentColour.setSolidColour();
  1891. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1892. state.activeTextures.bindTexture (other.mask.getTextureID());
  1893. state.currentShader.setShader (maskArea, state.quadQueue, state.currentShader.programs->copyTexture);
  1894. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  1895. state.currentShader.programs->copyTexture.imageParams
  1896. .setMatrix (AffineTransform::translation ((float) other.maskArea.getX(), (float) other.maskArea.getY()),
  1897. other.maskArea.getWidth(), other.maskArea.getHeight(), 1.0f, 1.0f,
  1898. (float) maskArea.getX(), (float) maskArea.getY(), (float) maskArea.getHeight());
  1899. state.fillRect (clip, PixelARGB (0xffffffff));
  1900. state.quadQueue.flush();
  1901. }
  1902. ClipRegion_Mask_Shader (OpenGLGraphicsContext::GLState& state_, const RectangleList& r)
  1903. : ClipRegionBase (state_),
  1904. clip (r.getBounds()),
  1905. maskArea (clip)
  1906. {
  1907. TargetSaver ts;
  1908. state.currentShader.clearShader (state.quadQueue);
  1909. state.quadQueue.flush();
  1910. state.activeTextures.clear();
  1911. mask.initialise (maskArea.getWidth(), maskArea.getHeight());
  1912. mask.makeCurrentAndClear();
  1913. makeActive();
  1914. state.blendMode.setBlendMode (state.quadQueue, true);
  1915. state.currentShader.setShader (maskArea, state.quadQueue, state.currentShader.programs->solidColourProgram);
  1916. state.fillRectangleList (r, PixelARGB (0xffffffff));
  1917. state.quadQueue.flush();
  1918. }
  1919. Ptr clone() const { return new ClipRegion_Mask_Shader (*this); }
  1920. Rectangle<int> getClipBounds() const { return clip; }
  1921. Ptr clipToRectangle (const Rectangle<int>& r)
  1922. {
  1923. clip = clip.getIntersection (r);
  1924. return clip.isEmpty() ? nullptr : this;
  1925. }
  1926. Ptr clipToRectangleList (const RectangleList& r)
  1927. {
  1928. clip = clip.getIntersection (r.getBounds());
  1929. if (clip.isEmpty())
  1930. return nullptr;
  1931. RectangleList excluded (clip);
  1932. if (excluded.subtract (r))
  1933. {
  1934. if (excluded.getNumRectangles() == 1)
  1935. return excludeClipRectangle (excluded.getRectangle (0));
  1936. TargetSaver ts;
  1937. makeActive();
  1938. state.blendMode.setBlendMode (state.quadQueue, true);
  1939. state.currentShader.setShader (maskArea, state.quadQueue, state.currentShader.programs->solidColourProgram);
  1940. state.fillRectangleList (excluded, PixelARGB (0));
  1941. state.quadQueue.flush();
  1942. }
  1943. return this;
  1944. }
  1945. Ptr excludeClipRectangle (const Rectangle<int>& r)
  1946. {
  1947. if (r.contains (clip))
  1948. return nullptr;
  1949. TargetSaver ts;
  1950. makeActive();
  1951. state.blendMode.setBlendMode (state.quadQueue, true);
  1952. state.currentShader.setShader (maskArea, state.quadQueue, state.currentShader.programs->solidColourProgram);
  1953. state.fillRect (r, PixelARGB (0));
  1954. state.quadQueue.flush();
  1955. return this;
  1956. }
  1957. Ptr clipToPath (const Path& p, const AffineTransform& t)
  1958. {
  1959. EdgeTable et (clip, p, t);
  1960. if (! et.isEmpty())
  1961. {
  1962. TargetSaver ts;
  1963. state.currentShader.clearShader (state.quadQueue);
  1964. state.quadQueue.flush();
  1965. state.activeTextures.clear();
  1966. OpenGLTexture texture;
  1967. PositionedTexture pt (texture, et, clip);
  1968. return clipToTexture (pt);
  1969. }
  1970. return nullptr;
  1971. }
  1972. Ptr clipToTexture (const PositionedTexture& pt)
  1973. {
  1974. clip = clip.getIntersection (pt.clip);
  1975. if (clip.isEmpty())
  1976. return nullptr;
  1977. TargetSaver ts;
  1978. makeActive();
  1979. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1980. state.activeTextures.bindTexture (pt.textureID);
  1981. state.currentShader.setShader (maskArea, state.quadQueue, state.currentShader.programs->maskTexture);
  1982. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  1983. state.currentShader.programs->maskTexture.imageParams
  1984. .setMatrix (AffineTransform::translation ((float) pt.area.getX(), (float) pt.area.getY()),
  1985. pt.area.getWidth(), pt.area.getHeight(), 1.0f, 1.0f,
  1986. (float) maskArea.getX(), (float) maskArea.getY(), (float) maskArea.getHeight());
  1987. state.blendMode.setBlendFunc (state.quadQueue, GL_ZERO, GL_SRC_ALPHA);
  1988. state.fillRect (clip, PixelARGB (0xffffffff));
  1989. state.quadQueue.flush();
  1990. return this;
  1991. }
  1992. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  1993. {
  1994. TargetSaver ts;
  1995. makeActive();
  1996. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1997. state.activeTextures.bindTexture (image.textureID);
  1998. state.currentShader.setShader (maskArea, state.quadQueue, state.currentShader.programs->maskTexture);
  1999. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  2000. state.currentShader.programs->maskTexture.imageParams
  2001. .setMatrix (transform, image, (float) maskArea.getX(), (float) maskArea.getY(), (float) maskArea.getHeight());
  2002. state.fillRect (clip, PixelARGB (0xffffffff));
  2003. state.quadQueue.flush();
  2004. return this;
  2005. }
  2006. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  2007. {
  2008. jassert (! replaceContents);
  2009. const Rectangle<int> r (clip.getIntersection (area));
  2010. if (! r.isEmpty())
  2011. {
  2012. ShaderFillOperation fillOp (*this, fill, false);
  2013. state.fillRect (r, fill.colour.getPixelARGB());
  2014. }
  2015. }
  2016. void fillRect (const Rectangle<float>& area, const FillType& fill)
  2017. {
  2018. ShaderFillOperation fillOp (*this, fill, false);
  2019. FloatRectangleRenderer frr (*this, fill);
  2020. RenderingHelpers::FloatRectangleRasterisingInfo (area).iterate (frr);
  2021. }
  2022. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  2023. {
  2024. if (et.getMaximumBounds().intersects (clip))
  2025. {
  2026. if (! clip.contains (et.getMaximumBounds()))
  2027. et.clipToRectangle (clip);
  2028. ShaderFillOperation fillOp (*this, fill, false);
  2029. state.fillEdgeTable (et, fill.colour.getPixelARGB());
  2030. }
  2031. }
  2032. void drawImage (const Image& image, const AffineTransform& transform,
  2033. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  2034. {
  2035. const Rectangle<int> r (clip.getIntersection (clipArea));
  2036. if (! r.isEmpty())
  2037. {
  2038. const PixelARGB colour (Colours::white.withAlpha (alpha).getPixelARGB());
  2039. ShaderFillOperation fillOp (*this, FillType (image, transform), true);
  2040. if (et != nullptr)
  2041. {
  2042. et->clipToRectangle (r);
  2043. if (! et->isEmpty())
  2044. state.fillEdgeTable (*et, colour);
  2045. }
  2046. else
  2047. {
  2048. state.fillRect (r, colour);
  2049. }
  2050. }
  2051. state.currentShader.clearShader (state.quadQueue);
  2052. }
  2053. private:
  2054. OpenGLFrameBuffer mask;
  2055. Rectangle<int> clip, maskArea;
  2056. struct ShaderFillOperation
  2057. {
  2058. ShaderFillOperation (const ClipRegion_Mask_Shader& clip, const FillType& fill, const bool clampTiledImages)
  2059. : state (clip.state)
  2060. {
  2061. const GLuint maskTextureID = clip.mask.getTextureID();
  2062. if (fill.isColour())
  2063. {
  2064. state.currentColour.setSolidColour();
  2065. state.blendMode.setPremultipliedBlendingMode (state.quadQueue);
  2066. state.activeTextures.setSingleTextureMode (state.quadQueue);
  2067. state.activeTextures.bindTexture (maskTextureID);
  2068. state.currentShader.setShader (state.target, state.quadQueue, state.currentShader.programs->solidColourMasked);
  2069. state.currentShader.programs->solidColourMasked.maskParams.setBounds (clip.maskArea, state.target);
  2070. }
  2071. else if (fill.isGradient())
  2072. {
  2073. state.setShaderForGradientFill (*fill.gradient, fill.transform, maskTextureID, &clip.maskArea);
  2074. }
  2075. else
  2076. {
  2077. jassert (fill.isTiledImage());
  2078. image = new OpenGLTextureFromImage (fill.image);
  2079. state.setShaderForTiledImageFill (*image, fill.transform, maskTextureID, &clip.maskArea, clampTiledImages);
  2080. }
  2081. }
  2082. ~ShaderFillOperation()
  2083. {
  2084. state.quadQueue.flush();
  2085. }
  2086. OpenGLGraphicsContext::GLState& state;
  2087. ScopedPointer<OpenGLTextureFromImage> image;
  2088. JUCE_DECLARE_NON_COPYABLE (ShaderFillOperation);
  2089. };
  2090. struct TargetSaver
  2091. {
  2092. TargetSaver()
  2093. : oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  2094. {
  2095. glGetIntegerv (GL_VIEWPORT, oldViewport);
  2096. }
  2097. ~TargetSaver()
  2098. {
  2099. OpenGLFrameBuffer::setCurrentFrameBufferTarget (oldFramebuffer);
  2100. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  2101. }
  2102. private:
  2103. GLuint oldFramebuffer;
  2104. GLint oldViewport[4];
  2105. };
  2106. void makeActive()
  2107. {
  2108. state.quadQueue.flush();
  2109. state.activeTextures.clear();
  2110. mask.makeCurrentRenderingTarget();
  2111. state.currentColour.setSolidColour();
  2112. glViewport (0, 0, maskArea.getWidth(), maskArea.getHeight());
  2113. }
  2114. struct FloatRectangleRenderer
  2115. {
  2116. FloatRectangleRenderer (ClipRegion_Mask_Shader& owner_, const FillType& fill_) noexcept
  2117. : owner (owner_), originalColour (fill_.colour.getPixelARGB())
  2118. {}
  2119. void operator() (int x, int y, int w, int h, const int alpha) noexcept
  2120. {
  2121. if (owner.clip.intersectRectangle (x, y, w, h))
  2122. {
  2123. PixelARGB col (originalColour);
  2124. col.multiplyAlpha (alpha);
  2125. owner.state.fillRect (Rectangle<int> (x, y, w, h), col);
  2126. }
  2127. }
  2128. private:
  2129. ClipRegion_Mask_Shader& owner;
  2130. const PixelARGB originalColour;
  2131. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  2132. };
  2133. ClipRegion_Mask_Shader& operator= (const ClipRegion_Mask_Shader&);
  2134. };
  2135. //==============================================================================
  2136. class ClipRegion_RectangleList_Shaders : public ClipRegion_RectangleListBase
  2137. {
  2138. public:
  2139. ClipRegion_RectangleList_Shaders (OpenGLGraphicsContext::GLState& state_, const Rectangle<int>& r) noexcept
  2140. : ClipRegion_RectangleListBase (state_, r)
  2141. {}
  2142. ClipRegion_RectangleList_Shaders (OpenGLGraphicsContext::GLState& state_, const RectangleList& r) noexcept
  2143. : ClipRegion_RectangleListBase (state_, r)
  2144. {}
  2145. Ptr clone() const { return new ClipRegion_RectangleList_Shaders (state, clip); }
  2146. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  2147. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  2148. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  2149. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  2150. {
  2151. ShaderFillOperation fillOp (*this, fill, replaceContents || fill.colour.isOpaque(), false);
  2152. state.fillRectangleList (clip, area, fill.colour.getPixelARGB());
  2153. }
  2154. void fillRect (const Rectangle<float>& area, const FillType& fill)
  2155. {
  2156. ShaderFillOperation fillOp (*this, fill, false, false);
  2157. for (RectangleList::Iterator i (clip); i.next();)
  2158. {
  2159. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  2160. if (! r.isEmpty())
  2161. state.fillRect (r, fill.colour.getPixelARGB());
  2162. }
  2163. }
  2164. void drawImage (const Image& image, const AffineTransform& transform,
  2165. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  2166. {
  2167. FillType fill (image, transform);
  2168. const PixelARGB colour (Colours::white.withAlpha (alpha).getPixelARGB());
  2169. ShaderFillOperation fillOp (*this, fill, false, true);
  2170. if (et != nullptr)
  2171. {
  2172. if (! clip.containsRectangle (et->getMaximumBounds()))
  2173. et->clipToEdgeTable (EdgeTable (clip));
  2174. state.fillEdgeTable (*et, colour);
  2175. }
  2176. else
  2177. {
  2178. state.fillRectangleList (clip, clipArea, colour);
  2179. }
  2180. state.currentShader.clearShader (state.quadQueue);
  2181. }
  2182. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  2183. {
  2184. if (clip.intersects (et.getMaximumBounds()))
  2185. {
  2186. if (! clip.containsRectangle (et.getMaximumBounds()))
  2187. et.clipToEdgeTable (EdgeTable (clip));
  2188. ShaderFillOperation fillOp (*this, fill, false, true);
  2189. state.fillEdgeTable (et, fill.colour.getPixelARGB());
  2190. }
  2191. }
  2192. private:
  2193. Ptr toMask() const { return new ClipRegion_Mask_Shader (state, clip); }
  2194. struct ShaderFillOperation
  2195. {
  2196. ShaderFillOperation (const ClipRegion_RectangleList_Shaders& clip, const FillType& fill,
  2197. const bool replaceContents, const bool clampTiledImages)
  2198. : state (clip.state)
  2199. {
  2200. if (fill.isColour())
  2201. {
  2202. state.currentColour.setSolidColour();
  2203. state.blendMode.setBlendMode (state.quadQueue, replaceContents);
  2204. state.currentShader.setShader (state.target, state.quadQueue, state.currentShader.programs->solidColourProgram);
  2205. }
  2206. else if (fill.isGradient())
  2207. {
  2208. state.setShaderForGradientFill (*fill.gradient, fill.transform, 0, nullptr);
  2209. }
  2210. else
  2211. {
  2212. jassert (fill.isTiledImage());
  2213. image = new OpenGLTextureFromImage (fill.image);
  2214. state.setShaderForTiledImageFill (*image, fill.transform, 0, nullptr, clampTiledImages);
  2215. }
  2216. }
  2217. ~ShaderFillOperation()
  2218. {
  2219. if (image != nullptr)
  2220. state.quadQueue.flush();
  2221. }
  2222. OpenGLGraphicsContext::GLState& state;
  2223. ScopedPointer<OpenGLTextureFromImage> image;
  2224. JUCE_DECLARE_NON_COPYABLE (ShaderFillOperation);
  2225. };
  2226. JUCE_DECLARE_NON_COPYABLE (ClipRegion_RectangleList_Shaders);
  2227. };
  2228. #endif
  2229. //==============================================================================
  2230. class OpenGLGraphicsContext::SavedState
  2231. {
  2232. public:
  2233. SavedState (OpenGLGraphicsContext::GLState* const state_)
  2234. : clip (createRectangleClip (*state_, Rectangle<int> (state_->target.width, state_->target.height))),
  2235. transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
  2236. state (state_), transparencyLayerAlpha (1.0f)
  2237. {
  2238. }
  2239. SavedState (const SavedState& other)
  2240. : clip (other.clip), transform (other.transform), font (other.font),
  2241. fillType (other.fillType), interpolationQuality (other.interpolationQuality),
  2242. state (other.state), transparencyLayerAlpha (other.transparencyLayerAlpha),
  2243. transparencyLayer (other.transparencyLayer), previousTarget (other.previousTarget.createCopy())
  2244. {
  2245. }
  2246. static ClipRegionBase* createRectangleClip (OpenGLGraphicsContext::GLState& state, const Rectangle<int>& clip)
  2247. {
  2248. #if JUCE_USE_OPENGL_SHADERS
  2249. if (state.currentShader.canUseShaders)
  2250. return new ClipRegion_RectangleList_Shaders (state, clip);
  2251. #endif
  2252. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  2253. return new ClipRegion_RectangleList (state, clip);
  2254. #else
  2255. // there's no shader hardware, but we're compiling without the fixed-function pipeline available!
  2256. jassertfalse;
  2257. return nullptr;
  2258. #endif
  2259. }
  2260. bool clipToRectangle (const Rectangle<int>& r)
  2261. {
  2262. if (clip != nullptr)
  2263. {
  2264. if (transform.isOnlyTranslated)
  2265. {
  2266. cloneClipIfMultiplyReferenced();
  2267. clip = clip->clipToRectangle (transform.translated (r));
  2268. }
  2269. else
  2270. {
  2271. Path p;
  2272. p.addRectangle (r);
  2273. clipToPath (p, AffineTransform::identity);
  2274. }
  2275. }
  2276. return clip != nullptr;
  2277. }
  2278. bool clipToRectangleList (const RectangleList& r)
  2279. {
  2280. if (clip != nullptr)
  2281. {
  2282. if (transform.isOnlyTranslated)
  2283. {
  2284. cloneClipIfMultiplyReferenced();
  2285. RectangleList offsetList (r);
  2286. offsetList.offsetAll (transform.xOffset, transform.yOffset);
  2287. clip = clip->clipToRectangleList (offsetList);
  2288. }
  2289. else
  2290. {
  2291. clipToPath (r.toPath(), AffineTransform::identity);
  2292. }
  2293. }
  2294. return clip != nullptr;
  2295. }
  2296. bool excludeClipRectangle (const Rectangle<int>& r)
  2297. {
  2298. if (clip != nullptr)
  2299. {
  2300. cloneClipIfMultiplyReferenced();
  2301. if (transform.isOnlyTranslated)
  2302. {
  2303. clip = clip->excludeClipRectangle (transform.translated (r));
  2304. }
  2305. else
  2306. {
  2307. Path p;
  2308. p.addRectangle (r.toFloat());
  2309. p.applyTransform (transform.complexTransform);
  2310. p.addRectangle (clip->getClipBounds().toFloat());
  2311. p.setUsingNonZeroWinding (false);
  2312. clip = clip->clipToPath (p, AffineTransform::identity);
  2313. }
  2314. }
  2315. return clip != nullptr;
  2316. }
  2317. void clipToPath (const Path& p, const AffineTransform& t)
  2318. {
  2319. if (clip != nullptr)
  2320. {
  2321. cloneClipIfMultiplyReferenced();
  2322. clip = clip->clipToPath (p, transform.getTransformWith (t));
  2323. }
  2324. }
  2325. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
  2326. {
  2327. if (clip != nullptr)
  2328. {
  2329. Path p;
  2330. p.addRectangle (sourceImage.getBounds());
  2331. clipToPath (p, t);
  2332. if (sourceImage.hasAlphaChannel() && clip != nullptr)
  2333. {
  2334. cloneClipIfMultiplyReferenced();
  2335. clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
  2336. }
  2337. }
  2338. }
  2339. bool clipRegionIntersects (const Rectangle<int>& r) const
  2340. {
  2341. return clip != nullptr
  2342. && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
  2343. : getClipBounds().intersects (r));
  2344. }
  2345. Rectangle<int> getClipBounds() const
  2346. {
  2347. return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
  2348. : Rectangle<int>();
  2349. }
  2350. SavedState* beginTransparencyLayer (float opacity)
  2351. {
  2352. SavedState* s = new SavedState (*this);
  2353. if (clip != nullptr)
  2354. {
  2355. const Rectangle<int> clipBounds (clip->getClipBounds());
  2356. state->quadQueue.flush();
  2357. s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
  2358. s->previousTarget = new OpenGLTarget (state->target);
  2359. state->target = OpenGLTarget (*OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
  2360. s->transparencyLayerAlpha = opacity;
  2361. s->cloneClipIfMultiplyReferenced();
  2362. s->state->target.makeActiveFor2D();
  2363. }
  2364. return s;
  2365. }
  2366. void endTransparencyLayer (SavedState& finishedLayerState)
  2367. {
  2368. if (clip != nullptr)
  2369. {
  2370. jassert (finishedLayerState.previousTarget != nullptr);
  2371. state->quadQueue.flush();
  2372. state->target = *finishedLayerState.previousTarget;
  2373. finishedLayerState.previousTarget = nullptr;
  2374. state->target.makeActiveFor2D();
  2375. const Rectangle<int> clipBounds (clip->getClipBounds());
  2376. clip->drawImage (finishedLayerState.transparencyLayer,
  2377. AffineTransform::translation ((float) clipBounds.getX(), (float) clipBounds.getY()),
  2378. finishedLayerState.transparencyLayerAlpha, clipBounds, nullptr);
  2379. }
  2380. }
  2381. //==============================================================================
  2382. void fillRect (const Rectangle<int>& r, const bool replaceContents)
  2383. {
  2384. if (clip != nullptr)
  2385. {
  2386. if (transform.isOnlyTranslated)
  2387. {
  2388. clip->fillRect (r.translated (transform.xOffset, transform.yOffset),
  2389. getFillType(), replaceContents);
  2390. }
  2391. else
  2392. {
  2393. Path p;
  2394. p.addRectangle (r);
  2395. fillPath (p, AffineTransform::identity);
  2396. }
  2397. }
  2398. }
  2399. void fillRect (const Rectangle<float>& r)
  2400. {
  2401. if (clip != nullptr)
  2402. {
  2403. if (transform.isOnlyTranslated)
  2404. {
  2405. const Rectangle<float> c (r.translated ((float) transform.xOffset, (float) transform.yOffset)
  2406. .getIntersection (clip->getClipBounds().toFloat()));
  2407. if (! c.isEmpty())
  2408. clip->fillRect (c, getFillType());
  2409. }
  2410. else
  2411. {
  2412. Path p;
  2413. p.addRectangle (r);
  2414. fillPath (p, AffineTransform::identity);
  2415. }
  2416. }
  2417. }
  2418. void fillPath (const Path& path, const AffineTransform& t)
  2419. {
  2420. if (clip != nullptr)
  2421. {
  2422. EdgeTable et (clip->getClipBounds(), path, transform.getTransformWith (t));
  2423. fillEdgeTable (et);
  2424. }
  2425. }
  2426. void drawGlyph (int glyphNumber, const AffineTransform& t)
  2427. {
  2428. if (clip != nullptr)
  2429. {
  2430. if (transform.isOnlyTranslated && t.isOnlyTranslation())
  2431. {
  2432. RenderingHelpers::GlyphCache <CachedGlyphEdgeTable, SavedState>::getInstance()
  2433. .drawGlyph (*this, font, glyphNumber,
  2434. transform.xOffset + t.getTranslationX(),
  2435. transform.yOffset + t.getTranslationY());
  2436. }
  2437. else
  2438. {
  2439. const float fontHeight = font.getHeight();
  2440. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph
  2441. (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  2442. .followedBy (t))));
  2443. if (et != nullptr)
  2444. fillEdgeTable (*et);
  2445. }
  2446. }
  2447. }
  2448. void fillEdgeTable (const EdgeTable& et, const float x, const int y)
  2449. {
  2450. if (clip != nullptr)
  2451. {
  2452. EdgeTable et2 (et);
  2453. et2.translate (x, y);
  2454. fillEdgeTable (et2);
  2455. }
  2456. }
  2457. void drawLine (const Line <float>& line)
  2458. {
  2459. Path p;
  2460. p.addLineSegment (line, 1.0f);
  2461. fillPath (p, AffineTransform::identity);
  2462. }
  2463. //==============================================================================
  2464. void drawImage (const Image& image, const AffineTransform& trans)
  2465. {
  2466. if (clip == nullptr || fillType.colour.isTransparent())
  2467. return;
  2468. const Rectangle<int> clipBounds (clip->getClipBounds());
  2469. const AffineTransform t (transform.getTransformWith (trans));
  2470. const float alpha = fillType.colour.getFloatAlpha();
  2471. if (t.isOnlyTranslation())
  2472. {
  2473. int tx = (int) (t.getTranslationX() * 256.0f);
  2474. int ty = (int) (t.getTranslationY() * 256.0f);
  2475. if (((tx | ty) & 0xf8) == 0)
  2476. {
  2477. tx = ((tx + 128) >> 8);
  2478. ty = ((ty + 128) >> 8);
  2479. clip->drawImage (image, t, alpha, Rectangle<int> (tx, ty, image.getWidth(), image.getHeight()), nullptr);
  2480. return;
  2481. }
  2482. }
  2483. if (! t.isSingularity())
  2484. {
  2485. Path p;
  2486. p.addRectangle (image.getBounds());
  2487. EdgeTable et (clipBounds, p, t);
  2488. clip->drawImage (image, t, alpha, clipBounds, &et);
  2489. }
  2490. }
  2491. void setFillType (const FillType& newFill)
  2492. {
  2493. fillType = newFill;
  2494. state->textureCache.resetGradient();
  2495. }
  2496. //==============================================================================
  2497. ClipRegionBase::Ptr clip;
  2498. RenderingHelpers::TranslationOrTransform transform;
  2499. Font font;
  2500. FillType fillType;
  2501. Graphics::ResamplingQuality interpolationQuality;
  2502. GLState* state;
  2503. private:
  2504. float transparencyLayerAlpha;
  2505. Image transparencyLayer;
  2506. ScopedPointer<OpenGLTarget> previousTarget;
  2507. void cloneClipIfMultiplyReferenced()
  2508. {
  2509. if (clip->getReferenceCount() > 1)
  2510. clip = clip->clone();
  2511. }
  2512. FillType getFillType() const
  2513. {
  2514. return fillType.transformed (transform.getTransform());
  2515. }
  2516. void fillEdgeTable (EdgeTable& et)
  2517. {
  2518. clip->fillEdgeTable (et, getFillType());
  2519. }
  2520. class CachedGlyphEdgeTable
  2521. {
  2522. public:
  2523. CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}
  2524. void draw (OpenGLGraphicsContext::SavedState& state, float x, const float y) const
  2525. {
  2526. if (snapToIntegerCoordinate)
  2527. x = std::floor (x + 0.5f);
  2528. if (edgeTable != nullptr)
  2529. state.fillEdgeTable (*edgeTable, x, roundToInt (y));
  2530. }
  2531. void generate (const Font& newFont, const int glyphNumber)
  2532. {
  2533. font = newFont;
  2534. snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
  2535. glyph = glyphNumber;
  2536. const float fontHeight = font.getHeight();
  2537. edgeTable = font.getTypeface()->getEdgeTableForGlyph (glyphNumber,
  2538. AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  2539. #if JUCE_MAC || JUCE_IOS
  2540. .translated (0.0f, -0.5f)
  2541. #endif
  2542. );
  2543. }
  2544. Font font;
  2545. int glyph, lastAccessCount;
  2546. bool snapToIntegerCoordinate;
  2547. private:
  2548. ScopedPointer <EdgeTable> edgeTable;
  2549. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable);
  2550. };
  2551. SavedState& operator= (const SavedState&);
  2552. };
  2553. //==============================================================================
  2554. OpenGLGraphicsContext::OpenGLGraphicsContext (OpenGLComponent& target)
  2555. : glState (new GLState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight()))),
  2556. stack (new SavedState (glState))
  2557. {
  2558. }
  2559. OpenGLGraphicsContext::OpenGLGraphicsContext (OpenGLFrameBuffer& target)
  2560. : glState (new GLState (OpenGLTarget (target, Point<int>()))),
  2561. stack (new SavedState (glState))
  2562. {
  2563. }
  2564. OpenGLGraphicsContext::OpenGLGraphicsContext (unsigned int frameBufferID, int width, int height)
  2565. : glState (new GLState (OpenGLTarget (frameBufferID, width, height))),
  2566. stack (new SavedState (glState))
  2567. {
  2568. }
  2569. OpenGLGraphicsContext::~OpenGLGraphicsContext()
  2570. {
  2571. }
  2572. bool OpenGLGraphicsContext::isVectorDevice() const { return false; }
  2573. void OpenGLGraphicsContext::setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
  2574. void OpenGLGraphicsContext::addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
  2575. float OpenGLGraphicsContext::getScaleFactor() { return stack->transform.getScaleFactor(); }
  2576. Rectangle<int> OpenGLGraphicsContext::getClipBounds() const { return stack->getClipBounds(); }
  2577. bool OpenGLGraphicsContext::isClipEmpty() const { return stack->clip == nullptr; }
  2578. bool OpenGLGraphicsContext::clipRegionIntersects (const Rectangle<int>& r) { return stack->clipRegionIntersects (r); }
  2579. bool OpenGLGraphicsContext::clipToRectangle (const Rectangle<int>& r) { return stack->clipToRectangle (r); }
  2580. bool OpenGLGraphicsContext::clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
  2581. void OpenGLGraphicsContext::excludeClipRectangle (const Rectangle<int>& r) { stack->excludeClipRectangle (r); }
  2582. void OpenGLGraphicsContext::clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
  2583. void OpenGLGraphicsContext::clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
  2584. void OpenGLGraphicsContext::saveState() { stack.save(); }
  2585. void OpenGLGraphicsContext::restoreState() { stack.restore(); }
  2586. void OpenGLGraphicsContext::beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
  2587. void OpenGLGraphicsContext::endTransparencyLayer() { stack.endTransparencyLayer(); }
  2588. void OpenGLGraphicsContext::setFill (const FillType& fillType) { stack->setFillType (fillType); }
  2589. void OpenGLGraphicsContext::setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
  2590. void OpenGLGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
  2591. void OpenGLGraphicsContext::fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
  2592. void OpenGLGraphicsContext::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
  2593. void OpenGLGraphicsContext::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
  2594. void OpenGLGraphicsContext::drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
  2595. void OpenGLGraphicsContext::drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
  2596. void OpenGLGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
  2597. void OpenGLGraphicsContext::drawLine (const Line <float>& line) { stack->drawLine (line); }
  2598. void OpenGLGraphicsContext::setFont (const Font& newFont) { stack->font = newFont; }
  2599. Font OpenGLGraphicsContext::getFont() { return stack->font; }