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.

3252 lines
120KB

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