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.

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