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.

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