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.

2231 lines
83KB

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