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.

3211 lines
119KB

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