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.

2241 lines
83KB

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