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.

2272 lines
84KB

  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& im,
  395. const float targetX, const float targetY) const
  396. {
  397. setMatrix (trans,
  398. im.imageWidth, im.imageHeight,
  399. im.fullWidthProportion, im.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 (const Rectangle<int>* i = list.begin(), * const e = list.end(); i != e; ++i)
  847. add (*i, colour);
  848. }
  849. void add (const RectangleList& list, const Rectangle<int>& clip, const PixelARGB& colour) noexcept
  850. {
  851. for (const Rectangle<int>* i = list.begin(), * const e = list.end(); i != e; ++i)
  852. {
  853. const Rectangle<int> r (i->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. JUCE_CHECK_OPENGL_ERROR
  889. numVertices = 0;
  890. }
  891. JUCE_DECLARE_NON_COPYABLE (ShaderQuadQueue)
  892. };
  893. //==============================================================================
  894. struct CurrentShader
  895. {
  896. CurrentShader (OpenGLContext& c) noexcept
  897. : context (c),
  898. activeShader (nullptr)
  899. {
  900. const char programValueID[] = "GraphicsContextPrograms";
  901. programs = static_cast <ShaderPrograms*> (context.getAssociatedObject (programValueID));
  902. if (programs == nullptr)
  903. {
  904. programs = new ShaderPrograms (context);
  905. context.setAssociatedObject (programValueID, programs);
  906. }
  907. }
  908. void setShader (const Rectangle<int>& bounds, ShaderQuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  909. {
  910. if (activeShader != &shader)
  911. {
  912. quadQueue.flush();
  913. activeShader = &shader;
  914. shader.program.use();
  915. shader.bindAttributes (context);
  916. currentBounds = bounds;
  917. shader.set2DBounds (bounds.toFloat());
  918. JUCE_CHECK_OPENGL_ERROR
  919. }
  920. else if (bounds != currentBounds)
  921. {
  922. currentBounds = bounds;
  923. shader.set2DBounds (bounds.toFloat());
  924. }
  925. }
  926. void setShader (Target& target, ShaderQuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  927. {
  928. setShader (target.bounds, quadQueue, shader);
  929. }
  930. void clearShader (ShaderQuadQueue& quadQueue)
  931. {
  932. if (activeShader != nullptr)
  933. {
  934. quadQueue.flush();
  935. activeShader->unbindAttributes (context);
  936. activeShader = nullptr;
  937. context.extensions.glUseProgram (0);
  938. }
  939. }
  940. OpenGLContext& context;
  941. ShaderPrograms::Ptr programs;
  942. private:
  943. ShaderPrograms::ShaderBase* activeShader;
  944. Rectangle<int> currentBounds;
  945. CurrentShader& operator= (const CurrentShader&);
  946. };
  947. };
  948. //==============================================================================
  949. class GLState
  950. {
  951. public:
  952. GLState (const Target& target_) noexcept
  953. : target (target_),
  954. activeTextures (target_.context),
  955. currentShader (target_.context),
  956. shaderQuadQueue (target_.context),
  957. previousFrameBufferTarget (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  958. {
  959. // This object can only be created and used when the current thread has an active OpenGL context.
  960. jassert (OpenGLHelpers::isContextActive());
  961. JUCE_CHECK_OPENGL_ERROR
  962. target.makeActive();
  963. blendMode.resync();
  964. JUCE_CHECK_OPENGL_ERROR
  965. #ifdef GL_COLOR_ARRAY
  966. glDisableClientState (GL_COLOR_ARRAY);
  967. glDisableClientState (GL_NORMAL_ARRAY);
  968. glDisableClientState (GL_VERTEX_ARRAY);
  969. glDisableClientState (GL_INDEX_ARRAY);
  970. for (int i = 3; --i >= 0;)
  971. {
  972. activeTextures.setActiveTexture (i);
  973. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  974. }
  975. #endif
  976. JUCE_CHECK_OPENGL_ERROR
  977. activeTextures.clear();
  978. shaderQuadQueue.initialise();
  979. JUCE_CHECK_OPENGL_ERROR
  980. }
  981. ~GLState()
  982. {
  983. flush();
  984. target.context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget);
  985. #if defined (GL_INDEX_ARRAY)
  986. glDisableClientState (GL_INDEX_ARRAY);
  987. #endif
  988. target.context.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
  989. target.context.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
  990. }
  991. void flush()
  992. {
  993. currentShader.clearShader (shaderQuadQueue);
  994. shaderQuadQueue.flush();
  995. JUCE_CHECK_OPENGL_ERROR
  996. }
  997. void setShader (ShaderPrograms::ShaderBase& shader)
  998. {
  999. currentShader.setShader (target, shaderQuadQueue, shader);
  1000. JUCE_CHECK_OPENGL_ERROR
  1001. }
  1002. void setShaderForGradientFill (const ColourGradient& g, const AffineTransform& transform,
  1003. const int maskTextureID, const Rectangle<int>* const maskArea)
  1004. {
  1005. JUCE_CHECK_OPENGL_ERROR
  1006. activeTextures.disableTextures (shaderQuadQueue);
  1007. blendMode.setPremultipliedBlendingMode (shaderQuadQueue);
  1008. JUCE_CHECK_OPENGL_ERROR
  1009. if (maskArea != nullptr)
  1010. {
  1011. activeTextures.setTexturesEnabled (shaderQuadQueue, 3);
  1012. activeTextures.setActiveTexture (1);
  1013. activeTextures.bindTexture (maskTextureID);
  1014. activeTextures.setActiveTexture (0);
  1015. textureCache.bindTextureForGradient (activeTextures, g);
  1016. }
  1017. else
  1018. {
  1019. activeTextures.setSingleTextureMode (shaderQuadQueue);
  1020. textureCache.bindTextureForGradient (activeTextures, g);
  1021. }
  1022. const AffineTransform t (transform.translated ((float) -target.bounds.getX(), (float) -target.bounds.getY()));
  1023. Point<float> p1 (g.point1.transformedBy (t));
  1024. const Point<float> p2 (g.point2.transformedBy (t));
  1025. const Point<float> p3 (Point<float> (g.point1.x + (g.point2.y - g.point1.y),
  1026. g.point1.y - (g.point2.x - g.point1.x)).transformedBy (t));
  1027. ShaderPrograms* const programs = currentShader.programs;
  1028. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1029. if (g.isRadial)
  1030. {
  1031. ShaderPrograms::RadialGradientParams* gradientParams;
  1032. if (maskArea == nullptr)
  1033. {
  1034. setShader (programs->radialGradient);
  1035. gradientParams = &programs->radialGradient.gradientParams;
  1036. }
  1037. else
  1038. {
  1039. setShader (programs->radialGradientMasked);
  1040. gradientParams = &programs->radialGradientMasked.gradientParams;
  1041. maskParams = &programs->radialGradientMasked.maskParams;
  1042. }
  1043. gradientParams->setMatrix (p1, p2, p3);
  1044. }
  1045. else
  1046. {
  1047. p1 = Line<float> (p1, p3).findNearestPointTo (p2);
  1048. const Point<float> delta (p2.x - p1.x, p1.y - p2.y);
  1049. const ShaderPrograms::LinearGradientParams* gradientParams;
  1050. float grad, length;
  1051. if (std::abs (delta.x) < std::abs (delta.y))
  1052. {
  1053. if (maskArea == nullptr)
  1054. {
  1055. setShader (programs->linearGradient1);
  1056. gradientParams = &(programs->linearGradient1.gradientParams);
  1057. }
  1058. else
  1059. {
  1060. setShader (programs->linearGradient1Masked);
  1061. gradientParams = &(programs->linearGradient1Masked.gradientParams);
  1062. maskParams = &programs->linearGradient1Masked.maskParams;
  1063. }
  1064. grad = delta.x / delta.y;
  1065. length = (p2.y - grad * p2.x) - (p1.y - grad * p1.x);
  1066. }
  1067. else
  1068. {
  1069. if (maskArea == nullptr)
  1070. {
  1071. setShader (programs->linearGradient2);
  1072. gradientParams = &(programs->linearGradient2.gradientParams);
  1073. }
  1074. else
  1075. {
  1076. setShader (programs->linearGradient2Masked);
  1077. gradientParams = &(programs->linearGradient2Masked.gradientParams);
  1078. maskParams = &programs->linearGradient2Masked.maskParams;
  1079. }
  1080. grad = delta.y / delta.x;
  1081. length = (p2.x - grad * p2.y) - (p1.x - grad * p1.y);
  1082. }
  1083. gradientParams->gradientInfo.set (p1.x, p1.y, grad, length);
  1084. }
  1085. if (maskParams != nullptr)
  1086. maskParams->setBounds (*maskArea, target, 1);
  1087. JUCE_CHECK_OPENGL_ERROR
  1088. }
  1089. void setShaderForTiledImageFill (const OpenGLTextureFromImage& image, const AffineTransform& transform,
  1090. const int maskTextureID, const Rectangle<int>* const maskArea, const bool clampTiledImages)
  1091. {
  1092. blendMode.setPremultipliedBlendingMode (shaderQuadQueue);
  1093. ShaderPrograms* const programs = currentShader.programs;
  1094. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1095. const ShaderPrograms::ImageParams* imageParams;
  1096. if (maskArea != nullptr)
  1097. {
  1098. activeTextures.setTwoTextureMode (shaderQuadQueue, image.textureID, maskTextureID);
  1099. if (clampTiledImages)
  1100. {
  1101. setShader (programs->imageMasked);
  1102. imageParams = &programs->imageMasked.imageParams;
  1103. maskParams = &programs->imageMasked.maskParams;
  1104. }
  1105. else
  1106. {
  1107. setShader (programs->tiledImageMasked);
  1108. imageParams = &programs->tiledImageMasked.imageParams;
  1109. maskParams = &programs->tiledImageMasked.maskParams;
  1110. }
  1111. }
  1112. else
  1113. {
  1114. activeTextures.setSingleTextureMode (shaderQuadQueue);
  1115. activeTextures.bindTexture (image.textureID);
  1116. if (clampTiledImages)
  1117. {
  1118. setShader (programs->image);
  1119. imageParams = &programs->image.imageParams;
  1120. }
  1121. else
  1122. {
  1123. setShader (programs->tiledImage);
  1124. imageParams = &programs->tiledImage.imageParams;
  1125. }
  1126. }
  1127. imageParams->setMatrix (transform, image, (float) target.bounds.getX(), (float) target.bounds.getY());
  1128. if (maskParams != nullptr)
  1129. maskParams->setBounds (*maskArea, target, 1);
  1130. }
  1131. Target target;
  1132. StateHelpers::BlendingMode blendMode;
  1133. StateHelpers::ActiveTextures activeTextures;
  1134. StateHelpers::TextureCache textureCache;
  1135. StateHelpers::CurrentShader currentShader;
  1136. StateHelpers::ShaderQuadQueue shaderQuadQueue;
  1137. private:
  1138. GLuint previousFrameBufferTarget;
  1139. };
  1140. //==============================================================================
  1141. class ClipRegionBase : public SingleThreadedReferenceCountedObject
  1142. {
  1143. public:
  1144. ClipRegionBase (GLState& state_) noexcept : state (state_) {}
  1145. virtual ~ClipRegionBase() {}
  1146. typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
  1147. virtual Ptr clone() const = 0;
  1148. virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
  1149. virtual Ptr clipToRectangleList (const RectangleList&) = 0;
  1150. virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
  1151. virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
  1152. virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
  1153. virtual Ptr clipToTexture (const PositionedTexture&) = 0;
  1154. virtual Rectangle<int> getClipBounds() const = 0;
  1155. virtual void fillRect (const Rectangle<int>& area, const FillType&, bool replaceContents) = 0;
  1156. virtual void fillRect (const Rectangle<float>& area, const FillType&) = 0;
  1157. virtual void fillEdgeTable (EdgeTable& et, const FillType& fill) = 0;
  1158. virtual void drawImage (const Image&, const AffineTransform&, float alpha,
  1159. const Rectangle<int>& clip, EdgeTable* mask) = 0;
  1160. GLState& state;
  1161. JUCE_DECLARE_NON_COPYABLE (ClipRegionBase)
  1162. };
  1163. //==============================================================================
  1164. class ClipRegion_Mask : public ClipRegionBase
  1165. {
  1166. public:
  1167. ClipRegion_Mask (const ClipRegion_Mask& other)
  1168. : ClipRegionBase (other.state),
  1169. clip (other.clip),
  1170. maskArea (other.clip)
  1171. {
  1172. TargetSaver ts (state.target.context);
  1173. state.currentShader.clearShader (state.shaderQuadQueue);
  1174. state.shaderQuadQueue.flush();
  1175. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  1176. state.activeTextures.clear();
  1177. mask.initialise (state.target.context, maskArea.getWidth(), maskArea.getHeight());
  1178. maskArea.setSize (mask.getWidth(), mask.getHeight());
  1179. makeActive();
  1180. state.blendMode.disableBlend (state.shaderQuadQueue);
  1181. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  1182. state.activeTextures.bindTexture (other.mask.getTextureID());
  1183. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->copyTexture);
  1184. state.currentShader.programs->copyTexture.imageParams.imageTexture.set (0);
  1185. state.currentShader.programs->copyTexture.imageParams
  1186. .setMatrix (AffineTransform::translation ((float) other.maskArea.getX(), (float) other.maskArea.getY()),
  1187. other.maskArea.getWidth(), other.maskArea.getHeight(), 1.0f, 1.0f,
  1188. (float) maskArea.getX(), (float) maskArea.getY());
  1189. state.shaderQuadQueue.add (clip, PixelARGB (0xffffffff));
  1190. state.shaderQuadQueue.flush();
  1191. }
  1192. ClipRegion_Mask (GLState& state_, const RectangleList& r)
  1193. : ClipRegionBase (state_),
  1194. clip (r.getBounds()),
  1195. maskArea (clip)
  1196. {
  1197. TargetSaver ts (state.target.context);
  1198. state.currentShader.clearShader (state.shaderQuadQueue);
  1199. state.shaderQuadQueue.flush();
  1200. state.activeTextures.clear();
  1201. mask.initialise (state.target.context, maskArea.getWidth(), maskArea.getHeight());
  1202. maskArea.setSize (mask.getWidth(), mask.getHeight());
  1203. mask.makeCurrentAndClear();
  1204. makeActive();
  1205. state.blendMode.setBlendMode (state.shaderQuadQueue, true);
  1206. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->solidColourProgram);
  1207. state.shaderQuadQueue.add (r, PixelARGB (0xffffffff));
  1208. state.shaderQuadQueue.flush();
  1209. }
  1210. Ptr clone() const { return new ClipRegion_Mask (*this); }
  1211. Rectangle<int> getClipBounds() const { return clip; }
  1212. Ptr clipToRectangle (const Rectangle<int>& r)
  1213. {
  1214. clip = clip.getIntersection (r);
  1215. return clip.isEmpty() ? nullptr : this;
  1216. }
  1217. Ptr clipToRectangleList (const RectangleList& r)
  1218. {
  1219. clip = clip.getIntersection (r.getBounds());
  1220. if (clip.isEmpty())
  1221. return Ptr();
  1222. RectangleList excluded (clip);
  1223. if (excluded.subtract (r))
  1224. {
  1225. if (excluded.getNumRectangles() == 1)
  1226. return excludeClipRectangle (excluded.getRectangle (0));
  1227. TargetSaver ts (state.target.context);
  1228. makeActive();
  1229. state.blendMode.setBlendMode (state.shaderQuadQueue, true);
  1230. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->solidColourProgram);
  1231. state.shaderQuadQueue.add (excluded, PixelARGB (0));
  1232. state.shaderQuadQueue.flush();
  1233. }
  1234. return this;
  1235. }
  1236. Ptr excludeClipRectangle (const Rectangle<int>& r)
  1237. {
  1238. if (r.contains (clip))
  1239. return Ptr();
  1240. TargetSaver ts (state.target.context);
  1241. makeActive();
  1242. state.blendMode.setBlendMode (state.shaderQuadQueue, true);
  1243. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->solidColourProgram);
  1244. state.shaderQuadQueue.add (r, PixelARGB (0));
  1245. state.shaderQuadQueue.flush();
  1246. return this;
  1247. }
  1248. Ptr clipToPath (const Path& p, const AffineTransform& t)
  1249. {
  1250. EdgeTable et (clip, p, t);
  1251. if (! et.isEmpty())
  1252. {
  1253. TargetSaver ts (state.target.context);
  1254. state.currentShader.clearShader (state.shaderQuadQueue);
  1255. state.shaderQuadQueue.flush();
  1256. state.activeTextures.clear();
  1257. OpenGLTexture texture;
  1258. PositionedTexture pt (texture, et, clip);
  1259. return clipToTexture (pt);
  1260. }
  1261. return Ptr();
  1262. }
  1263. Ptr clipToTexture (const PositionedTexture& pt)
  1264. {
  1265. clip = clip.getIntersection (pt.clip);
  1266. if (clip.isEmpty())
  1267. return Ptr();
  1268. TargetSaver ts (state.target.context);
  1269. makeActive();
  1270. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  1271. state.activeTextures.bindTexture (pt.textureID);
  1272. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->maskTexture);
  1273. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  1274. state.currentShader.programs->maskTexture.imageParams
  1275. .setMatrix (AffineTransform::translation ((float) pt.area.getX(), (float) pt.area.getY()),
  1276. pt.area.getWidth(), pt.area.getHeight(), 1.0f, 1.0f,
  1277. (float) maskArea.getX(), (float) maskArea.getY());
  1278. state.blendMode.setBlendFunc (state.shaderQuadQueue, GL_ZERO, GL_SRC_ALPHA);
  1279. state.shaderQuadQueue.add (clip, PixelARGB (0xffffffff));
  1280. state.shaderQuadQueue.flush();
  1281. return this;
  1282. }
  1283. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  1284. {
  1285. TargetSaver ts (state.target.context);
  1286. makeActive();
  1287. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  1288. state.activeTextures.bindTexture (image.textureID);
  1289. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->maskTexture);
  1290. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  1291. state.currentShader.programs->maskTexture.imageParams
  1292. .setMatrix (transform, image, (float) maskArea.getX(), (float) maskArea.getY());
  1293. state.shaderQuadQueue.add (clip, PixelARGB (0xffffffff));
  1294. state.shaderQuadQueue.flush();
  1295. return this;
  1296. }
  1297. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1298. {
  1299. (void) replaceContents; jassert (! replaceContents);
  1300. const Rectangle<int> r (clip.getIntersection (area));
  1301. if (! r.isEmpty())
  1302. {
  1303. ShaderFillOperation fillOp (*this, fill, false);
  1304. state.shaderQuadQueue.add (r, fill.colour.getPixelARGB());
  1305. }
  1306. }
  1307. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1308. {
  1309. ShaderFillOperation fillOp (*this, fill, false);
  1310. FloatRectangleRenderer frr (*this, fill);
  1311. RenderingHelpers::FloatRectangleRasterisingInfo (area).iterate (frr);
  1312. }
  1313. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1314. {
  1315. if (et.getMaximumBounds().intersects (clip))
  1316. {
  1317. if (! clip.contains (et.getMaximumBounds()))
  1318. et.clipToRectangle (clip);
  1319. ShaderFillOperation fillOp (*this, fill, false);
  1320. state.shaderQuadQueue.add (et, fill.colour.getPixelARGB());
  1321. }
  1322. }
  1323. void drawImage (const Image& image, const AffineTransform& transform,
  1324. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  1325. {
  1326. const Rectangle<int> r (clip.getIntersection (clipArea));
  1327. if (! r.isEmpty())
  1328. {
  1329. const PixelARGB colour (Colours::white.withAlpha (alpha).getPixelARGB());
  1330. ShaderFillOperation fillOp (*this, FillType (image, transform), true);
  1331. if (et != nullptr)
  1332. {
  1333. et->clipToRectangle (r);
  1334. if (! et->isEmpty())
  1335. state.shaderQuadQueue.add (*et, colour);
  1336. }
  1337. else
  1338. {
  1339. state.shaderQuadQueue.add (r, colour);
  1340. }
  1341. }
  1342. state.currentShader.clearShader (state.shaderQuadQueue);
  1343. }
  1344. private:
  1345. OpenGLFrameBuffer mask;
  1346. Rectangle<int> clip, maskArea;
  1347. struct ShaderFillOperation
  1348. {
  1349. ShaderFillOperation (const ClipRegion_Mask& clipMask, const FillType& fill, const bool clampTiledImages)
  1350. : state (clipMask.state)
  1351. {
  1352. const GLuint maskTextureID = clipMask.mask.getTextureID();
  1353. if (fill.isColour())
  1354. {
  1355. state.blendMode.setPremultipliedBlendingMode (state.shaderQuadQueue);
  1356. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  1357. state.activeTextures.bindTexture (maskTextureID);
  1358. state.setShader (state.currentShader.programs->solidColourMasked);
  1359. state.currentShader.programs->solidColourMasked.maskParams.setBounds (clipMask.maskArea, state.target, 0);
  1360. }
  1361. else if (fill.isGradient())
  1362. {
  1363. state.setShaderForGradientFill (*fill.gradient, fill.transform, maskTextureID, &clipMask.maskArea);
  1364. }
  1365. else
  1366. {
  1367. jassert (fill.isTiledImage());
  1368. image = new OpenGLTextureFromImage (fill.image);
  1369. state.setShaderForTiledImageFill (*image, fill.transform, maskTextureID, &clipMask.maskArea, clampTiledImages);
  1370. }
  1371. }
  1372. ~ShaderFillOperation()
  1373. {
  1374. state.shaderQuadQueue.flush();
  1375. }
  1376. GLState& state;
  1377. ScopedPointer<OpenGLTextureFromImage> image;
  1378. JUCE_DECLARE_NON_COPYABLE (ShaderFillOperation)
  1379. };
  1380. struct TargetSaver
  1381. {
  1382. TargetSaver (const OpenGLContext& c)
  1383. : context (c), oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  1384. {
  1385. glGetIntegerv (GL_VIEWPORT, oldViewport);
  1386. }
  1387. ~TargetSaver()
  1388. {
  1389. context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, oldFramebuffer);
  1390. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  1391. }
  1392. private:
  1393. const OpenGLContext& context;
  1394. GLuint oldFramebuffer;
  1395. GLint oldViewport[4];
  1396. TargetSaver& operator= (const TargetSaver&);
  1397. };
  1398. void makeActive()
  1399. {
  1400. state.shaderQuadQueue.flush();
  1401. state.activeTextures.clear();
  1402. mask.makeCurrentRenderingTarget();
  1403. glViewport (0, 0, maskArea.getWidth(), maskArea.getHeight());
  1404. }
  1405. struct FloatRectangleRenderer
  1406. {
  1407. FloatRectangleRenderer (ClipRegion_Mask& owner_, const FillType& fill_) noexcept
  1408. : owner (owner_), originalColour (fill_.colour.getPixelARGB())
  1409. {}
  1410. void operator() (int x, int y, int w, int h, const int alpha) noexcept
  1411. {
  1412. if (owner.clip.intersectRectangle (x, y, w, h))
  1413. {
  1414. PixelARGB col (originalColour);
  1415. col.multiplyAlpha (alpha);
  1416. owner.state.shaderQuadQueue.add (x, y, w, h, col);
  1417. }
  1418. }
  1419. private:
  1420. ClipRegion_Mask& owner;
  1421. const PixelARGB originalColour;
  1422. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer)
  1423. };
  1424. ClipRegion_Mask& operator= (const ClipRegion_Mask&);
  1425. };
  1426. //==============================================================================
  1427. class ClipRegion_RectangleList : public ClipRegionBase
  1428. {
  1429. public:
  1430. ClipRegion_RectangleList (GLState& state_, const Rectangle<int>& r) noexcept
  1431. : ClipRegionBase (state_), clip (r)
  1432. {}
  1433. ClipRegion_RectangleList (GLState& state_, const RectangleList& r) noexcept
  1434. : ClipRegionBase (state_), clip (r)
  1435. {}
  1436. Ptr clone() const { return new ClipRegion_RectangleList (state, clip); }
  1437. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  1438. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  1439. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  1440. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1441. {
  1442. ShaderFillOperation fillOp (*this, fill, replaceContents || fill.colour.isOpaque(), false);
  1443. state.shaderQuadQueue.add (clip, area, fill.colour.getPixelARGB());
  1444. }
  1445. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1446. {
  1447. const PixelARGB colour (fill.colour.getPixelARGB());
  1448. ShaderFillOperation fillOp (*this, fill, false, false);
  1449. for (const Rectangle<int>* i = clip.begin(), * const e = clip.end(); i != e; ++i)
  1450. {
  1451. const Rectangle<float> r (i->toFloat().getIntersection (area));
  1452. if (! r.isEmpty())
  1453. state.shaderQuadQueue.add (r, colour);
  1454. }
  1455. }
  1456. void drawImage (const Image& image, const AffineTransform& transform,
  1457. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  1458. {
  1459. FillType fill (image, transform);
  1460. const PixelARGB colour (Colours::white.withAlpha (alpha).getPixelARGB());
  1461. ShaderFillOperation fillOp (*this, fill, false, true);
  1462. if (et != nullptr)
  1463. {
  1464. if (! clip.containsRectangle (et->getMaximumBounds()))
  1465. et->clipToEdgeTable (EdgeTable (clip));
  1466. state.shaderQuadQueue.add (*et, colour);
  1467. }
  1468. else
  1469. {
  1470. state.shaderQuadQueue.add (clip, clipArea, colour);
  1471. }
  1472. state.currentShader.clearShader (state.shaderQuadQueue);
  1473. }
  1474. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1475. {
  1476. if (clip.intersects (et.getMaximumBounds()))
  1477. {
  1478. if (! clip.containsRectangle (et.getMaximumBounds()))
  1479. et.clipToEdgeTable (EdgeTable (clip));
  1480. ShaderFillOperation fillOp (*this, fill, false, true);
  1481. state.shaderQuadQueue.add (et, fill.colour.getPixelARGB());
  1482. }
  1483. }
  1484. Rectangle<int> getClipBounds() const { return clip.getBounds(); }
  1485. Ptr clipToRectangle (const Rectangle<int>& r) { return clip.clipTo (r) ? this : nullptr; }
  1486. Ptr clipToRectangleList (const RectangleList& r) { return clip.clipTo (r) ? this : nullptr; }
  1487. Ptr excludeClipRectangle (const Rectangle<int>& r) { clip.subtract (r); return clip.isEmpty() ? nullptr : this; }
  1488. private:
  1489. RectangleList clip;
  1490. Ptr toMask() const { return new ClipRegion_Mask (state, clip); }
  1491. struct ShaderFillOperation
  1492. {
  1493. ShaderFillOperation (const ClipRegion_RectangleList& clipList, const FillType& fill,
  1494. const bool replaceContents, const bool clampTiledImages)
  1495. : state (clipList.state)
  1496. {
  1497. if (fill.isColour())
  1498. {
  1499. state.activeTextures.disableTextures (state.shaderQuadQueue);
  1500. state.blendMode.setBlendMode (state.shaderQuadQueue, replaceContents);
  1501. state.setShader (state.currentShader.programs->solidColourProgram);
  1502. }
  1503. else if (fill.isGradient())
  1504. {
  1505. state.setShaderForGradientFill (*fill.gradient, fill.transform, 0, nullptr);
  1506. }
  1507. else
  1508. {
  1509. jassert (fill.isTiledImage());
  1510. image = new OpenGLTextureFromImage (fill.image);
  1511. state.setShaderForTiledImageFill (*image, fill.transform, 0, nullptr, clampTiledImages);
  1512. }
  1513. }
  1514. ~ShaderFillOperation()
  1515. {
  1516. if (image != nullptr)
  1517. state.shaderQuadQueue.flush();
  1518. }
  1519. GLState& state;
  1520. ScopedPointer<OpenGLTextureFromImage> image;
  1521. JUCE_DECLARE_NON_COPYABLE (ShaderFillOperation)
  1522. };
  1523. JUCE_DECLARE_NON_COPYABLE (ClipRegion_RectangleList)
  1524. };
  1525. //==============================================================================
  1526. class SavedState
  1527. {
  1528. public:
  1529. SavedState (GLState* const state_)
  1530. : clip (new ClipRegion_RectangleList (*state_, state_->target.bounds)),
  1531. transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
  1532. state (state_), transparencyLayerAlpha (1.0f)
  1533. {}
  1534. SavedState (const SavedState& other)
  1535. : clip (other.clip), transform (other.transform), font (other.font),
  1536. fillType (other.fillType), interpolationQuality (other.interpolationQuality),
  1537. state (other.state), transparencyLayerAlpha (other.transparencyLayerAlpha),
  1538. transparencyLayer (other.transparencyLayer), previousTarget (other.previousTarget.createCopy())
  1539. {}
  1540. bool clipToRectangle (const Rectangle<int>& r)
  1541. {
  1542. if (clip != nullptr)
  1543. {
  1544. if (transform.isOnlyTranslated)
  1545. {
  1546. cloneClipIfMultiplyReferenced();
  1547. clip = clip->clipToRectangle (transform.translated (r));
  1548. }
  1549. else if (transform.isIntegerScaling)
  1550. {
  1551. cloneClipIfMultiplyReferenced();
  1552. clip = clip->clipToRectangle (transform.transformed (r).getSmallestIntegerContainer());
  1553. }
  1554. else
  1555. {
  1556. Path p;
  1557. p.addRectangle (r);
  1558. clipToPath (p, AffineTransform::identity);
  1559. }
  1560. }
  1561. return clip != nullptr;
  1562. }
  1563. bool clipToRectangleList (const RectangleList& r)
  1564. {
  1565. if (clip != nullptr)
  1566. {
  1567. if (transform.isOnlyTranslated)
  1568. {
  1569. cloneClipIfMultiplyReferenced();
  1570. RectangleList offsetList (r);
  1571. offsetList.offsetAll (transform.xOffset, transform.yOffset);
  1572. clip = clip->clipToRectangleList (offsetList);
  1573. }
  1574. else if (transform.isIntegerScaling)
  1575. {
  1576. cloneClipIfMultiplyReferenced();
  1577. RectangleList scaledList;
  1578. for (const Rectangle<int>* i = r.begin(), * const e = r.end(); i != e; ++i)
  1579. scaledList.add (transform.transformed (*i).getSmallestIntegerContainer());
  1580. clip = clip->clipToRectangleList (scaledList);
  1581. }
  1582. else
  1583. {
  1584. clipToPath (r.toPath(), AffineTransform::identity);
  1585. }
  1586. }
  1587. return clip != nullptr;
  1588. }
  1589. bool excludeClipRectangle (const Rectangle<int>& r)
  1590. {
  1591. if (clip != nullptr)
  1592. {
  1593. cloneClipIfMultiplyReferenced();
  1594. if (transform.isOnlyTranslated)
  1595. {
  1596. clip = clip->excludeClipRectangle (transform.translated (r));
  1597. }
  1598. else if (transform.isIntegerScaling)
  1599. {
  1600. clip = clip->excludeClipRectangle (transform.transformed (r).getSmallestIntegerContainer());
  1601. }
  1602. else
  1603. {
  1604. Path p;
  1605. p.addRectangle (r.toFloat());
  1606. p.applyTransform (transform.complexTransform);
  1607. p.addRectangle (clip->getClipBounds().toFloat());
  1608. p.setUsingNonZeroWinding (false);
  1609. clip = clip->clipToPath (p, AffineTransform::identity);
  1610. }
  1611. }
  1612. return clip != nullptr;
  1613. }
  1614. void clipToPath (const Path& p, const AffineTransform& t)
  1615. {
  1616. if (clip != nullptr)
  1617. {
  1618. cloneClipIfMultiplyReferenced();
  1619. clip = clip->clipToPath (p, transform.getTransformWith (t));
  1620. }
  1621. }
  1622. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
  1623. {
  1624. if (clip != nullptr)
  1625. {
  1626. Path p;
  1627. p.addRectangle (sourceImage.getBounds());
  1628. clipToPath (p, t);
  1629. if (sourceImage.hasAlphaChannel() && clip != nullptr)
  1630. {
  1631. cloneClipIfMultiplyReferenced();
  1632. clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
  1633. }
  1634. }
  1635. }
  1636. bool clipRegionIntersects (const Rectangle<int>& r) const
  1637. {
  1638. return clip != nullptr
  1639. && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
  1640. : getClipBounds().intersects (r));
  1641. }
  1642. Rectangle<int> getClipBounds() const
  1643. {
  1644. return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
  1645. : Rectangle<int>();
  1646. }
  1647. SavedState* beginTransparencyLayer (float opacity)
  1648. {
  1649. SavedState* const s = new SavedState (*this);
  1650. if (clip != nullptr)
  1651. {
  1652. const Rectangle<int> clipBounds (clip->getClipBounds());
  1653. state->flush();
  1654. s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
  1655. s->previousTarget = new Target (state->target);
  1656. state->target = Target (state->target.context, *OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
  1657. s->transparencyLayerAlpha = opacity;
  1658. s->cloneClipIfMultiplyReferenced();
  1659. s->state->target.makeActive();
  1660. }
  1661. return s;
  1662. }
  1663. void endTransparencyLayer (SavedState& finishedLayerState)
  1664. {
  1665. if (clip != nullptr)
  1666. {
  1667. jassert (finishedLayerState.previousTarget != nullptr);
  1668. state->flush();
  1669. state->target = *finishedLayerState.previousTarget;
  1670. finishedLayerState.previousTarget = nullptr;
  1671. state->target.makeActive();
  1672. const Rectangle<int> clipBounds (clip->getClipBounds());
  1673. clip->drawImage (finishedLayerState.transparencyLayer,
  1674. AffineTransform::translation ((float) clipBounds.getX(), (float) clipBounds.getY()),
  1675. finishedLayerState.transparencyLayerAlpha, clipBounds, nullptr);
  1676. }
  1677. }
  1678. //==============================================================================
  1679. void fillRect (const Rectangle<int>& r, const bool replaceContents)
  1680. {
  1681. if (clip != nullptr)
  1682. {
  1683. if (transform.isOnlyTranslated)
  1684. {
  1685. clip->fillRect (r.translated (transform.xOffset, transform.yOffset),
  1686. getFillType(), replaceContents);
  1687. }
  1688. else
  1689. {
  1690. Path p;
  1691. p.addRectangle (r);
  1692. fillPath (p, AffineTransform::identity);
  1693. }
  1694. }
  1695. }
  1696. void fillRect (const Rectangle<float>& r)
  1697. {
  1698. if (clip != nullptr)
  1699. {
  1700. if (transform.isOnlyTranslated)
  1701. {
  1702. const Rectangle<float> c (r.translated ((float) transform.xOffset, (float) transform.yOffset)
  1703. .getIntersection (clip->getClipBounds().toFloat()));
  1704. if (! c.isEmpty())
  1705. clip->fillRect (c, getFillType());
  1706. }
  1707. else
  1708. {
  1709. Path p;
  1710. p.addRectangle (r);
  1711. fillPath (p, AffineTransform::identity);
  1712. }
  1713. }
  1714. }
  1715. void fillPath (const Path& path, const AffineTransform& t)
  1716. {
  1717. if (clip != nullptr)
  1718. {
  1719. EdgeTable et (clip->getClipBounds(), path, transform.getTransformWith (t));
  1720. fillEdgeTable (et);
  1721. }
  1722. }
  1723. void drawGlyph (int glyphNumber, const AffineTransform& t)
  1724. {
  1725. if (clip != nullptr)
  1726. {
  1727. if (transform.isOnlyTranslated && t.isOnlyTranslation())
  1728. {
  1729. RenderingHelpers::GlyphCache <RenderingHelpers::CachedGlyphEdgeTable <SavedState>, SavedState>::getInstance()
  1730. .drawGlyph (*this, font, glyphNumber,
  1731. transform.xOffset + t.getTranslationX(),
  1732. transform.yOffset + t.getTranslationY());
  1733. }
  1734. else
  1735. {
  1736. const float fontHeight = font.getHeight();
  1737. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph
  1738. (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  1739. .followedBy (t))));
  1740. if (et != nullptr)
  1741. fillEdgeTable (*et);
  1742. }
  1743. }
  1744. }
  1745. void fillEdgeTable (const EdgeTable& et, const float x, const int y)
  1746. {
  1747. if (clip != nullptr)
  1748. {
  1749. EdgeTable et2 (et);
  1750. et2.translate (x, y);
  1751. fillEdgeTable (et2);
  1752. }
  1753. }
  1754. void drawLine (const Line <float>& line)
  1755. {
  1756. Path p;
  1757. p.addLineSegment (line, 1.0f);
  1758. fillPath (p, AffineTransform::identity);
  1759. }
  1760. //==============================================================================
  1761. void drawImage (const Image& image, const AffineTransform& trans)
  1762. {
  1763. if (clip == nullptr || fillType.colour.isTransparent())
  1764. return;
  1765. const Rectangle<int> clipBounds (clip->getClipBounds());
  1766. const AffineTransform t (transform.getTransformWith (trans));
  1767. const float alpha = fillType.colour.getFloatAlpha();
  1768. if (t.isOnlyTranslation())
  1769. {
  1770. int tx = (int) (t.getTranslationX() * 256.0f);
  1771. int ty = (int) (t.getTranslationY() * 256.0f);
  1772. if (((tx | ty) & 0xf8) == 0)
  1773. {
  1774. tx = ((tx + 128) >> 8);
  1775. ty = ((ty + 128) >> 8);
  1776. clip->drawImage (image, t, alpha, Rectangle<int> (tx, ty, image.getWidth(), image.getHeight()), nullptr);
  1777. return;
  1778. }
  1779. }
  1780. if (! t.isSingularity())
  1781. {
  1782. Path p;
  1783. p.addRectangle (image.getBounds());
  1784. EdgeTable et (clipBounds, p, t);
  1785. clip->drawImage (image, t, alpha, clipBounds, &et);
  1786. }
  1787. }
  1788. void setFillType (const FillType& newFill)
  1789. {
  1790. fillType = newFill;
  1791. state->textureCache.resetGradient();
  1792. }
  1793. //==============================================================================
  1794. ClipRegionBase::Ptr clip;
  1795. RenderingHelpers::TranslationOrTransform transform;
  1796. Font font;
  1797. FillType fillType;
  1798. Graphics::ResamplingQuality interpolationQuality;
  1799. GLState* state;
  1800. private:
  1801. float transparencyLayerAlpha;
  1802. Image transparencyLayer;
  1803. ScopedPointer<Target> previousTarget;
  1804. void cloneClipIfMultiplyReferenced()
  1805. {
  1806. if (clip->getReferenceCount() > 1)
  1807. clip = clip->clone();
  1808. }
  1809. FillType getFillType() const
  1810. {
  1811. return fillType.transformed (transform.getTransform());
  1812. }
  1813. void fillEdgeTable (EdgeTable& et) const
  1814. {
  1815. clip->fillEdgeTable (et, getFillType());
  1816. }
  1817. SavedState& operator= (const SavedState&);
  1818. };
  1819. //==============================================================================
  1820. class ShaderContext : public LowLevelGraphicsContext
  1821. {
  1822. public:
  1823. ShaderContext (const Target& target)
  1824. : glState (target), stack (new SavedState (&glState))
  1825. {}
  1826. bool isVectorDevice() const { return false; }
  1827. void setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
  1828. void addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
  1829. float getScaleFactor() { return stack->transform.getScaleFactor(); }
  1830. Rectangle<int> getClipBounds() const { return stack->getClipBounds(); }
  1831. bool isClipEmpty() const { return stack->clip == nullptr; }
  1832. bool clipRegionIntersects (const Rectangle<int>& r) { return stack->clipRegionIntersects (r); }
  1833. bool clipToRectangle (const Rectangle<int>& r) { return stack->clipToRectangle (r); }
  1834. bool clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
  1835. void excludeClipRectangle (const Rectangle<int>& r) { stack->excludeClipRectangle (r); }
  1836. void clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
  1837. void clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
  1838. void saveState() { stack.save(); }
  1839. void restoreState() { stack.restore(); }
  1840. void beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
  1841. void endTransparencyLayer() { stack.endTransparencyLayer(); }
  1842. void setFill (const FillType& fillType) { stack->setFillType (fillType); }
  1843. void setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
  1844. void setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
  1845. void fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
  1846. void fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
  1847. void drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
  1848. void drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
  1849. void drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
  1850. void drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
  1851. void drawLine (const Line <float>& line) { stack->drawLine (line); }
  1852. void setFont (const Font& newFont) { stack->font = newFont; }
  1853. const Font& getFont() { return stack->font; }
  1854. private:
  1855. GLState glState;
  1856. RenderingHelpers::SavedStateStack<SavedState> stack;
  1857. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ShaderContext)
  1858. };
  1859. #endif
  1860. class NonShaderContext : public LowLevelGraphicsSoftwareRenderer
  1861. {
  1862. public:
  1863. NonShaderContext (const Target& target_, const Image& image_)
  1864. : LowLevelGraphicsSoftwareRenderer (image_), target (target_), image (image_)
  1865. {}
  1866. ~NonShaderContext()
  1867. {
  1868. JUCE_CHECK_OPENGL_ERROR
  1869. const GLuint previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget();
  1870. #if ! JUCE_ANDROID
  1871. target.context.extensions.glActiveTexture (GL_TEXTURE0);
  1872. glEnable (GL_TEXTURE_2D);
  1873. clearGLError();
  1874. #endif
  1875. OpenGLTexture texture;
  1876. texture.loadImage (image);
  1877. texture.bind();
  1878. target.makeActive();
  1879. target.context.copyTexture (target.bounds, Rectangle<int> (texture.getWidth(),
  1880. texture.getHeight()),
  1881. target.bounds.getWidth(), target.bounds.getHeight());
  1882. glBindTexture (GL_TEXTURE_2D, 0);
  1883. #if JUCE_WINDOWS
  1884. if (target.context.extensions.glBindFramebuffer != nullptr)
  1885. #endif
  1886. target.context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget);
  1887. JUCE_CHECK_OPENGL_ERROR
  1888. }
  1889. private:
  1890. Target target;
  1891. Image image;
  1892. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NonShaderContext)
  1893. };
  1894. LowLevelGraphicsContext* createOpenGLContext (const Target&);
  1895. LowLevelGraphicsContext* createOpenGLContext (const Target& target)
  1896. {
  1897. #if JUCE_USE_OPENGL_SHADERS
  1898. if (target.context.areShadersAvailable())
  1899. return new ShaderContext (target);
  1900. #endif
  1901. Image tempImage (Image::ARGB, target.bounds.getWidth(), target.bounds.getHeight(), true, SoftwareImageType());
  1902. return new NonShaderContext (target, tempImage);
  1903. }
  1904. }
  1905. //==============================================================================
  1906. LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, int width, int height)
  1907. {
  1908. return createOpenGLGraphicsContext (context, context.getFrameBufferID(), width, height);
  1909. }
  1910. LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, OpenGLFrameBuffer& target)
  1911. {
  1912. return OpenGLRendering::createOpenGLContext (OpenGLRendering::Target (context, target, Point<int>()));
  1913. }
  1914. LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, unsigned int frameBufferID, int width, int height)
  1915. {
  1916. using namespace OpenGLRendering;
  1917. return OpenGLRendering::createOpenGLContext (OpenGLRendering::Target (context, frameBufferID, width, height));
  1918. }