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.

3311 lines
125KB

  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. //==============================================================================
  19. struct OpenGLTarget
  20. {
  21. OpenGLTarget (OpenGLContext& context_, GLuint frameBufferID_, int width, int height) noexcept
  22. : context (context_), frameBuffer (nullptr), frameBufferID (frameBufferID_), bounds (width, height)
  23. {}
  24. OpenGLTarget (OpenGLContext& context_, OpenGLFrameBuffer& frameBuffer_, const Point<int>& origin) noexcept
  25. : context (context_), frameBuffer (&frameBuffer_), frameBufferID (0),
  26. bounds (origin.x, origin.y, frameBuffer_.getWidth(), frameBuffer_.getHeight())
  27. {}
  28. OpenGLTarget (const OpenGLTarget& other) noexcept
  29. : context (other.context), frameBuffer (other.frameBuffer),
  30. frameBufferID (other.frameBufferID), bounds (other.bounds)
  31. {}
  32. OpenGLTarget& operator= (const OpenGLTarget& other)
  33. {
  34. frameBuffer = other.frameBuffer;
  35. frameBufferID = other.frameBufferID;
  36. bounds = other.bounds;
  37. return *this;
  38. }
  39. void makeActiveFor2D() const
  40. {
  41. if (frameBuffer != nullptr)
  42. frameBuffer->makeCurrentRenderingTarget();
  43. else
  44. context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferID);
  45. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  46. applyFlippedMatrix (bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
  47. #else
  48. glViewport (0, 0, bounds.getWidth(), bounds.getHeight());
  49. #endif
  50. glDisable (GL_DEPTH_TEST);
  51. }
  52. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  53. void scissor (Rectangle<int> r) const
  54. {
  55. r -= bounds.getPosition();
  56. OpenGLHelpers::enableScissorTest (r.withY (bounds.getHeight() - r.getBottom()));
  57. }
  58. static void applyFlippedMatrix (const int x, const int y, const int width, const int height)
  59. {
  60. glMatrixMode (GL_PROJECTION);
  61. glLoadIdentity();
  62. #if JUCE_OPENGL_ES
  63. glOrthof ((GLfloat) x, (GLfloat) (x + width), (GLfloat) (y + height), (GLfloat) y, 0.0f, 1.0f);
  64. #else
  65. glOrtho (x, x + width, y + height, y, 0, 1);
  66. #endif
  67. glViewport (0, 0, width, height);
  68. }
  69. #endif
  70. OpenGLContext& context;
  71. OpenGLFrameBuffer* frameBuffer;
  72. GLuint frameBufferID;
  73. Rectangle<int> bounds;
  74. };
  75. //==============================================================================
  76. class PositionedTexture
  77. {
  78. public:
  79. PositionedTexture (OpenGLTexture& texture, const EdgeTable& et, const Rectangle<int>& clip_)
  80. : clip (clip_.getIntersection (et.getMaximumBounds()))
  81. {
  82. if (clip.contains (et.getMaximumBounds()))
  83. {
  84. createMap (texture, et);
  85. }
  86. else
  87. {
  88. EdgeTable et2 (clip);
  89. et2.clipToEdgeTable (et);
  90. createMap (texture, et2);
  91. }
  92. }
  93. PositionedTexture (GLuint textureID_, const Rectangle<int> area_, const Rectangle<int> clip_) noexcept
  94. : textureID (textureID_), area (area_), clip (clip_)
  95. {}
  96. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  97. template <typename ValueType>
  98. void getTextureCoordAt (ValueType x, ValueType y, GLfloat& resultX, GLfloat& resultY) const noexcept
  99. {
  100. resultX = (x - area.getX()) / (float) area.getWidth();
  101. resultY = (area.getBottom() - y) / (float) area.getHeight();
  102. }
  103. void prepareTextureCoords (const Rectangle<int>* const area, GLfloat* const textureCoords) const noexcept
  104. {
  105. if (area != nullptr)
  106. {
  107. getTextureCoordAt (area->getX(), area->getY(), textureCoords[0], textureCoords[1]);
  108. getTextureCoordAt (area->getRight(), area->getY(), textureCoords[2], textureCoords[3]);
  109. getTextureCoordAt (area->getX(), area->getBottom(), textureCoords[4], textureCoords[5]);
  110. getTextureCoordAt (area->getRight(), area->getBottom(), textureCoords[6], textureCoords[7]);
  111. }
  112. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  113. }
  114. #endif
  115. GLuint textureID;
  116. Rectangle<int> area, clip;
  117. private:
  118. void createMap (OpenGLTexture& texture, const EdgeTable& et)
  119. {
  120. EdgeTableAlphaMap alphaMap (et);
  121. texture.loadAlpha (alphaMap.data, alphaMap.area.getWidth(), alphaMap.area.getHeight());
  122. textureID = texture.getTextureID();
  123. area = alphaMap.area;
  124. }
  125. struct EdgeTableAlphaMap
  126. {
  127. EdgeTableAlphaMap (const EdgeTable& et)
  128. : area (et.getMaximumBounds().withSize (nextPowerOfTwo (et.getMaximumBounds().getWidth()),
  129. nextPowerOfTwo (et.getMaximumBounds().getHeight())))
  130. {
  131. data.calloc (area.getWidth() * area.getHeight());
  132. et.iterate (*this);
  133. }
  134. inline void setEdgeTableYPos (const int y) noexcept
  135. {
  136. currentLine = data + (area.getBottom() - 1 - y) * area.getWidth() - area.getX();
  137. }
  138. inline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
  139. {
  140. currentLine[x] = (uint8) alphaLevel;
  141. }
  142. inline void handleEdgeTablePixelFull (const int x) const noexcept
  143. {
  144. currentLine[x] = 255;
  145. }
  146. inline void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept
  147. {
  148. memset (currentLine + x, (uint8) alphaLevel, width);
  149. }
  150. inline void handleEdgeTableLineFull (int x, int width) const noexcept
  151. {
  152. memset (currentLine + x, 255, width);
  153. }
  154. HeapBlock<uint8> data;
  155. const Rectangle<int> area;
  156. private:
  157. uint8* currentLine;
  158. JUCE_DECLARE_NON_COPYABLE (EdgeTableAlphaMap);
  159. };
  160. };
  161. //==============================================================================
  162. #if JUCE_USE_OPENGL_SHADERS
  163. class ShaderPrograms : public ReferenceCountedObject
  164. {
  165. public:
  166. ShaderPrograms (OpenGLContext& context)
  167. : solidColourProgram (context),
  168. solidColourMasked (context),
  169. radialGradient (context),
  170. radialGradientMasked (context),
  171. linearGradient1 (context),
  172. linearGradient1Masked (context),
  173. linearGradient2 (context),
  174. linearGradient2Masked (context),
  175. image (context),
  176. imageMasked (context),
  177. tiledImage (context),
  178. tiledImageMasked (context),
  179. copyTexture (context),
  180. maskTexture (context)
  181. {}
  182. typedef ReferenceCountedObjectPtr<ShaderPrograms> Ptr;
  183. //==============================================================================
  184. struct ShaderProgramHolder
  185. {
  186. ShaderProgramHolder (OpenGLContext& context, const char* fragmentShader)
  187. : program (context)
  188. {
  189. JUCE_CHECK_OPENGL_ERROR
  190. program.addShader ("attribute vec2 position;"
  191. "attribute vec4 colour;"
  192. "uniform vec4 screenBounds;"
  193. "varying " JUCE_MEDIUMP " vec4 frontColour;"
  194. "varying " JUCE_HIGHP " vec2 pixelPos;"
  195. "void main()"
  196. "{"
  197. " frontColour = colour;"
  198. " vec2 adjustedPos = position - screenBounds.xy;"
  199. " pixelPos = adjustedPos;"
  200. " vec2 scaledPos = adjustedPos / screenBounds.zw;"
  201. " gl_Position = vec4 (scaledPos.x - 1.0, 1.0 - scaledPos.y, 0, 1.0);"
  202. "}", GL_VERTEX_SHADER);
  203. program.addShader (fragmentShader, GL_FRAGMENT_SHADER);
  204. program.link();
  205. JUCE_CHECK_OPENGL_ERROR
  206. }
  207. OpenGLShaderProgram program;
  208. };
  209. struct ShaderBase : public ShaderProgramHolder
  210. {
  211. ShaderBase (OpenGLContext& context, const char* fragmentShader)
  212. : ShaderProgramHolder (context, fragmentShader),
  213. positionAttribute (program, "position"),
  214. colourAttribute (program, "colour"),
  215. screenBounds (program, "screenBounds")
  216. {}
  217. void set2DBounds (const Rectangle<float>& bounds)
  218. {
  219. screenBounds.set (bounds.getX(), bounds.getY(), 0.5f * bounds.getWidth(), 0.5f * bounds.getHeight());
  220. }
  221. void bindAttributes (OpenGLContext& context)
  222. {
  223. context.extensions.glVertexAttribPointer (positionAttribute.attributeID, 2, GL_SHORT, GL_FALSE, 8, (void*) 0);
  224. context.extensions.glVertexAttribPointer (colourAttribute.attributeID, 4, GL_UNSIGNED_BYTE, GL_TRUE, 8, (void*) 4);
  225. context.extensions.glEnableVertexAttribArray (positionAttribute.attributeID);
  226. context.extensions.glEnableVertexAttribArray (colourAttribute.attributeID);
  227. }
  228. void unbindAttributes (OpenGLContext& context)
  229. {
  230. context.extensions.glDisableVertexAttribArray (positionAttribute.attributeID);
  231. context.extensions.glDisableVertexAttribArray (colourAttribute.attributeID);
  232. }
  233. OpenGLShaderProgram::Attribute positionAttribute, colourAttribute;
  234. private:
  235. OpenGLShaderProgram::Uniform screenBounds;
  236. };
  237. struct MaskedShaderParams
  238. {
  239. MaskedShaderParams (OpenGLShaderProgram& program)
  240. : maskTexture (program, "maskTexture"),
  241. maskBounds (program, "maskBounds")
  242. {}
  243. void setBounds (const Rectangle<int>& area, const OpenGLTarget& target, const GLint textureIndex) const
  244. {
  245. maskTexture.set (textureIndex);
  246. maskBounds.set (area.getX() - target.bounds.getX(),
  247. area.getY() - target.bounds.getY(),
  248. area.getWidth(), area.getHeight());
  249. }
  250. OpenGLShaderProgram::Uniform maskTexture, maskBounds;
  251. };
  252. //==============================================================================
  253. #define JUCE_DECLARE_VARYING_COLOUR "varying " JUCE_MEDIUMP " vec4 frontColour;"
  254. #define JUCE_DECLARE_VARYING_PIXELPOS "varying " JUCE_HIGHP " vec2 pixelPos;"
  255. struct SolidColourProgram : public ShaderBase
  256. {
  257. SolidColourProgram (OpenGLContext& context)
  258. : ShaderBase (context, JUCE_DECLARE_VARYING_COLOUR
  259. "void main()"
  260. "{"
  261. " gl_FragColor = frontColour;"
  262. "}")
  263. {}
  264. };
  265. #if JUCE_ANDROID
  266. #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"
  267. #else
  268. #define JUCE_DECLARE_SWIZZLE_FUNCTION "\n" JUCE_MEDIUMP " vec4 swizzleRGBOrder (in " JUCE_MEDIUMP " vec4 c) { return c; }\n"
  269. #endif
  270. #define JUCE_DECLARE_MASK_UNIFORMS "uniform sampler2D maskTexture;" \
  271. "uniform ivec4 maskBounds;"
  272. #define JUCE_FRAGCOORD_TO_MASK_POS "vec2 ((pixelPos.x - float (maskBounds.x)) / float (maskBounds.z)," \
  273. "1.0 - (pixelPos.y - float (maskBounds.y)) / float (maskBounds.w))"
  274. #define JUCE_GET_MASK_ALPHA "texture2D (maskTexture, " JUCE_FRAGCOORD_TO_MASK_POS ").a"
  275. struct SolidColourMaskedProgram : public ShaderBase
  276. {
  277. SolidColourMaskedProgram (OpenGLContext& context)
  278. : ShaderBase (context,
  279. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS
  280. "void main()"
  281. "{"
  282. "gl_FragColor = frontColour * " JUCE_GET_MASK_ALPHA ";"
  283. "}"),
  284. maskParams (program)
  285. {}
  286. MaskedShaderParams maskParams;
  287. };
  288. //==============================================================================
  289. struct RadialGradientParams
  290. {
  291. RadialGradientParams (OpenGLShaderProgram& program)
  292. : gradientTexture (program, "gradientTexture"),
  293. matrix (program, "matrix")
  294. {}
  295. void setMatrix (const Point<float>& p1, const Point<float>& p2, const Point<float>& p3)
  296. {
  297. const AffineTransform t (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  298. p2.x, p2.y, 1.0f, 0.0f,
  299. p3.x, p3.y, 0.0f, 1.0f));
  300. const GLfloat m[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  301. matrix.set (m, 6);
  302. }
  303. OpenGLShaderProgram::Uniform gradientTexture, matrix;
  304. };
  305. #define JUCE_DECLARE_MATRIX_UNIFORM "uniform " JUCE_HIGHP " float matrix[6];"
  306. #define JUCE_DECLARE_RADIAL_UNIFORMS "uniform sampler2D gradientTexture;" JUCE_DECLARE_MATRIX_UNIFORM
  307. #define JUCE_MATRIX_TIMES_FRAGCOORD "(mat2 (matrix[0], matrix[3], matrix[1], matrix[4]) * pixelPos" \
  308. " + vec2 (matrix[2], matrix[5]))"
  309. #define JUCE_GET_TEXTURE_COLOUR "(frontColour.a * swizzleRGBOrder (texture2D (gradientTexture, vec2 (gradientPos, 0.5))))"
  310. struct RadialGradientProgram : public ShaderBase
  311. {
  312. RadialGradientProgram (OpenGLContext& context)
  313. : ShaderBase (context, JUCE_DECLARE_VARYING_PIXELPOS
  314. JUCE_DECLARE_RADIAL_UNIFORMS JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_SWIZZLE_FUNCTION
  315. "void main()"
  316. "{"
  317. JUCE_MEDIUMP " float gradientPos = length (" JUCE_MATRIX_TIMES_FRAGCOORD ");"
  318. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  319. "}"),
  320. gradientParams (program)
  321. {}
  322. RadialGradientParams gradientParams;
  323. };
  324. struct RadialGradientMaskedProgram : public ShaderBase
  325. {
  326. RadialGradientMaskedProgram (OpenGLContext& context)
  327. : ShaderBase (context, JUCE_DECLARE_VARYING_PIXELPOS
  328. JUCE_DECLARE_RADIAL_UNIFORMS JUCE_DECLARE_VARYING_COLOUR
  329. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  330. "void main()"
  331. "{"
  332. JUCE_MEDIUMP " float gradientPos = length (" JUCE_MATRIX_TIMES_FRAGCOORD ");"
  333. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  334. "}"),
  335. gradientParams (program),
  336. maskParams (program)
  337. {}
  338. RadialGradientParams gradientParams;
  339. MaskedShaderParams maskParams;
  340. };
  341. //==============================================================================
  342. struct LinearGradientParams
  343. {
  344. LinearGradientParams (OpenGLShaderProgram& program)
  345. : gradientTexture (program, "gradientTexture"),
  346. gradientInfo (program, "gradientInfo")
  347. {}
  348. OpenGLShaderProgram::Uniform gradientTexture, gradientInfo;
  349. };
  350. #define JUCE_DECLARE_LINEAR_UNIFORMS "uniform sampler2D gradientTexture;" \
  351. "uniform " JUCE_MEDIUMP " vec4 gradientInfo;" \
  352. JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS
  353. #define JUCE_CALC_LINEAR_GRAD_POS1 JUCE_MEDIUMP " float gradientPos = (pixelPos.y - (gradientInfo.y + (gradientInfo.z * (pixelPos.x - gradientInfo.x)))) / gradientInfo.w;"
  354. #define JUCE_CALC_LINEAR_GRAD_POS2 JUCE_MEDIUMP " float gradientPos = (pixelPos.x - (gradientInfo.x + (gradientInfo.z * (pixelPos.y - gradientInfo.y)))) / gradientInfo.w;"
  355. struct LinearGradient1Program : public ShaderBase
  356. {
  357. LinearGradient1Program (OpenGLContext& context)
  358. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  359. JUCE_DECLARE_SWIZZLE_FUNCTION
  360. "void main()"
  361. "{"
  362. JUCE_CALC_LINEAR_GRAD_POS1
  363. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  364. "}"),
  365. gradientParams (program)
  366. {}
  367. LinearGradientParams gradientParams;
  368. };
  369. struct LinearGradient1MaskedProgram : public ShaderBase
  370. {
  371. LinearGradient1MaskedProgram (OpenGLContext& context)
  372. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  373. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  374. "void main()"
  375. "{"
  376. JUCE_CALC_LINEAR_GRAD_POS1
  377. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  378. "}"),
  379. gradientParams (program),
  380. maskParams (program)
  381. {}
  382. LinearGradientParams gradientParams;
  383. MaskedShaderParams maskParams;
  384. };
  385. struct LinearGradient2Program : public ShaderBase
  386. {
  387. LinearGradient2Program (OpenGLContext& context)
  388. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  389. JUCE_DECLARE_SWIZZLE_FUNCTION
  390. "void main()"
  391. "{"
  392. JUCE_CALC_LINEAR_GRAD_POS2
  393. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  394. "}"),
  395. gradientParams (program)
  396. {}
  397. LinearGradientParams gradientParams;
  398. };
  399. struct LinearGradient2MaskedProgram : public ShaderBase
  400. {
  401. LinearGradient2MaskedProgram (OpenGLContext& context)
  402. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  403. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  404. "void main()"
  405. "{"
  406. JUCE_CALC_LINEAR_GRAD_POS2
  407. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  408. "}"),
  409. gradientParams (program),
  410. maskParams (program)
  411. {}
  412. LinearGradientParams gradientParams;
  413. MaskedShaderParams maskParams;
  414. };
  415. //==============================================================================
  416. struct ImageParams
  417. {
  418. ImageParams (OpenGLShaderProgram& program)
  419. : imageTexture (program, "imageTexture"),
  420. matrix (program, "matrix"),
  421. imageLimits (program, "imageLimits")
  422. {}
  423. void setMatrix (const AffineTransform& trans,
  424. const int imageWidth, const int imageHeight,
  425. const float fullWidthProportion, const float fullHeightProportion,
  426. const float targetX, const float targetY) const
  427. {
  428. const AffineTransform t (trans.translated (-targetX, -targetY)
  429. .inverted().scaled (fullWidthProportion / imageWidth,
  430. fullHeightProportion / imageHeight));
  431. const GLfloat m[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  432. matrix.set (m, 6);
  433. const float halfPixelX = 0.5f / imageWidth;
  434. const float halfPixelY = 0.5f / imageHeight;
  435. imageLimits.set (halfPixelX, halfPixelY,
  436. fullWidthProportion - halfPixelX,
  437. fullHeightProportion - halfPixelY);
  438. }
  439. void setMatrix (const AffineTransform& trans, const OpenGLTextureFromImage& image,
  440. const float targetX, const float targetY) const
  441. {
  442. setMatrix (trans,
  443. image.imageWidth, image.imageHeight,
  444. image.fullWidthProportion, image.fullHeightProportion,
  445. targetX, targetY);
  446. }
  447. OpenGLShaderProgram::Uniform imageTexture, matrix, imageLimits;
  448. };
  449. #define JUCE_DECLARE_IMAGE_UNIFORMS "uniform sampler2D imageTexture;" \
  450. "uniform " JUCE_MEDIUMP " vec4 imageLimits;" \
  451. JUCE_DECLARE_MATRIX_UNIFORM JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS
  452. #define JUCE_GET_IMAGE_PIXEL "swizzleRGBOrder (texture2D (imageTexture, vec2 (texturePos.x, 1.0 - texturePos.y)))"
  453. #define JUCE_CLAMP_TEXTURE_COORD JUCE_HIGHP " vec2 texturePos = clamp (" JUCE_MATRIX_TIMES_FRAGCOORD ", imageLimits.xy, imageLimits.zw);"
  454. #define JUCE_MOD_TEXTURE_COORD JUCE_HIGHP " vec2 texturePos = clamp (mod (" JUCE_MATRIX_TIMES_FRAGCOORD ", imageLimits.zw + imageLimits.xy), imageLimits.xy, imageLimits.zw);"
  455. struct ImageProgram : public ShaderBase
  456. {
  457. ImageProgram (OpenGLContext& context)
  458. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  459. "void main()"
  460. "{"
  461. JUCE_CLAMP_TEXTURE_COORD
  462. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL ";"
  463. "}"),
  464. imageParams (program)
  465. {}
  466. ImageParams imageParams;
  467. };
  468. struct ImageMaskedProgram : public ShaderBase
  469. {
  470. ImageMaskedProgram (OpenGLContext& context)
  471. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  472. "void main()"
  473. "{"
  474. JUCE_CLAMP_TEXTURE_COORD
  475. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL " * " JUCE_GET_MASK_ALPHA ";"
  476. "}"),
  477. imageParams (program),
  478. maskParams (program)
  479. {}
  480. ImageParams imageParams;
  481. MaskedShaderParams maskParams;
  482. };
  483. struct TiledImageProgram : public ShaderBase
  484. {
  485. TiledImageProgram (OpenGLContext& context)
  486. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  487. "void main()"
  488. "{"
  489. JUCE_MOD_TEXTURE_COORD
  490. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL ";"
  491. "}"),
  492. imageParams (program)
  493. {}
  494. ImageParams imageParams;
  495. };
  496. struct TiledImageMaskedProgram : public ShaderBase
  497. {
  498. TiledImageMaskedProgram (OpenGLContext& context)
  499. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  500. "void main()"
  501. "{"
  502. JUCE_MOD_TEXTURE_COORD
  503. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL " * " JUCE_GET_MASK_ALPHA ";"
  504. "}"),
  505. imageParams (program),
  506. maskParams (program)
  507. {}
  508. ImageParams imageParams;
  509. MaskedShaderParams maskParams;
  510. };
  511. struct CopyTextureProgram : public ShaderBase
  512. {
  513. CopyTextureProgram (OpenGLContext& context)
  514. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  515. "void main()"
  516. "{"
  517. JUCE_MOD_TEXTURE_COORD
  518. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL ";"
  519. "}"),
  520. imageParams (program)
  521. {}
  522. ImageParams imageParams;
  523. };
  524. struct MaskTextureProgram : public ShaderBase
  525. {
  526. MaskTextureProgram (OpenGLContext& context)
  527. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  528. "void main()"
  529. "{"
  530. JUCE_HIGHP " vec2 texturePos = " JUCE_MATRIX_TIMES_FRAGCOORD ";"
  531. JUCE_HIGHP " float roundingError = 0.00001;"
  532. "if (texturePos.x >= imageLimits.x - roundingError"
  533. "&& texturePos.y >= imageLimits.y - roundingError"
  534. "&& texturePos.x <= imageLimits.z + roundingError"
  535. "&& texturePos.y <= imageLimits.w + roundingError)"
  536. "gl_FragColor = frontColour * " JUCE_GET_IMAGE_PIXEL ".a;"
  537. "else "
  538. "gl_FragColor = vec4 (0, 0, 0, 0);"
  539. "}"),
  540. imageParams (program)
  541. {}
  542. ImageParams imageParams;
  543. };
  544. SolidColourProgram solidColourProgram;
  545. SolidColourMaskedProgram solidColourMasked;
  546. RadialGradientProgram radialGradient;
  547. RadialGradientMaskedProgram radialGradientMasked;
  548. LinearGradient1Program linearGradient1;
  549. LinearGradient1MaskedProgram linearGradient1Masked;
  550. LinearGradient2Program linearGradient2;
  551. LinearGradient2MaskedProgram linearGradient2Masked;
  552. ImageProgram image;
  553. ImageMaskedProgram imageMasked;
  554. TiledImageProgram tiledImage;
  555. TiledImageMaskedProgram tiledImageMasked;
  556. CopyTextureProgram copyTexture;
  557. MaskTextureProgram maskTexture;
  558. };
  559. #endif
  560. //==============================================================================
  561. struct StateHelpers
  562. {
  563. struct ActiveTextures;
  564. //==============================================================================
  565. struct BlendingMode
  566. {
  567. BlendingMode() noexcept
  568. : blendingEnabled (false), srcFunction (0), dstFunction (0)
  569. {}
  570. void resync() noexcept
  571. {
  572. glDisable (GL_BLEND);
  573. srcFunction = dstFunction = 0;
  574. }
  575. template <class QuadQueueType>
  576. void setPremultipliedBlendingMode (QuadQueueType& quadQueue) noexcept
  577. {
  578. setBlendFunc (quadQueue, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  579. }
  580. template <class QuadQueueType>
  581. void setBlendFunc (QuadQueueType& quadQueue, GLenum src, GLenum dst)
  582. {
  583. if (! blendingEnabled)
  584. {
  585. quadQueue.flush();
  586. blendingEnabled = true;
  587. glEnable (GL_BLEND);
  588. }
  589. if (srcFunction != src || dstFunction != dst)
  590. {
  591. quadQueue.flush();
  592. srcFunction = src;
  593. dstFunction = dst;
  594. glBlendFunc (src, dst);
  595. }
  596. }
  597. template <class QuadQueueType>
  598. void disableBlend (QuadQueueType& quadQueue) noexcept
  599. {
  600. if (blendingEnabled)
  601. {
  602. quadQueue.flush();
  603. blendingEnabled = false;
  604. glDisable (GL_BLEND);
  605. }
  606. }
  607. template <class QuadQueueType>
  608. void setBlendMode (QuadQueueType& quadQueue, const bool replaceExistingContents) noexcept
  609. {
  610. if (replaceExistingContents)
  611. disableBlend (quadQueue);
  612. else
  613. setPremultipliedBlendingMode (quadQueue);
  614. }
  615. private:
  616. bool blendingEnabled;
  617. GLenum srcFunction, dstFunction;
  618. };
  619. //==============================================================================
  620. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  621. struct CurrentColour
  622. {
  623. CurrentColour() noexcept
  624. : currentColour (0xffffffff)
  625. {}
  626. void resync() noexcept
  627. {
  628. currentColour = PixelARGB (0xffffffff);
  629. glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
  630. }
  631. void setPremultipliedColour (const Colour& c) noexcept
  632. {
  633. setColour (c.getPixelARGB());
  634. }
  635. void setColour (const float alpha) noexcept
  636. {
  637. const uint8 v = (uint8) jmin (255, (int) (alpha * 255.0f));
  638. setColour (PixelARGB (v, v, v, v));
  639. }
  640. void setColour (const PixelARGB& c) noexcept
  641. {
  642. if (currentColour.getARGB() != c.getARGB())
  643. {
  644. currentColour = c;
  645. glColor4f (c.getRed() / 255.0f, c.getGreen() / 255.0f,
  646. c.getBlue() / 255.0f, c.getAlpha() / 255.0f);
  647. }
  648. }
  649. void setSolidColour() noexcept
  650. {
  651. if (currentColour.getARGB() != 0xffffffff)
  652. {
  653. currentColour = PixelARGB (0xffffffff);
  654. glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
  655. }
  656. }
  657. private:
  658. PixelARGB currentColour;
  659. };
  660. #endif
  661. //==============================================================================
  662. template <class QuadQueueType>
  663. struct EdgeTableRenderer
  664. {
  665. EdgeTableRenderer (QuadQueueType& quadQueue_, const PixelARGB& colour_) noexcept
  666. : quadQueue (quadQueue_), colour (colour_)
  667. {}
  668. void setEdgeTableYPos (const int y) noexcept
  669. {
  670. currentY = y;
  671. }
  672. void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
  673. {
  674. PixelARGB c (colour);
  675. c.multiplyAlpha (alphaLevel);
  676. quadQueue.add (x, currentY, 1, 1, c);
  677. }
  678. void handleEdgeTablePixelFull (const int x) noexcept
  679. {
  680. quadQueue.add (x, currentY, 1, 1, colour);
  681. }
  682. void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept
  683. {
  684. PixelARGB c (colour);
  685. c.multiplyAlpha (alphaLevel);
  686. quadQueue.add (x, currentY, width, 1, c);
  687. }
  688. void handleEdgeTableLineFull (const int x, const int width) noexcept
  689. {
  690. quadQueue.add (x, currentY, width, 1, colour);
  691. }
  692. private:
  693. QuadQueueType& quadQueue;
  694. const PixelARGB colour;
  695. int currentY;
  696. JUCE_DECLARE_NON_COPYABLE (EdgeTableRenderer);
  697. };
  698. template <class QuadQueueType>
  699. struct FloatRectangleRenderer
  700. {
  701. FloatRectangleRenderer (QuadQueueType& quadQueue_, const PixelARGB& colour_) noexcept
  702. : quadQueue (quadQueue_), colour (colour_)
  703. {}
  704. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  705. {
  706. if (w > 0 && h > 0)
  707. {
  708. PixelARGB c (colour);
  709. c.multiplyAlpha (alpha);
  710. quadQueue.add (x, y, w, h, c);
  711. }
  712. }
  713. private:
  714. QuadQueueType& quadQueue;
  715. const PixelARGB colour;
  716. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  717. };
  718. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  719. struct QuadQueue
  720. {
  721. QuadQueue() noexcept
  722. : numIndices (0), numVertices (0), isActive (false)
  723. {}
  724. void prepare (ActiveTextures& activeTextures, CurrentColour& currentColour)
  725. {
  726. if (! isActive)
  727. {
  728. jassert (numIndices == 0 && numVertices == 0);
  729. activeTextures.disableTextures (*this);
  730. glEnableClientState (GL_COLOR_ARRAY);
  731. glVertexPointer (2, GL_SHORT, 0, vertices);
  732. glColorPointer (4, GL_UNSIGNED_BYTE, 0, colours);
  733. currentColour.setSolidColour();
  734. isActive = true; // (careful to do this last, as the preceding calls may change it)
  735. }
  736. }
  737. void add (const int x, const int y, const int w, const int h, const PixelARGB& colour) noexcept
  738. {
  739. jassert (isActive && w > 0 && h > 0);
  740. GLshort* const v = vertices + numVertices * 2;
  741. v[0] = v[4] = (GLshort) x;
  742. v[1] = v[3] = (GLshort) y;
  743. v[2] = v[6] = (GLshort) (x + w);
  744. v[5] = v[7] = (GLshort) (y + h);
  745. uint32* const c = colours + numVertices;
  746. c[0] = c[1] = c[2] = c[3] = colour.getInRGBAMemoryOrder();
  747. GLubyte* const i = indices + numIndices;
  748. i[0] = (GLubyte) numVertices;
  749. i[1] = i[3] = (GLubyte) (numVertices + 1);
  750. i[2] = i[4] = (GLubyte) (numVertices + 2);
  751. i[5] = (GLubyte) (numVertices + 3);
  752. numVertices += 4;
  753. numIndices += 6;
  754. if (numIndices > maxVerticesPerBlock - 6)
  755. draw();
  756. }
  757. void add (const Rectangle<float>& r, const PixelARGB& colour) noexcept
  758. {
  759. FloatRectangleRenderer<QuadQueue> frr (*this, colour);
  760. RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (frr);
  761. }
  762. void flush() noexcept
  763. {
  764. if (isActive)
  765. {
  766. if (numIndices > 0)
  767. draw();
  768. isActive = false;
  769. glDisableClientState (GL_COLOR_ARRAY);
  770. }
  771. }
  772. void add (const EdgeTable& et, const PixelARGB& colour)
  773. {
  774. EdgeTableRenderer<QuadQueue> etr (*this, colour);
  775. et.iterate (etr);
  776. }
  777. private:
  778. enum { maxVerticesPerBlock = 192 }; // must not go over 256 because the indices are 8-bit.
  779. GLshort vertices [maxVerticesPerBlock * 2];
  780. GLubyte indices [maxVerticesPerBlock];
  781. uint32 colours [maxVerticesPerBlock];
  782. int numIndices, numVertices;
  783. bool isActive;
  784. void draw() noexcept
  785. {
  786. glDrawElements (GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices);
  787. numIndices = 0;
  788. numVertices = 0;
  789. }
  790. };
  791. #endif
  792. //==============================================================================
  793. struct ActiveTextures
  794. {
  795. ActiveTextures (const OpenGLContext& context_) noexcept
  796. : texturesEnabled (0), currentActiveTexture (0), context (context_)
  797. {}
  798. void clear() noexcept
  799. {
  800. for (int i = 0; i < numElementsInArray (currentTextureID); ++i)
  801. currentTextureID[i] = 0;
  802. }
  803. void clearCurrent() noexcept
  804. {
  805. currentTextureID [currentActiveTexture] = 0;
  806. }
  807. template <class QuadQueueType>
  808. void setTexturesEnabled (QuadQueueType& quadQueue, const int textureIndexMask) noexcept
  809. {
  810. if (texturesEnabled != textureIndexMask)
  811. {
  812. quadQueue.flush();
  813. for (int i = 3; --i >= 0;)
  814. {
  815. if ((texturesEnabled & (1 << i)) != (textureIndexMask & (1 << i)))
  816. {
  817. setActiveTexture (i);
  818. JUCE_CHECK_OPENGL_ERROR
  819. #if ! JUCE_ANDROID
  820. if ((textureIndexMask & (1 << i)) != 0)
  821. glEnable (GL_TEXTURE_2D);
  822. else
  823. {
  824. glDisable (GL_TEXTURE_2D);
  825. currentTextureID[i] = 0;
  826. }
  827. JUCE_CHECK_OPENGL_ERROR
  828. #endif
  829. }
  830. }
  831. texturesEnabled = textureIndexMask;
  832. }
  833. }
  834. template <class QuadQueueType>
  835. void disableTextures (QuadQueueType& quadQueue) noexcept
  836. {
  837. setTexturesEnabled (quadQueue, 0);
  838. }
  839. template <class QuadQueueType>
  840. void setSingleTextureMode (QuadQueueType& quadQueue) noexcept
  841. {
  842. setTexturesEnabled (quadQueue, 1);
  843. setActiveTexture (0);
  844. }
  845. template <class QuadQueueType>
  846. void setTwoTextureMode (QuadQueueType& quadQueue, GLuint texture1, GLuint texture2)
  847. {
  848. JUCE_CHECK_OPENGL_ERROR
  849. setTexturesEnabled (quadQueue, 3);
  850. if (currentActiveTexture == 0)
  851. {
  852. bindTexture (texture1);
  853. setActiveTexture (1);
  854. bindTexture (texture2);
  855. }
  856. else
  857. {
  858. setActiveTexture (1);
  859. bindTexture (texture2);
  860. setActiveTexture (0);
  861. bindTexture (texture1);
  862. }
  863. JUCE_CHECK_OPENGL_ERROR
  864. }
  865. void setActiveTexture (const int index) noexcept
  866. {
  867. if (currentActiveTexture != index)
  868. {
  869. currentActiveTexture = index;
  870. context.extensions.glActiveTexture (GL_TEXTURE0 + index);
  871. JUCE_CHECK_OPENGL_ERROR
  872. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  873. context.extensions.glClientActiveTexture (GL_TEXTURE0 + index);
  874. JUCE_CHECK_OPENGL_ERROR
  875. #endif
  876. }
  877. }
  878. void bindTexture (const GLuint textureID) noexcept
  879. {
  880. if (currentTextureID [currentActiveTexture] != textureID)
  881. {
  882. currentTextureID [currentActiveTexture] = textureID;
  883. glBindTexture (GL_TEXTURE_2D, textureID);
  884. JUCE_CHECK_OPENGL_ERROR
  885. }
  886. else
  887. {
  888. #if JUCE_DEBUG
  889. GLint t = 0;
  890. glGetIntegerv (GL_TEXTURE_BINDING_2D, &t);
  891. jassert (t == (GLint) textureID);
  892. #endif
  893. }
  894. }
  895. private:
  896. GLuint currentTextureID [3];
  897. int texturesEnabled, currentActiveTexture;
  898. const OpenGLContext& context;
  899. ActiveTextures& operator= (const ActiveTextures&);
  900. };
  901. //==============================================================================
  902. struct TextureCache
  903. {
  904. TextureCache() noexcept
  905. : activeGradientIndex (0), gradientNeedsRefresh (true)
  906. {}
  907. OpenGLTexture* getTexture (ActiveTextures& activeTextures, int w, int h)
  908. {
  909. if (textures.size() < numTexturesToCache)
  910. {
  911. activeTextures.clear();
  912. return new OpenGLTexture();
  913. }
  914. for (int i = 0; i < numTexturesToCache - 2; ++i)
  915. {
  916. const OpenGLTexture* const t = textures.getUnchecked(i);
  917. if (t->getWidth() == w && t->getHeight() == h)
  918. return textures.removeAndReturn (i);
  919. }
  920. return textures.removeAndReturn (0);
  921. }
  922. void releaseTexture (ActiveTextures& activeTextures, OpenGLTexture* texture)
  923. {
  924. activeTextures.clearCurrent();
  925. textures.add (texture);
  926. }
  927. void resetGradient() noexcept
  928. {
  929. gradientNeedsRefresh = true;
  930. }
  931. void bindTextureForGradient (ActiveTextures& activeTextures, const ColourGradient& gradient)
  932. {
  933. if (gradientNeedsRefresh)
  934. {
  935. gradientNeedsRefresh = false;
  936. if (gradientTextures.size() < numGradientTexturesToCache)
  937. {
  938. activeGradientIndex = gradientTextures.size();
  939. activeTextures.clear();
  940. gradientTextures.add (new OpenGLTexture());
  941. }
  942. else
  943. {
  944. activeGradientIndex = (activeGradientIndex + 1) % numGradientTexturesToCache;
  945. }
  946. JUCE_CHECK_OPENGL_ERROR;
  947. PixelARGB lookup [gradientTextureSize];
  948. gradient.createLookupTable (lookup, gradientTextureSize);
  949. gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1);
  950. }
  951. activeTextures.bindTexture (gradientTextures.getUnchecked (activeGradientIndex)->getTextureID());
  952. }
  953. enum { gradientTextureSize = 256 };
  954. private:
  955. enum { numTexturesToCache = 8, numGradientTexturesToCache = 10 };
  956. OwnedArray<OpenGLTexture> textures, gradientTextures;
  957. int activeGradientIndex;
  958. bool gradientNeedsRefresh;
  959. };
  960. #if JUCE_USE_OPENGL_SHADERS
  961. //==============================================================================
  962. struct ShaderQuadQueue
  963. {
  964. ShaderQuadQueue (const OpenGLContext& context_) noexcept
  965. : context (context_), numVertices (0)
  966. {}
  967. ~ShaderQuadQueue() noexcept
  968. {
  969. static_jassert (sizeof (VertexInfo) == 8);
  970. context.extensions.glDeleteBuffers (2, buffers);
  971. }
  972. void initialise() noexcept
  973. {
  974. JUCE_CHECK_OPENGL_ERROR
  975. for (int i = 0, v = 0; i < numQuads * 6; i += 6, v += 4)
  976. {
  977. indexData[i] = (GLushort) v;
  978. indexData[i + 1] = indexData[i + 3] = (GLushort) (v + 1);
  979. indexData[i + 2] = indexData[i + 4] = (GLushort) (v + 2);
  980. indexData[i + 5] = (GLushort) (v + 3);
  981. }
  982. context.extensions.glGenBuffers (2, buffers);
  983. context.extensions.glBindBuffer (GL_ARRAY_BUFFER, buffers[0]);
  984. context.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
  985. context.extensions.glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indexData), indexData, GL_STATIC_DRAW);
  986. JUCE_CHECK_OPENGL_ERROR
  987. }
  988. void add (const int x, const int y, const int w, const int h, const PixelARGB& colour) noexcept
  989. {
  990. jassert (w > 0 && h > 0);
  991. VertexInfo* const v = vertexData + numVertices;
  992. v[0].x = v[2].x = (GLshort) x;
  993. v[0].y = v[1].y = (GLshort) y;
  994. v[1].x = v[3].x = (GLshort) (x + w);
  995. v[2].y = v[3].y = (GLshort) (y + h);
  996. const GLuint rgba = colour.getInRGBAMemoryOrder();
  997. v[0].colour = rgba;
  998. v[1].colour = rgba;
  999. v[2].colour = rgba;
  1000. v[3].colour = rgba;
  1001. numVertices += 4;
  1002. if (numVertices > numQuads * 4 - 4)
  1003. draw();
  1004. }
  1005. void add (const Rectangle<int>& r, const PixelARGB& colour) noexcept
  1006. {
  1007. add (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  1008. }
  1009. void add (const Rectangle<float>& r, const PixelARGB& colour) noexcept
  1010. {
  1011. FloatRectangleRenderer<ShaderQuadQueue> frr (*this, colour);
  1012. RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (frr);
  1013. }
  1014. void add (const RectangleList& list, const PixelARGB& colour) noexcept
  1015. {
  1016. for (RectangleList::Iterator i (list); i.next();)
  1017. add (*i.getRectangle(), colour);
  1018. }
  1019. void add (const RectangleList& list, const Rectangle<int>& clip, const PixelARGB& colour) noexcept
  1020. {
  1021. for (RectangleList::Iterator i (list); i.next();)
  1022. {
  1023. const Rectangle<int> r (i.getRectangle()->getIntersection (clip));
  1024. if (! r.isEmpty())
  1025. add (r, colour);
  1026. }
  1027. }
  1028. void add (const EdgeTable& et, const PixelARGB& colour)
  1029. {
  1030. EdgeTableRenderer<ShaderQuadQueue> etr (*this, colour);
  1031. et.iterate (etr);
  1032. }
  1033. void flush() noexcept
  1034. {
  1035. if (numVertices > 0)
  1036. draw();
  1037. }
  1038. private:
  1039. struct VertexInfo
  1040. {
  1041. GLshort x, y;
  1042. GLuint colour;
  1043. };
  1044. #if ! JUCE_MAC
  1045. enum { numQuads = 64 }; // (had problems with my drivers segfaulting when these buffers are any larger)
  1046. #else
  1047. enum { numQuads = 8192 };
  1048. #endif
  1049. GLuint buffers[2];
  1050. VertexInfo vertexData [numQuads * 4];
  1051. GLushort indexData [numQuads * 6];
  1052. const OpenGLContext& context;
  1053. int numVertices;
  1054. void draw() noexcept
  1055. {
  1056. context.extensions.glBufferData (GL_ARRAY_BUFFER, numVertices * sizeof (VertexInfo), vertexData, GL_DYNAMIC_DRAW);
  1057. glDrawElements (GL_TRIANGLES, (numVertices * 3) / 2, GL_UNSIGNED_SHORT, 0);
  1058. numVertices = 0;
  1059. }
  1060. ShaderQuadQueue& operator= (const ShaderQuadQueue&);
  1061. };
  1062. //==============================================================================
  1063. struct CurrentShader
  1064. {
  1065. CurrentShader (OpenGLContext& context_) noexcept
  1066. : context (context_),
  1067. canUseShaders (context.areShadersAvailable()),
  1068. activeShader (nullptr)
  1069. {
  1070. const Identifier programValueID ("GraphicsContextPrograms");
  1071. programs = dynamic_cast <ShaderPrograms*> (context.properties [programValueID].getObject());
  1072. if (programs == nullptr && canUseShaders)
  1073. {
  1074. programs = new ShaderPrograms (context);
  1075. context.properties.set (programValueID, var (programs));
  1076. }
  1077. }
  1078. void setShader (const Rectangle<int>& bounds, ShaderQuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  1079. {
  1080. if (activeShader != &shader)
  1081. {
  1082. quadQueue.flush();
  1083. activeShader = &shader;
  1084. shader.program.use();
  1085. shader.bindAttributes (context);
  1086. currentBounds = bounds;
  1087. shader.set2DBounds (bounds.toFloat());
  1088. JUCE_CHECK_OPENGL_ERROR
  1089. }
  1090. else if (bounds != currentBounds)
  1091. {
  1092. currentBounds = bounds;
  1093. shader.set2DBounds (bounds.toFloat());
  1094. }
  1095. }
  1096. void setShader (OpenGLTarget& target, ShaderQuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  1097. {
  1098. setShader (target.bounds, quadQueue, shader);
  1099. }
  1100. void clearShader (ShaderQuadQueue& quadQueue)
  1101. {
  1102. if (activeShader != nullptr)
  1103. {
  1104. quadQueue.flush();
  1105. activeShader->unbindAttributes (context);
  1106. activeShader = nullptr;
  1107. context.extensions.glUseProgram (0);
  1108. }
  1109. }
  1110. OpenGLContext& context;
  1111. ShaderPrograms::Ptr programs;
  1112. bool canUseShaders;
  1113. private:
  1114. ShaderPrograms::ShaderBase* activeShader;
  1115. Rectangle<int> currentBounds;
  1116. CurrentShader& operator= (const CurrentShader&);
  1117. };
  1118. #endif
  1119. };
  1120. //==============================================================================
  1121. class OpenGLGraphicsContext::GLState
  1122. {
  1123. public:
  1124. GLState (const OpenGLTarget& target_) noexcept
  1125. : target (target_),
  1126. activeTextures (target_.context),
  1127. #if JUCE_USE_OPENGL_SHADERS
  1128. currentShader (target_.context),
  1129. shaderQuadQueue (target_.context),
  1130. #endif
  1131. previousFrameBufferTarget (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  1132. {
  1133. // This object can only be created and used when the current thread has an active OpenGL context.
  1134. jassert (OpenGLHelpers::isContextActive());
  1135. JUCE_CHECK_OPENGL_ERROR
  1136. target.makeActiveFor2D();
  1137. blendMode.resync();
  1138. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1139. currentColour.resync();
  1140. #endif
  1141. JUCE_CHECK_OPENGL_ERROR
  1142. #ifdef GL_COLOR_ARRAY
  1143. glDisableClientState (GL_COLOR_ARRAY);
  1144. glDisableClientState (GL_NORMAL_ARRAY);
  1145. #if JUCE_USE_OPENGL_SHADERS
  1146. if (currentShader.canUseShaders)
  1147. {
  1148. glDisableClientState (GL_VERTEX_ARRAY);
  1149. glDisableClientState (GL_INDEX_ARRAY);
  1150. for (int i = 3; --i >= 0;)
  1151. {
  1152. activeTextures.setActiveTexture (i);
  1153. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  1154. }
  1155. }
  1156. else
  1157. #endif
  1158. {
  1159. glEnableClientState (GL_VERTEX_ARRAY);
  1160. for (int i = 3; --i >= 0;)
  1161. {
  1162. activeTextures.setActiveTexture (i);
  1163. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  1164. }
  1165. }
  1166. #endif
  1167. JUCE_CHECK_OPENGL_ERROR
  1168. activeTextures.clear();
  1169. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1170. resetMultiTextureModes (false);
  1171. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1172. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1173. #endif
  1174. #if JUCE_USE_OPENGL_SHADERS
  1175. shaderQuadQueue.initialise();
  1176. #endif
  1177. JUCE_CHECK_OPENGL_ERROR
  1178. }
  1179. ~GLState()
  1180. {
  1181. flush();
  1182. target.context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget);
  1183. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1184. resetMultiTextureModes (true);
  1185. #endif
  1186. #if JUCE_USE_OPENGL_SHADERS && defined (GL_INDEX_ARRAY)
  1187. glDisableClientState (GL_INDEX_ARRAY);
  1188. #endif
  1189. }
  1190. void flush()
  1191. {
  1192. #if JUCE_USE_OPENGL_SHADERS
  1193. currentShader.clearShader (shaderQuadQueue);
  1194. shaderQuadQueue.flush();
  1195. #endif
  1196. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1197. quadQueue.flush();
  1198. #endif
  1199. JUCE_CHECK_OPENGL_ERROR
  1200. }
  1201. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1202. void scissor (const Rectangle<int>& r)
  1203. {
  1204. quadQueue.flush();
  1205. target.scissor (r);
  1206. }
  1207. void disableScissor()
  1208. {
  1209. quadQueue.flush();
  1210. glDisable (GL_SCISSOR_TEST);
  1211. }
  1212. void prepareMasks (const PositionedTexture* const mask1, const PositionedTexture* const mask2,
  1213. GLfloat* const textureCoords1, GLfloat* const textureCoords2, const Rectangle<int>* const area)
  1214. {
  1215. if (mask1 != nullptr)
  1216. {
  1217. activeTextures.setTexturesEnabled (quadQueue, mask2 != nullptr ? 7 : 3);
  1218. activeTextures.setActiveTexture (0);
  1219. mask1->prepareTextureCoords (area, textureCoords1);
  1220. activeTextures.bindTexture (mask1->textureID);
  1221. activeTextures.setActiveTexture (1);
  1222. if (mask2 != nullptr)
  1223. {
  1224. mask2->prepareTextureCoords (area, textureCoords2);
  1225. activeTextures.bindTexture (mask2->textureID);
  1226. activeTextures.setActiveTexture (2);
  1227. }
  1228. }
  1229. else
  1230. {
  1231. activeTextures.setSingleTextureMode (quadQueue);
  1232. }
  1233. }
  1234. void fillRect (const Rectangle<int>& r, const PixelARGB& colour) noexcept
  1235. {
  1236. jassert (! r.isEmpty());
  1237. quadQueue.prepare (activeTextures, currentColour);
  1238. quadQueue.add (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  1239. }
  1240. void fillRect (const Rectangle<float>& r, const PixelARGB& colour) noexcept
  1241. {
  1242. jassert (! r.isEmpty());
  1243. quadQueue.prepare (activeTextures, currentColour);
  1244. quadQueue.add (r, colour);
  1245. }
  1246. void fillRectangleList (const RectangleList& list, const PixelARGB& colour)
  1247. {
  1248. quadQueue.prepare (activeTextures, currentColour);
  1249. for (RectangleList::Iterator i (list); i.next();)
  1250. quadQueue.add (i.getRectangle()->getX(), i.getRectangle()->getY(),
  1251. i.getRectangle()->getWidth(), i.getRectangle()->getHeight(), colour);
  1252. }
  1253. void fillRectangleList (const RectangleList& list, const Rectangle<int>& clip, const PixelARGB& colour)
  1254. {
  1255. quadQueue.prepare (activeTextures, currentColour);
  1256. for (RectangleList::Iterator i (list); i.next();)
  1257. {
  1258. const Rectangle<int> r (i.getRectangle()->getIntersection (clip));
  1259. if (! r.isEmpty())
  1260. quadQueue.add (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  1261. }
  1262. }
  1263. void fillEdgeTable (const EdgeTable& et, const PixelARGB& colour)
  1264. {
  1265. quadQueue.prepare (activeTextures, currentColour);
  1266. quadQueue.add (et, colour);
  1267. }
  1268. void drawTriangleStrip (const GLfloat* const vertices, const GLfloat* const textureCoords, const int numVertices) noexcept
  1269. {
  1270. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1271. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  1272. glDrawArrays (GL_TRIANGLE_STRIP, 0, numVertices);
  1273. }
  1274. void renderImage (const OpenGLTextureFromImage& image,
  1275. const Rectangle<int>& clip, const AffineTransform& transform, float alpha,
  1276. const PositionedTexture* mask1, const PositionedTexture* mask2,
  1277. const bool replaceExistingContents, const bool isTiled)
  1278. {
  1279. quadQueue.flush();
  1280. blendMode.setBlendMode (quadQueue, replaceExistingContents);
  1281. currentColour.setColour (alpha);
  1282. GLfloat textureCoords1[8], textureCoords2[8];
  1283. if ((! isTiled) || (isPowerOfTwo (image.imageWidth) && isPowerOfTwo (image.imageHeight)))
  1284. {
  1285. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &clip);
  1286. activeTextures.bindTexture (image.textureID);
  1287. TemporaryColourModulationMode tmm;
  1288. if (isTiled)
  1289. {
  1290. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  1291. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  1292. }
  1293. const GLfloat clipX = (GLfloat) clip.getX();
  1294. const GLfloat clipY = (GLfloat) clip.getY();
  1295. const GLfloat clipR = (GLfloat) clip.getRight();
  1296. const GLfloat clipB = (GLfloat) clip.getBottom();
  1297. const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  1298. GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  1299. {
  1300. const AffineTransform t (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  1301. image.fullHeightProportion / image.imageHeight));
  1302. t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1303. t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1304. textureCoords[1] = 1.0f - textureCoords[1];
  1305. textureCoords[3] = 1.0f - textureCoords[3];
  1306. textureCoords[5] = 1.0f - textureCoords[5];
  1307. textureCoords[7] = 1.0f - textureCoords[7];
  1308. }
  1309. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1310. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  1311. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  1312. if (isTiled)
  1313. {
  1314. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1315. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1316. }
  1317. }
  1318. else
  1319. {
  1320. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, nullptr);
  1321. activeTextures.bindTexture (image.textureID);
  1322. TemporaryColourModulationMode tmm;
  1323. scissor (clip);
  1324. glPushMatrix();
  1325. OpenGLHelpers::applyTransform (transform);
  1326. GLfloat vertices[8];
  1327. const GLfloat textureCoords[] = { 0, 1.0f, image.fullWidthProportion, 1.0f,
  1328. 0, 1.0f - image.fullHeightProportion, image.fullWidthProportion, 1.0f - image.fullHeightProportion };
  1329. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1330. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  1331. const Rectangle<int> targetArea (clip.toFloat().transformed (transform.inverted()).getSmallestIntegerContainer());
  1332. int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), image.imageWidth);
  1333. int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), image.imageHeight);
  1334. const int right = targetArea.getRight();
  1335. const int bottom = targetArea.getBottom();
  1336. while (y < bottom)
  1337. {
  1338. vertices[1] = vertices[3] = (GLfloat) y;
  1339. vertices[5] = vertices[7] = (GLfloat) (y + image.imageHeight);
  1340. for (int x1 = x; x1 < right; x1 += image.imageWidth)
  1341. {
  1342. vertices[0] = vertices[4] = (GLfloat) x1;
  1343. vertices[2] = vertices[6] = (GLfloat) (x1 + image.imageWidth);
  1344. if (mask1 != nullptr)
  1345. {
  1346. float t[] = { vertices[0], vertices[1], vertices[2], vertices[3],
  1347. vertices[4], vertices[5], vertices[6], vertices[7] };
  1348. transform.transformPoints (t[0], t[1], t[2], t[3]);
  1349. transform.transformPoints (t[4], t[5], t[6], t[7]);
  1350. mask1->getTextureCoordAt (t[0], t[1], textureCoords1[0], textureCoords1[1]);
  1351. mask1->getTextureCoordAt (t[2], t[3], textureCoords1[2], textureCoords1[3]);
  1352. mask1->getTextureCoordAt (t[4], t[5], textureCoords1[4], textureCoords1[5]);
  1353. mask1->getTextureCoordAt (t[6], t[7], textureCoords1[6], textureCoords1[7]);
  1354. if (mask2 != nullptr)
  1355. {
  1356. mask2->getTextureCoordAt (t[0], t[1], textureCoords2[0], textureCoords2[1]);
  1357. mask2->getTextureCoordAt (t[2], t[3], textureCoords2[2], textureCoords2[3]);
  1358. mask2->getTextureCoordAt (t[4], t[5], textureCoords2[4], textureCoords2[5]);
  1359. mask2->getTextureCoordAt (t[6], t[7], textureCoords2[6], textureCoords2[7]);
  1360. }
  1361. }
  1362. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  1363. }
  1364. y += image.imageHeight;
  1365. }
  1366. glPopMatrix();
  1367. disableScissor();
  1368. }
  1369. }
  1370. void fillTexture (const Rectangle<int>& area, const FillType& fill,
  1371. const PositionedTexture* mask1, const PositionedTexture* mask2,
  1372. const bool replaceExistingContents)
  1373. {
  1374. jassert (! (mask1 == nullptr && mask2 != nullptr));
  1375. if (fill.isColour())
  1376. {
  1377. GLfloat textureCoords1[8], textureCoords2[8];
  1378. if (mask1 != nullptr)
  1379. {
  1380. blendMode.setBlendMode (quadQueue, replaceExistingContents);
  1381. activeTextures.setTexturesEnabled (quadQueue, mask2 != nullptr ? 3 : 1);
  1382. activeTextures.setActiveTexture (0);
  1383. mask1->prepareTextureCoords (&area, textureCoords1);
  1384. activeTextures.bindTexture (mask1->textureID);
  1385. if (mask2 != nullptr)
  1386. {
  1387. activeTextures.setActiveTexture (1);
  1388. mask2->prepareTextureCoords (&area, textureCoords2);
  1389. activeTextures.bindTexture (mask2->textureID);
  1390. }
  1391. }
  1392. else
  1393. {
  1394. blendMode.setBlendMode (quadQueue, replaceExistingContents || fill.colour.isOpaque());
  1395. activeTextures.disableTextures (quadQueue);
  1396. }
  1397. currentColour.setPremultipliedColour (fill.colour);
  1398. OpenGLHelpers::fillRect (area);
  1399. }
  1400. else if (fill.isGradient())
  1401. {
  1402. ColourGradient g2 (*(fill.gradient));
  1403. g2.multiplyOpacity (fill.getOpacity());
  1404. if (g2.point1 == g2.point2)
  1405. {
  1406. fillTexture (area, g2.getColourAtPosition (1.0), mask1, mask2, replaceExistingContents);
  1407. }
  1408. else
  1409. {
  1410. blendMode.setBlendMode (quadQueue, replaceExistingContents || (mask1 == nullptr && fill.colour.isOpaque() && fill.gradient->isOpaque()));
  1411. if (g2.isRadial)
  1412. fillWithRadialGradient (area, g2, fill.transform, mask1, mask2);
  1413. else
  1414. fillWithLinearGradient (area, g2, fill.transform, mask1, mask2);
  1415. }
  1416. }
  1417. else if (fill.isTiledImage())
  1418. {
  1419. renderImage (fill.image, area, fill.transform, fill.colour.getFloatAlpha(),
  1420. mask1, mask2, replaceExistingContents, true);
  1421. }
  1422. }
  1423. #endif
  1424. #if JUCE_USE_OPENGL_SHADERS
  1425. void setShader (ShaderPrograms::ShaderBase& shader)
  1426. {
  1427. currentShader.setShader (target, shaderQuadQueue, shader);
  1428. JUCE_CHECK_OPENGL_ERROR
  1429. }
  1430. void setShaderForGradientFill (const ColourGradient& g, const AffineTransform& transform,
  1431. const int maskTextureID, const Rectangle<int>* const maskArea)
  1432. {
  1433. JUCE_CHECK_OPENGL_ERROR
  1434. activeTextures.disableTextures (shaderQuadQueue);
  1435. blendMode.setPremultipliedBlendingMode (shaderQuadQueue);
  1436. JUCE_CHECK_OPENGL_ERROR
  1437. if (maskArea != nullptr)
  1438. {
  1439. activeTextures.setTexturesEnabled (shaderQuadQueue, 3);
  1440. activeTextures.setActiveTexture (1);
  1441. activeTextures.bindTexture (maskTextureID);
  1442. activeTextures.setActiveTexture (0);
  1443. textureCache.bindTextureForGradient (activeTextures, g);
  1444. }
  1445. else
  1446. {
  1447. activeTextures.setSingleTextureMode (shaderQuadQueue);
  1448. textureCache.bindTextureForGradient (activeTextures, g);
  1449. }
  1450. const AffineTransform t (transform.translated ((float) -target.bounds.getX(), (float) -target.bounds.getY()));
  1451. Point<float> p1 (g.point1.transformedBy (t));
  1452. const Point<float> p2 (g.point2.transformedBy (t));
  1453. const Point<float> p3 (Point<float> (g.point1.x + (g.point2.y - g.point1.y),
  1454. g.point1.y - (g.point2.x - g.point1.x)).transformedBy (t));
  1455. ShaderPrograms* const programs = currentShader.programs;
  1456. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1457. if (g.isRadial)
  1458. {
  1459. ShaderPrograms::RadialGradientParams* gradientParams;
  1460. if (maskArea == nullptr)
  1461. {
  1462. setShader (programs->radialGradient);
  1463. gradientParams = &programs->radialGradient.gradientParams;
  1464. }
  1465. else
  1466. {
  1467. setShader (programs->radialGradientMasked);
  1468. gradientParams = &programs->radialGradientMasked.gradientParams;
  1469. maskParams = &programs->radialGradientMasked.maskParams;
  1470. }
  1471. gradientParams->setMatrix (p1, p2, p3);
  1472. }
  1473. else
  1474. {
  1475. p1 = Line<float> (p1, p3).findNearestPointTo (p2);
  1476. const Point<float> delta (p2.x - p1.x, p1.y - p2.y);
  1477. const ShaderPrograms::LinearGradientParams* gradientParams;
  1478. float grad, length;
  1479. if (std::abs (delta.x) < std::abs (delta.y))
  1480. {
  1481. if (maskArea == nullptr)
  1482. {
  1483. setShader (programs->linearGradient1);
  1484. gradientParams = &(programs->linearGradient1.gradientParams);
  1485. }
  1486. else
  1487. {
  1488. setShader (programs->linearGradient1Masked);
  1489. gradientParams = &(programs->linearGradient1Masked.gradientParams);
  1490. maskParams = &programs->linearGradient1Masked.maskParams;
  1491. }
  1492. grad = delta.x / delta.y;
  1493. length = (p2.y - grad * p2.x) - (p1.y - grad * p1.x);
  1494. }
  1495. else
  1496. {
  1497. if (maskArea == nullptr)
  1498. {
  1499. setShader (programs->linearGradient2);
  1500. gradientParams = &(programs->linearGradient2.gradientParams);
  1501. }
  1502. else
  1503. {
  1504. setShader (programs->linearGradient2Masked);
  1505. gradientParams = &(programs->linearGradient2Masked.gradientParams);
  1506. maskParams = &programs->linearGradient2Masked.maskParams;
  1507. }
  1508. grad = delta.y / delta.x;
  1509. length = (p2.x - grad * p2.y) - (p1.x - grad * p1.y);
  1510. }
  1511. gradientParams->gradientInfo.set (p1.x, p1.y, grad, length);
  1512. }
  1513. if (maskParams != nullptr)
  1514. maskParams->setBounds (*maskArea, target, 1);
  1515. JUCE_CHECK_OPENGL_ERROR
  1516. }
  1517. void setShaderForTiledImageFill (const OpenGLTextureFromImage& image, const AffineTransform& transform,
  1518. const int maskTextureID, const Rectangle<int>* const maskArea, const bool clampTiledImages)
  1519. {
  1520. blendMode.setPremultipliedBlendingMode (shaderQuadQueue);
  1521. ShaderPrograms* const programs = currentShader.programs;
  1522. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1523. const ShaderPrograms::ImageParams* imageParams;
  1524. if (maskArea != nullptr)
  1525. {
  1526. activeTextures.setTwoTextureMode (shaderQuadQueue, image.textureID, maskTextureID);
  1527. if (clampTiledImages)
  1528. {
  1529. setShader (programs->imageMasked);
  1530. imageParams = &programs->imageMasked.imageParams;
  1531. maskParams = &programs->imageMasked.maskParams;
  1532. }
  1533. else
  1534. {
  1535. setShader (programs->tiledImageMasked);
  1536. imageParams = &programs->tiledImageMasked.imageParams;
  1537. maskParams = &programs->tiledImageMasked.maskParams;
  1538. }
  1539. }
  1540. else
  1541. {
  1542. activeTextures.setSingleTextureMode (shaderQuadQueue);
  1543. activeTextures.bindTexture (image.textureID);
  1544. if (clampTiledImages)
  1545. {
  1546. setShader (programs->image);
  1547. imageParams = &programs->image.imageParams;
  1548. }
  1549. else
  1550. {
  1551. setShader (programs->tiledImage);
  1552. imageParams = &programs->tiledImage.imageParams;
  1553. }
  1554. }
  1555. imageParams->setMatrix (transform, image, (float) target.bounds.getX(), (float) target.bounds.getY());
  1556. if (maskParams != nullptr)
  1557. maskParams->setBounds (*maskArea, target, 1);
  1558. }
  1559. #endif
  1560. OpenGLTarget target;
  1561. StateHelpers::BlendingMode blendMode;
  1562. StateHelpers::ActiveTextures activeTextures;
  1563. StateHelpers::TextureCache textureCache;
  1564. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1565. StateHelpers::CurrentColour currentColour;
  1566. StateHelpers::QuadQueue quadQueue;
  1567. #endif
  1568. #if JUCE_USE_OPENGL_SHADERS
  1569. StateHelpers::CurrentShader currentShader;
  1570. StateHelpers::ShaderQuadQueue shaderQuadQueue;
  1571. #endif
  1572. private:
  1573. GLuint previousFrameBufferTarget;
  1574. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1575. void resetMultiTextureMode (int index, const bool forRGBTextures)
  1576. {
  1577. activeTextures.setActiveTexture (index);
  1578. glDisable (GL_TEXTURE_2D);
  1579. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  1580. glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  1581. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
  1582. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
  1583. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
  1584. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
  1585. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, forRGBTextures ? GL_SRC_COLOR : GL_SRC_ALPHA);
  1586. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
  1587. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
  1588. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
  1589. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
  1590. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
  1591. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1592. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1593. }
  1594. void resetMultiTextureModes (const bool forRGBTextures)
  1595. {
  1596. resetMultiTextureMode (2, forRGBTextures);
  1597. resetMultiTextureMode (1, forRGBTextures);
  1598. resetMultiTextureMode (0, forRGBTextures);
  1599. }
  1600. void fillWithLinearGradient (const Rectangle<int>& rect, const ColourGradient& grad, const AffineTransform& transform,
  1601. const PositionedTexture* mask1, const PositionedTexture* mask2)
  1602. {
  1603. const Point<float> p1 (grad.point1.transformedBy (transform));
  1604. const Point<float> p2 (grad.point2.transformedBy (transform));
  1605. const Point<float> p3 (Point<float> (grad.point1.x - (grad.point2.y - grad.point1.y) / StateHelpers::TextureCache::gradientTextureSize,
  1606. grad.point1.y + (grad.point2.x - grad.point1.x) / StateHelpers::TextureCache::gradientTextureSize)
  1607. .transformedBy (transform));
  1608. const AffineTransform textureTransform (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  1609. p2.x, p2.y, 1.0f, 0.0f,
  1610. p3.x, p3.y, 0.0f, 1.0f));
  1611. const GLfloat l = (GLfloat) rect.getX();
  1612. const GLfloat r = (GLfloat) rect.getRight();
  1613. const GLfloat t = (GLfloat) rect.getY();
  1614. const GLfloat b = (GLfloat) rect.getBottom();
  1615. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  1616. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  1617. textureTransform.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1618. textureTransform.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1619. GLfloat textureCoords1[8], textureCoords2[8];
  1620. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &rect);
  1621. TemporaryColourModulationMode tmm;
  1622. textureCache.bindTextureForGradient (activeTextures, grad);
  1623. currentColour.setSolidColour();
  1624. drawTriangleStrip (vertices, textureCoords, 4);
  1625. }
  1626. void fillWithRadialGradient (const Rectangle<int>& rect, const ColourGradient& grad, const AffineTransform& transform,
  1627. const PositionedTexture* mask1, const PositionedTexture* mask2)
  1628. {
  1629. const Point<float> centre (grad.point1.transformedBy (transform));
  1630. const float screenRadius = centre.getDistanceFrom (rect.getCentre().toFloat())
  1631. + Point<int> (rect.getWidth() / 2,
  1632. rect.getHeight() / 2).getDistanceFromOrigin()
  1633. + 8.0f;
  1634. const AffineTransform inverse (transform.inverted());
  1635. const float sourceRadius = jmax (Point<float> (screenRadius, 0.0f).transformedBy (inverse).getDistanceFromOrigin(),
  1636. Point<float> (0.0f, screenRadius).transformedBy (inverse).getDistanceFromOrigin());
  1637. const int numDivisions = 90;
  1638. GLfloat vertices [4 + numDivisions * 2];
  1639. GLfloat textureCoords1 [4 + numDivisions * 2];
  1640. GLfloat textureCoords2 [4 + numDivisions * 2];
  1641. GLfloat textureCoords3 [4 + numDivisions * 2];
  1642. {
  1643. GLfloat* t = textureCoords1;
  1644. *t++ = 0.0f;
  1645. *t++ = 0.0f;
  1646. const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2);
  1647. for (int i = numDivisions + 1; --i >= 0;)
  1648. {
  1649. *t++ = texturePos;
  1650. *t++ = 0.0f;
  1651. }
  1652. }
  1653. {
  1654. GLfloat* v = vertices;
  1655. *v++ = centre.x;
  1656. *v++ = centre.y;
  1657. const Point<float> first (grad.point1.translated (0, -sourceRadius)
  1658. .transformedBy (transform));
  1659. *v++ = first.x;
  1660. *v++ = first.y;
  1661. for (int i = 1; i < numDivisions; ++i)
  1662. {
  1663. const float angle = i * (float_Pi * 2.0f / numDivisions);
  1664. const Point<float> p (grad.point1.translated (std::sin (angle) * sourceRadius,
  1665. std::cos (angle) * -sourceRadius)
  1666. .transformedBy (transform));
  1667. *v++ = p.x;
  1668. *v++ = p.y;
  1669. }
  1670. *v++ = first.x;
  1671. *v++ = first.y;
  1672. }
  1673. prepareMasks (mask1, mask2, textureCoords2, textureCoords3, nullptr);
  1674. if (mask1 != nullptr)
  1675. {
  1676. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  1677. mask1->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords2[i], textureCoords2[i + 1]);
  1678. if (mask2 != nullptr)
  1679. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  1680. mask2->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords3[i], textureCoords3[i + 1]);
  1681. }
  1682. scissor (rect);
  1683. textureCache.bindTextureForGradient (activeTextures, grad);
  1684. currentColour.setSolidColour();
  1685. TemporaryColourModulationMode tmm;
  1686. glVertexPointer (2, GL_FLOAT, 0, vertices);
  1687. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords1);
  1688. glDrawArrays (GL_TRIANGLE_FAN, 0, numDivisions + 2);
  1689. disableScissor();
  1690. }
  1691. struct TemporaryColourModulationMode
  1692. {
  1693. TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); }
  1694. ~TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); }
  1695. };
  1696. #endif
  1697. };
  1698. //==============================================================================
  1699. class ClipRegion_Mask;
  1700. //==============================================================================
  1701. class ClipRegionBase : public SingleThreadedReferenceCountedObject
  1702. {
  1703. public:
  1704. ClipRegionBase (OpenGLGraphicsContext::GLState& state_) noexcept : state (state_) {}
  1705. virtual ~ClipRegionBase() {}
  1706. typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
  1707. virtual Ptr clone() const = 0;
  1708. virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
  1709. virtual Ptr clipToRectangleList (const RectangleList&) = 0;
  1710. virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
  1711. virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
  1712. virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
  1713. virtual Ptr clipToTexture (const PositionedTexture&) = 0;
  1714. virtual Rectangle<int> getClipBounds() const = 0;
  1715. virtual void fillRect (const Rectangle<int>& area, const FillType&, bool replaceContents) = 0;
  1716. virtual void fillRect (const Rectangle<float>& area, const FillType&) = 0;
  1717. virtual void fillEdgeTable (EdgeTable& et, const FillType& fill) = 0;
  1718. virtual void drawImage (const Image&, const AffineTransform&, float alpha,
  1719. const Rectangle<int>& clip, EdgeTable* mask) = 0;
  1720. OpenGLGraphicsContext::GLState& state;
  1721. private:
  1722. JUCE_DECLARE_NON_COPYABLE (ClipRegionBase);
  1723. };
  1724. //==============================================================================
  1725. class ClipRegion_RectangleListBase : public ClipRegionBase
  1726. {
  1727. public:
  1728. ClipRegion_RectangleListBase (OpenGLGraphicsContext::GLState& state_, const Rectangle<int>& r) noexcept
  1729. : ClipRegionBase (state_), clip (r)
  1730. {}
  1731. ClipRegion_RectangleListBase (OpenGLGraphicsContext::GLState& state_, const RectangleList& r) noexcept
  1732. : ClipRegionBase (state_), clip (r)
  1733. {}
  1734. Rectangle<int> getClipBounds() const { return clip.getBounds(); }
  1735. Ptr clipToRectangle (const Rectangle<int>& r) { return clip.clipTo (r) ? this : nullptr; }
  1736. Ptr clipToRectangleList (const RectangleList& r) { return clip.clipTo (r) ? this : nullptr; }
  1737. Ptr excludeClipRectangle (const Rectangle<int>& r) { clip.subtract (r); return clip.isEmpty() ? nullptr : this; }
  1738. protected:
  1739. RectangleList clip;
  1740. };
  1741. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  1742. //==============================================================================
  1743. class ClipRegion_Mask : public ClipRegionBase
  1744. {
  1745. public:
  1746. ClipRegion_Mask (const ClipRegion_Mask& other)
  1747. : ClipRegionBase (other.state),
  1748. clip (other.clip),
  1749. maskOrigin (other.clip.getPosition())
  1750. {
  1751. TargetSaver ts (state.target.context);
  1752. state.flush();
  1753. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1754. state.activeTextures.clear();
  1755. mask.initialise (state.target.context, clip.getWidth(), clip.getHeight());
  1756. OpenGLTarget m (state.target.context, mask, maskOrigin);
  1757. m.makeActiveFor2D();
  1758. state.blendMode.disableBlend (state.quadQueue);
  1759. state.currentColour.setSolidColour();
  1760. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1761. OpenGLHelpers::drawTextureQuad (other.mask.getTextureID(), other.getMaskArea());
  1762. }
  1763. ClipRegion_Mask (OpenGLGraphicsContext::GLState& state_, const RectangleList& r)
  1764. : ClipRegionBase (state_),
  1765. clip (r.getBounds()),
  1766. maskOrigin (clip.getPosition())
  1767. {
  1768. TargetSaver ts (state.target.context);
  1769. initialiseClear();
  1770. state.blendMode.disableBlend (state.quadQueue);
  1771. state.fillRectangleList (r, PixelARGB (0xffffffff));
  1772. state.quadQueue.flush();
  1773. }
  1774. Ptr clone() const { return new ClipRegion_Mask (*this); }
  1775. Rectangle<int> getClipBounds() const { return clip; }
  1776. Ptr clipToRectangle (const Rectangle<int>& r)
  1777. {
  1778. clip = clip.getIntersection (r);
  1779. return clip.isEmpty() ? nullptr : this;
  1780. }
  1781. Ptr clipToRectangleList (const RectangleList& r)
  1782. {
  1783. clip = clip.getIntersection (r.getBounds());
  1784. if (clip.isEmpty())
  1785. return nullptr;
  1786. RectangleList excluded (clip);
  1787. if (excluded.subtract (r))
  1788. {
  1789. if (excluded.getNumRectangles() == 1)
  1790. return excludeClipRectangle (excluded.getRectangle (0));
  1791. TargetSaver ts (state.target.context);
  1792. makeMaskActive();
  1793. state.blendMode.disableBlend (state.quadQueue);
  1794. state.fillRectangleList (excluded, PixelARGB (0));
  1795. state.quadQueue.flush();
  1796. }
  1797. return this;
  1798. }
  1799. Ptr excludeClipRectangle (const Rectangle<int>& r)
  1800. {
  1801. if (r.contains (clip))
  1802. return nullptr;
  1803. TargetSaver ts (state.target.context);
  1804. makeMaskActive();
  1805. state.activeTextures.disableTextures (state.quadQueue);
  1806. state.blendMode.disableBlend (state.quadQueue);
  1807. state.currentColour.setColour (PixelARGB (0));
  1808. OpenGLHelpers::fillRect (r);
  1809. return this;
  1810. }
  1811. Ptr clipToPath (const Path& p, const AffineTransform& t)
  1812. {
  1813. EdgeTable et (clip, p, t);
  1814. if (! et.isEmpty())
  1815. {
  1816. OpenGLTexture texture;
  1817. PositionedTexture pt (texture, et, et.getMaximumBounds());
  1818. return clipToTexture (pt);
  1819. }
  1820. return nullptr;
  1821. }
  1822. Ptr clipToTexture (const PositionedTexture& pt)
  1823. {
  1824. clip = clip.getIntersection (pt.clip);
  1825. if (clip.isEmpty())
  1826. return nullptr;
  1827. TargetSaver ts (state.target.context);
  1828. makeMaskActive();
  1829. state.blendMode.setBlendFunc (state.quadQueue, GL_ZERO, GL_SRC_ALPHA);
  1830. state.currentColour.setSolidColour();
  1831. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1832. OpenGLHelpers::drawTextureQuad (pt.textureID, pt.area);
  1833. return this;
  1834. }
  1835. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  1836. {
  1837. TargetSaver ts (state.target.context);
  1838. makeMaskActive();
  1839. state.blendMode.setBlendFunc (state.quadQueue, GL_ZERO, GL_SRC_ALPHA);
  1840. state.currentColour.setSolidColour();
  1841. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1842. state.activeTextures.bindTexture (image.textureID);
  1843. const GLfloat l = (GLfloat) maskOrigin.x;
  1844. const GLfloat t = (GLfloat) maskOrigin.y;
  1845. const GLfloat r = (GLfloat) (maskOrigin.x + mask.getWidth());
  1846. const GLfloat b = (GLfloat) (maskOrigin.y + mask.getHeight());
  1847. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  1848. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  1849. const AffineTransform inv (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  1850. image.fullHeightProportion / image.imageHeight));
  1851. inv.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  1852. inv.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  1853. textureCoords[1] = 1.0f - textureCoords[1];
  1854. textureCoords[3] = 1.0f - textureCoords[3];
  1855. textureCoords[5] = 1.0f - textureCoords[5];
  1856. textureCoords[7] = 1.0f - textureCoords[7];
  1857. state.drawTriangleStrip (vertices, textureCoords, 4);
  1858. return this;
  1859. }
  1860. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1861. {
  1862. (void) replaceContents; jassert (! replaceContents);
  1863. const Rectangle<int> r (clip.getIntersection (area));
  1864. if (! r.isEmpty())
  1865. fillRectInternal (r, fill, false);
  1866. }
  1867. void fillRect (const Rectangle<float>& area, const FillType& fill)
  1868. {
  1869. if (fill.isColour())
  1870. {
  1871. FloatRectangleRenderer frr (*this, fill);
  1872. RenderingHelpers::FloatRectangleRasterisingInfo (area).iterate (frr);
  1873. }
  1874. else
  1875. {
  1876. EdgeTable et (area);
  1877. fillEdgeTable (et, fill);
  1878. }
  1879. }
  1880. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  1881. {
  1882. const Rectangle<int> r (et.getMaximumBounds().getIntersection (clip));
  1883. if (! r.isEmpty())
  1884. {
  1885. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures, r.getWidth(), r.getHeight());
  1886. PositionedTexture pt1 (*texture, et, r);
  1887. PositionedTexture pt2 (mask.getTextureID(), getMaskArea(), r);
  1888. state.fillTexture (r, fill, &pt2, &pt1, false);
  1889. state.textureCache.releaseTexture (state.activeTextures, texture);
  1890. }
  1891. }
  1892. void fillRectInternal (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1893. {
  1894. PositionedTexture pt (mask.getTextureID(), getMaskArea(), area);
  1895. state.fillTexture (area, fill, &pt, nullptr, replaceContents);
  1896. }
  1897. void drawImage (const Image& image, const AffineTransform& transform,
  1898. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  1899. {
  1900. const OpenGLTextureFromImage source (image);
  1901. const Rectangle<int> bufferArea (clipArea.getIntersection (clip));
  1902. if (! bufferArea.isEmpty())
  1903. {
  1904. PositionedTexture pt (mask.getTextureID(), getMaskArea(), bufferArea);
  1905. if (et != nullptr)
  1906. {
  1907. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures, clipArea.getWidth(), clipArea.getHeight());
  1908. PositionedTexture mask1 (*texture, *et, clipArea);
  1909. state.renderImage (source, bufferArea, transform, alpha, &pt, &mask1, false, false);
  1910. state.textureCache.releaseTexture (state.activeTextures, texture);
  1911. }
  1912. else
  1913. {
  1914. state.renderImage (source, bufferArea, transform, alpha, &pt, nullptr, false, false);
  1915. }
  1916. }
  1917. }
  1918. protected:
  1919. OpenGLFrameBuffer mask;
  1920. Rectangle<int> clip;
  1921. Point<int> maskOrigin;
  1922. Rectangle<int> getMaskArea() const noexcept { return Rectangle<int> (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()); }
  1923. void prepareFor2D() const { OpenGLTarget::applyFlippedMatrix (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()); }
  1924. void makeMaskActive()
  1925. {
  1926. state.flush();
  1927. const bool b = mask.makeCurrentRenderingTarget();
  1928. (void) b; jassert (b);
  1929. prepareFor2D();
  1930. }
  1931. void initialiseClear()
  1932. {
  1933. state.flush();
  1934. jassert (! clip.isEmpty());
  1935. state.activeTextures.setSingleTextureMode (state.quadQueue);
  1936. state.activeTextures.clear();
  1937. mask.initialise (state.target.context, clip.getWidth(), clip.getHeight());
  1938. mask.makeCurrentAndClear();
  1939. state.activeTextures.disableTextures (state.quadQueue);
  1940. state.blendMode.disableBlend (state.quadQueue);
  1941. prepareFor2D();
  1942. }
  1943. struct TargetSaver
  1944. {
  1945. TargetSaver (const OpenGLContext& context_)
  1946. : context (context_), oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  1947. {
  1948. glGetIntegerv (GL_VIEWPORT, oldViewport);
  1949. glPushMatrix();
  1950. }
  1951. ~TargetSaver()
  1952. {
  1953. context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, oldFramebuffer);
  1954. glPopMatrix();
  1955. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  1956. }
  1957. private:
  1958. const OpenGLContext& context;
  1959. GLuint oldFramebuffer;
  1960. GLint oldViewport[4];
  1961. TargetSaver& operator= (const TargetSaver&);
  1962. };
  1963. struct FloatRectangleRenderer
  1964. {
  1965. FloatRectangleRenderer (ClipRegion_Mask& owner_, const FillType& fill_) noexcept
  1966. : owner (owner_), fill (fill_), originalColour (fill_.colour)
  1967. {}
  1968. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  1969. {
  1970. if (w > 0 && h > 0)
  1971. {
  1972. fill.colour = originalColour.withMultipliedAlpha (alpha / 255.0f);
  1973. owner.fillRect (Rectangle<int> (x, y, w, h), fill, false);
  1974. }
  1975. }
  1976. private:
  1977. ClipRegion_Mask& owner;
  1978. FillType fill;
  1979. const Colour originalColour;
  1980. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  1981. };
  1982. ClipRegion_Mask& operator= (const ClipRegion_Mask&);
  1983. };
  1984. //==============================================================================
  1985. class ClipRegion_RectangleList : public ClipRegion_RectangleListBase
  1986. {
  1987. public:
  1988. ClipRegion_RectangleList (OpenGLGraphicsContext::GLState& state_, const Rectangle<int>& r) noexcept
  1989. : ClipRegion_RectangleListBase (state_, r)
  1990. {}
  1991. ClipRegion_RectangleList (OpenGLGraphicsContext::GLState& state_, const RectangleList& r) noexcept
  1992. : ClipRegion_RectangleListBase (state_, r)
  1993. {}
  1994. Ptr clone() const { return new ClipRegion_RectangleList (state, clip); }
  1995. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  1996. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  1997. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  1998. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  1999. {
  2000. if (fill.isColour())
  2001. {
  2002. state.activeTextures.disableTextures (state.quadQueue);
  2003. state.blendMode.setBlendMode (state.quadQueue, replaceContents || fill.colour.isOpaque());
  2004. state.fillRectangleList (clip, area, fill.colour.getPixelARGB());
  2005. }
  2006. else
  2007. {
  2008. for (RectangleList::Iterator i (clip); i.next();)
  2009. {
  2010. const Rectangle<int> r (i.getRectangle()->getIntersection (area));
  2011. if (! r.isEmpty())
  2012. state.fillTexture (r, fill, nullptr, nullptr, replaceContents);
  2013. }
  2014. }
  2015. }
  2016. void fillRect (const Rectangle<float>& area, const FillType& fill)
  2017. {
  2018. if (fill.isColour())
  2019. {
  2020. state.activeTextures.disableTextures (state.quadQueue);
  2021. state.blendMode.setPremultipliedBlendingMode (state.quadQueue);
  2022. for (RectangleList::Iterator i (clip); i.next();)
  2023. {
  2024. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  2025. if (! r.isEmpty())
  2026. state.fillRect (r, fill.colour.getPixelARGB());
  2027. }
  2028. }
  2029. else
  2030. {
  2031. EdgeTable et (area);
  2032. fillEdgeTable (et, fill);
  2033. }
  2034. }
  2035. void drawImage (const Image& image, const AffineTransform& transform,
  2036. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  2037. {
  2038. const OpenGLTextureFromImage source (image);
  2039. for (RectangleList::Iterator i (clip); i.next();)
  2040. {
  2041. const Rectangle<int> bufferArea (i.getRectangle()->getIntersection (clipArea));
  2042. if (! bufferArea.isEmpty())
  2043. {
  2044. if (et != nullptr)
  2045. {
  2046. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures, clipArea.getWidth(), clipArea.getHeight());
  2047. PositionedTexture mask (*texture, *et, clipArea);
  2048. state.renderImage (source, bufferArea, transform, alpha, &mask, nullptr, false, false);
  2049. state.textureCache.releaseTexture (state.activeTextures, texture);
  2050. }
  2051. else
  2052. {
  2053. state.renderImage (source, bufferArea, transform, alpha, nullptr, nullptr, false, false);
  2054. }
  2055. }
  2056. }
  2057. }
  2058. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  2059. {
  2060. if (fill.isColour())
  2061. {
  2062. state.blendMode.setPremultipliedBlendingMode (state.quadQueue);
  2063. if (! clip.containsRectangle (et.getMaximumBounds()))
  2064. et.clipToEdgeTable (EdgeTable (clip));
  2065. state.fillEdgeTable (et, fill.colour.getPixelARGB());
  2066. }
  2067. else
  2068. {
  2069. OpenGLTexture* texture = state.textureCache.getTexture (state.activeTextures,
  2070. clip.getBounds().getWidth(), clip.getBounds().getHeight());
  2071. PositionedTexture pt (*texture, et, clip.getBounds());
  2072. for (RectangleList::Iterator i (clip); i.next();)
  2073. {
  2074. const Rectangle<int> r (i.getRectangle()->getIntersection (pt.clip));
  2075. if (! r.isEmpty())
  2076. state.fillTexture (r, fill, &pt, nullptr, false);
  2077. }
  2078. state.textureCache.releaseTexture (state.activeTextures, texture);
  2079. }
  2080. }
  2081. protected:
  2082. Ptr toMask() const { return new ClipRegion_Mask (state, clip); }
  2083. JUCE_DECLARE_NON_COPYABLE (ClipRegion_RectangleList);
  2084. };
  2085. #endif
  2086. //==============================================================================
  2087. #if JUCE_USE_OPENGL_SHADERS
  2088. class ClipRegion_Mask_Shader : public ClipRegionBase
  2089. {
  2090. public:
  2091. ClipRegion_Mask_Shader (const ClipRegion_Mask_Shader& other)
  2092. : ClipRegionBase (other.state),
  2093. clip (other.clip),
  2094. maskArea (other.clip)
  2095. {
  2096. TargetSaver ts (state.target.context);
  2097. state.currentShader.clearShader (state.shaderQuadQueue);
  2098. state.shaderQuadQueue.flush();
  2099. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  2100. state.activeTextures.clear();
  2101. mask.initialise (state.target.context, maskArea.getWidth(), maskArea.getHeight());
  2102. maskArea.setSize (mask.getWidth(), mask.getHeight());
  2103. makeActive();
  2104. state.blendMode.disableBlend (state.shaderQuadQueue);
  2105. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  2106. state.activeTextures.bindTexture (other.mask.getTextureID());
  2107. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->copyTexture);
  2108. state.currentShader.programs->copyTexture.imageParams.imageTexture.set (0);
  2109. state.currentShader.programs->copyTexture.imageParams
  2110. .setMatrix (AffineTransform::translation ((float) other.maskArea.getX(), (float) other.maskArea.getY()),
  2111. other.maskArea.getWidth(), other.maskArea.getHeight(), 1.0f, 1.0f,
  2112. (float) maskArea.getX(), (float) maskArea.getY());
  2113. state.shaderQuadQueue.add (clip, PixelARGB (0xffffffff));
  2114. state.shaderQuadQueue.flush();
  2115. }
  2116. ClipRegion_Mask_Shader (OpenGLGraphicsContext::GLState& state_, const RectangleList& r)
  2117. : ClipRegionBase (state_),
  2118. clip (r.getBounds()),
  2119. maskArea (clip)
  2120. {
  2121. TargetSaver ts (state.target.context);
  2122. state.currentShader.clearShader (state.shaderQuadQueue);
  2123. state.shaderQuadQueue.flush();
  2124. state.activeTextures.clear();
  2125. mask.initialise (state.target.context, maskArea.getWidth(), maskArea.getHeight());
  2126. maskArea.setSize (mask.getWidth(), mask.getHeight());
  2127. mask.makeCurrentAndClear();
  2128. makeActive();
  2129. state.blendMode.setBlendMode (state.shaderQuadQueue, true);
  2130. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->solidColourProgram);
  2131. state.shaderQuadQueue.add (r, PixelARGB (0xffffffff));
  2132. state.shaderQuadQueue.flush();
  2133. }
  2134. Ptr clone() const { return new ClipRegion_Mask_Shader (*this); }
  2135. Rectangle<int> getClipBounds() const { return clip; }
  2136. Ptr clipToRectangle (const Rectangle<int>& r)
  2137. {
  2138. clip = clip.getIntersection (r);
  2139. return clip.isEmpty() ? nullptr : this;
  2140. }
  2141. Ptr clipToRectangleList (const RectangleList& r)
  2142. {
  2143. clip = clip.getIntersection (r.getBounds());
  2144. if (clip.isEmpty())
  2145. return nullptr;
  2146. RectangleList excluded (clip);
  2147. if (excluded.subtract (r))
  2148. {
  2149. if (excluded.getNumRectangles() == 1)
  2150. return excludeClipRectangle (excluded.getRectangle (0));
  2151. TargetSaver ts (state.target.context);
  2152. makeActive();
  2153. state.blendMode.setBlendMode (state.shaderQuadQueue, true);
  2154. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->solidColourProgram);
  2155. state.shaderQuadQueue.add (excluded, PixelARGB (0));
  2156. state.shaderQuadQueue.flush();
  2157. }
  2158. return this;
  2159. }
  2160. Ptr excludeClipRectangle (const Rectangle<int>& r)
  2161. {
  2162. if (r.contains (clip))
  2163. return nullptr;
  2164. TargetSaver ts (state.target.context);
  2165. makeActive();
  2166. state.blendMode.setBlendMode (state.shaderQuadQueue, true);
  2167. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->solidColourProgram);
  2168. state.shaderQuadQueue.add (r, PixelARGB (0));
  2169. state.shaderQuadQueue.flush();
  2170. return this;
  2171. }
  2172. Ptr clipToPath (const Path& p, const AffineTransform& t)
  2173. {
  2174. EdgeTable et (clip, p, t);
  2175. if (! et.isEmpty())
  2176. {
  2177. TargetSaver ts (state.target.context);
  2178. state.currentShader.clearShader (state.shaderQuadQueue);
  2179. state.shaderQuadQueue.flush();
  2180. state.activeTextures.clear();
  2181. OpenGLTexture texture;
  2182. PositionedTexture pt (texture, et, clip);
  2183. return clipToTexture (pt);
  2184. }
  2185. return nullptr;
  2186. }
  2187. Ptr clipToTexture (const PositionedTexture& pt)
  2188. {
  2189. clip = clip.getIntersection (pt.clip);
  2190. if (clip.isEmpty())
  2191. return nullptr;
  2192. TargetSaver ts (state.target.context);
  2193. makeActive();
  2194. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  2195. state.activeTextures.bindTexture (pt.textureID);
  2196. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->maskTexture);
  2197. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  2198. state.currentShader.programs->maskTexture.imageParams
  2199. .setMatrix (AffineTransform::translation ((float) pt.area.getX(), (float) pt.area.getY()),
  2200. pt.area.getWidth(), pt.area.getHeight(), 1.0f, 1.0f,
  2201. (float) maskArea.getX(), (float) maskArea.getY());
  2202. state.blendMode.setBlendFunc (state.shaderQuadQueue, GL_ZERO, GL_SRC_ALPHA);
  2203. state.shaderQuadQueue.add (clip, PixelARGB (0xffffffff));
  2204. state.shaderQuadQueue.flush();
  2205. return this;
  2206. }
  2207. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  2208. {
  2209. TargetSaver ts (state.target.context);
  2210. makeActive();
  2211. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  2212. state.activeTextures.bindTexture (image.textureID);
  2213. state.currentShader.setShader (maskArea, state.shaderQuadQueue, state.currentShader.programs->maskTexture);
  2214. state.currentShader.programs->maskTexture.imageParams.imageTexture.set (0);
  2215. state.currentShader.programs->maskTexture.imageParams
  2216. .setMatrix (transform, image, (float) maskArea.getX(), (float) maskArea.getY());
  2217. state.shaderQuadQueue.add (clip, PixelARGB (0xffffffff));
  2218. state.shaderQuadQueue.flush();
  2219. return this;
  2220. }
  2221. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  2222. {
  2223. (void) replaceContents; jassert (! replaceContents);
  2224. const Rectangle<int> r (clip.getIntersection (area));
  2225. if (! r.isEmpty())
  2226. {
  2227. ShaderFillOperation fillOp (*this, fill, false);
  2228. state.shaderQuadQueue.add (r, fill.colour.getPixelARGB());
  2229. }
  2230. }
  2231. void fillRect (const Rectangle<float>& area, const FillType& fill)
  2232. {
  2233. ShaderFillOperation fillOp (*this, fill, false);
  2234. FloatRectangleRenderer frr (*this, fill);
  2235. RenderingHelpers::FloatRectangleRasterisingInfo (area).iterate (frr);
  2236. }
  2237. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  2238. {
  2239. if (et.getMaximumBounds().intersects (clip))
  2240. {
  2241. if (! clip.contains (et.getMaximumBounds()))
  2242. et.clipToRectangle (clip);
  2243. ShaderFillOperation fillOp (*this, fill, false);
  2244. state.shaderQuadQueue.add (et, fill.colour.getPixelARGB());
  2245. }
  2246. }
  2247. void drawImage (const Image& image, const AffineTransform& transform,
  2248. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  2249. {
  2250. const Rectangle<int> r (clip.getIntersection (clipArea));
  2251. if (! r.isEmpty())
  2252. {
  2253. const PixelARGB colour (Colours::white.withAlpha (alpha).getPixelARGB());
  2254. ShaderFillOperation fillOp (*this, FillType (image, transform), true);
  2255. if (et != nullptr)
  2256. {
  2257. et->clipToRectangle (r);
  2258. if (! et->isEmpty())
  2259. state.shaderQuadQueue.add (*et, colour);
  2260. }
  2261. else
  2262. {
  2263. state.shaderQuadQueue.add (r, colour);
  2264. }
  2265. }
  2266. state.currentShader.clearShader (state.shaderQuadQueue);
  2267. }
  2268. private:
  2269. OpenGLFrameBuffer mask;
  2270. Rectangle<int> clip, maskArea;
  2271. struct ShaderFillOperation
  2272. {
  2273. ShaderFillOperation (const ClipRegion_Mask_Shader& clip, const FillType& fill, const bool clampTiledImages)
  2274. : state (clip.state)
  2275. {
  2276. const GLuint maskTextureID = clip.mask.getTextureID();
  2277. if (fill.isColour())
  2278. {
  2279. state.blendMode.setPremultipliedBlendingMode (state.shaderQuadQueue);
  2280. state.activeTextures.setSingleTextureMode (state.shaderQuadQueue);
  2281. state.activeTextures.bindTexture (maskTextureID);
  2282. state.setShader (state.currentShader.programs->solidColourMasked);
  2283. state.currentShader.programs->solidColourMasked.maskParams.setBounds (clip.maskArea, state.target, 0);
  2284. }
  2285. else if (fill.isGradient())
  2286. {
  2287. state.setShaderForGradientFill (*fill.gradient, fill.transform, maskTextureID, &clip.maskArea);
  2288. }
  2289. else
  2290. {
  2291. jassert (fill.isTiledImage());
  2292. image = new OpenGLTextureFromImage (fill.image);
  2293. state.setShaderForTiledImageFill (*image, fill.transform, maskTextureID, &clip.maskArea, clampTiledImages);
  2294. }
  2295. }
  2296. ~ShaderFillOperation()
  2297. {
  2298. state.shaderQuadQueue.flush();
  2299. }
  2300. OpenGLGraphicsContext::GLState& state;
  2301. ScopedPointer<OpenGLTextureFromImage> image;
  2302. JUCE_DECLARE_NON_COPYABLE (ShaderFillOperation);
  2303. };
  2304. struct TargetSaver
  2305. {
  2306. TargetSaver (const OpenGLContext& context_)
  2307. : context (context_), oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  2308. {
  2309. glGetIntegerv (GL_VIEWPORT, oldViewport);
  2310. }
  2311. ~TargetSaver()
  2312. {
  2313. context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, oldFramebuffer);
  2314. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  2315. }
  2316. private:
  2317. const OpenGLContext& context;
  2318. GLuint oldFramebuffer;
  2319. GLint oldViewport[4];
  2320. TargetSaver& operator= (const TargetSaver&);
  2321. };
  2322. void makeActive()
  2323. {
  2324. state.shaderQuadQueue.flush();
  2325. state.activeTextures.clear();
  2326. mask.makeCurrentRenderingTarget();
  2327. glViewport (0, 0, maskArea.getWidth(), maskArea.getHeight());
  2328. }
  2329. struct FloatRectangleRenderer
  2330. {
  2331. FloatRectangleRenderer (ClipRegion_Mask_Shader& owner_, const FillType& fill_) noexcept
  2332. : owner (owner_), originalColour (fill_.colour.getPixelARGB())
  2333. {}
  2334. void operator() (int x, int y, int w, int h, const int alpha) noexcept
  2335. {
  2336. if (owner.clip.intersectRectangle (x, y, w, h))
  2337. {
  2338. PixelARGB col (originalColour);
  2339. col.multiplyAlpha (alpha);
  2340. owner.state.shaderQuadQueue.add (x, y, w, h, col);
  2341. }
  2342. }
  2343. private:
  2344. ClipRegion_Mask_Shader& owner;
  2345. const PixelARGB originalColour;
  2346. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  2347. };
  2348. ClipRegion_Mask_Shader& operator= (const ClipRegion_Mask_Shader&);
  2349. };
  2350. //==============================================================================
  2351. class ClipRegion_RectangleList_Shaders : public ClipRegion_RectangleListBase
  2352. {
  2353. public:
  2354. ClipRegion_RectangleList_Shaders (OpenGLGraphicsContext::GLState& state_, const Rectangle<int>& r) noexcept
  2355. : ClipRegion_RectangleListBase (state_, r)
  2356. {}
  2357. ClipRegion_RectangleList_Shaders (OpenGLGraphicsContext::GLState& state_, const RectangleList& r) noexcept
  2358. : ClipRegion_RectangleListBase (state_, r)
  2359. {}
  2360. Ptr clone() const { return new ClipRegion_RectangleList_Shaders (state, clip); }
  2361. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  2362. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  2363. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  2364. void fillRect (const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  2365. {
  2366. ShaderFillOperation fillOp (*this, fill, replaceContents || fill.colour.isOpaque(), false);
  2367. state.shaderQuadQueue.add (clip, area, fill.colour.getPixelARGB());
  2368. }
  2369. void fillRect (const Rectangle<float>& area, const FillType& fill)
  2370. {
  2371. const PixelARGB colour (fill.colour.getPixelARGB());
  2372. ShaderFillOperation fillOp (*this, fill, false, false);
  2373. for (RectangleList::Iterator i (clip); i.next();)
  2374. {
  2375. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  2376. if (! r.isEmpty())
  2377. state.shaderQuadQueue.add (r, colour);
  2378. }
  2379. }
  2380. void drawImage (const Image& image, const AffineTransform& transform,
  2381. float alpha, const Rectangle<int>& clipArea, EdgeTable* et)
  2382. {
  2383. FillType fill (image, transform);
  2384. const PixelARGB colour (Colours::white.withAlpha (alpha).getPixelARGB());
  2385. ShaderFillOperation fillOp (*this, fill, false, true);
  2386. if (et != nullptr)
  2387. {
  2388. if (! clip.containsRectangle (et->getMaximumBounds()))
  2389. et->clipToEdgeTable (EdgeTable (clip));
  2390. state.shaderQuadQueue.add (*et, colour);
  2391. }
  2392. else
  2393. {
  2394. state.shaderQuadQueue.add (clip, clipArea, colour);
  2395. }
  2396. state.currentShader.clearShader (state.shaderQuadQueue);
  2397. }
  2398. void fillEdgeTable (EdgeTable& et, const FillType& fill)
  2399. {
  2400. if (clip.intersects (et.getMaximumBounds()))
  2401. {
  2402. if (! clip.containsRectangle (et.getMaximumBounds()))
  2403. et.clipToEdgeTable (EdgeTable (clip));
  2404. ShaderFillOperation fillOp (*this, fill, false, true);
  2405. state.shaderQuadQueue.add (et, fill.colour.getPixelARGB());
  2406. }
  2407. }
  2408. private:
  2409. Ptr toMask() const { return new ClipRegion_Mask_Shader (state, clip); }
  2410. struct ShaderFillOperation
  2411. {
  2412. ShaderFillOperation (const ClipRegion_RectangleList_Shaders& clip, const FillType& fill,
  2413. const bool replaceContents, const bool clampTiledImages)
  2414. : state (clip.state)
  2415. {
  2416. if (fill.isColour())
  2417. {
  2418. state.activeTextures.disableTextures (state.shaderQuadQueue);
  2419. state.blendMode.setBlendMode (state.shaderQuadQueue, replaceContents);
  2420. state.setShader (state.currentShader.programs->solidColourProgram);
  2421. }
  2422. else if (fill.isGradient())
  2423. {
  2424. state.setShaderForGradientFill (*fill.gradient, fill.transform, 0, nullptr);
  2425. }
  2426. else
  2427. {
  2428. jassert (fill.isTiledImage());
  2429. image = new OpenGLTextureFromImage (fill.image);
  2430. state.setShaderForTiledImageFill (*image, fill.transform, 0, nullptr, clampTiledImages);
  2431. }
  2432. }
  2433. ~ShaderFillOperation()
  2434. {
  2435. if (image != nullptr)
  2436. state.shaderQuadQueue.flush();
  2437. }
  2438. OpenGLGraphicsContext::GLState& state;
  2439. ScopedPointer<OpenGLTextureFromImage> image;
  2440. JUCE_DECLARE_NON_COPYABLE (ShaderFillOperation);
  2441. };
  2442. JUCE_DECLARE_NON_COPYABLE (ClipRegion_RectangleList_Shaders);
  2443. };
  2444. #endif
  2445. //==============================================================================
  2446. class OpenGLGraphicsContext::SavedState
  2447. {
  2448. public:
  2449. SavedState (OpenGLGraphicsContext::GLState* const state_)
  2450. : clip (createRectangleClip (*state_, state_->target.bounds)),
  2451. transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
  2452. state (state_), transparencyLayerAlpha (1.0f)
  2453. {
  2454. }
  2455. SavedState (const SavedState& other)
  2456. : clip (other.clip), transform (other.transform), font (other.font),
  2457. fillType (other.fillType), interpolationQuality (other.interpolationQuality),
  2458. state (other.state), transparencyLayerAlpha (other.transparencyLayerAlpha),
  2459. transparencyLayer (other.transparencyLayer), previousTarget (other.previousTarget.createCopy())
  2460. {
  2461. }
  2462. static ClipRegionBase* createRectangleClip (OpenGLGraphicsContext::GLState& state, const Rectangle<int>& clip)
  2463. {
  2464. #if JUCE_USE_OPENGL_SHADERS
  2465. if (state.currentShader.canUseShaders)
  2466. return new ClipRegion_RectangleList_Shaders (state, clip);
  2467. #endif
  2468. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  2469. return new ClipRegion_RectangleList (state, clip);
  2470. #else
  2471. // there's no shader hardware, but we're compiling without the fixed-function pipeline available!
  2472. jassertfalse;
  2473. return nullptr;
  2474. #endif
  2475. }
  2476. bool clipToRectangle (const Rectangle<int>& r)
  2477. {
  2478. if (clip != nullptr)
  2479. {
  2480. if (transform.isOnlyTranslated)
  2481. {
  2482. cloneClipIfMultiplyReferenced();
  2483. clip = clip->clipToRectangle (transform.translated (r));
  2484. }
  2485. else
  2486. {
  2487. Path p;
  2488. p.addRectangle (r);
  2489. clipToPath (p, AffineTransform::identity);
  2490. }
  2491. }
  2492. return clip != nullptr;
  2493. }
  2494. bool clipToRectangleList (const RectangleList& r)
  2495. {
  2496. if (clip != nullptr)
  2497. {
  2498. if (transform.isOnlyTranslated)
  2499. {
  2500. cloneClipIfMultiplyReferenced();
  2501. RectangleList offsetList (r);
  2502. offsetList.offsetAll (transform.xOffset, transform.yOffset);
  2503. clip = clip->clipToRectangleList (offsetList);
  2504. }
  2505. else
  2506. {
  2507. clipToPath (r.toPath(), AffineTransform::identity);
  2508. }
  2509. }
  2510. return clip != nullptr;
  2511. }
  2512. bool excludeClipRectangle (const Rectangle<int>& r)
  2513. {
  2514. if (clip != nullptr)
  2515. {
  2516. cloneClipIfMultiplyReferenced();
  2517. if (transform.isOnlyTranslated)
  2518. {
  2519. clip = clip->excludeClipRectangle (transform.translated (r));
  2520. }
  2521. else
  2522. {
  2523. Path p;
  2524. p.addRectangle (r.toFloat());
  2525. p.applyTransform (transform.complexTransform);
  2526. p.addRectangle (clip->getClipBounds().toFloat());
  2527. p.setUsingNonZeroWinding (false);
  2528. clip = clip->clipToPath (p, AffineTransform::identity);
  2529. }
  2530. }
  2531. return clip != nullptr;
  2532. }
  2533. void clipToPath (const Path& p, const AffineTransform& t)
  2534. {
  2535. if (clip != nullptr)
  2536. {
  2537. cloneClipIfMultiplyReferenced();
  2538. clip = clip->clipToPath (p, transform.getTransformWith (t));
  2539. }
  2540. }
  2541. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
  2542. {
  2543. if (clip != nullptr)
  2544. {
  2545. Path p;
  2546. p.addRectangle (sourceImage.getBounds());
  2547. clipToPath (p, t);
  2548. if (sourceImage.hasAlphaChannel() && clip != nullptr)
  2549. {
  2550. cloneClipIfMultiplyReferenced();
  2551. clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
  2552. }
  2553. }
  2554. }
  2555. bool clipRegionIntersects (const Rectangle<int>& r) const
  2556. {
  2557. return clip != nullptr
  2558. && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
  2559. : getClipBounds().intersects (r));
  2560. }
  2561. Rectangle<int> getClipBounds() const
  2562. {
  2563. return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
  2564. : Rectangle<int>();
  2565. }
  2566. SavedState* beginTransparencyLayer (float opacity)
  2567. {
  2568. SavedState* s = new SavedState (*this);
  2569. if (clip != nullptr)
  2570. {
  2571. const Rectangle<int> clipBounds (clip->getClipBounds());
  2572. state->flush();
  2573. s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
  2574. s->previousTarget = new OpenGLTarget (state->target);
  2575. state->target = OpenGLTarget (state->target.context, *OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
  2576. s->transparencyLayerAlpha = opacity;
  2577. s->cloneClipIfMultiplyReferenced();
  2578. s->state->target.makeActiveFor2D();
  2579. }
  2580. return s;
  2581. }
  2582. void endTransparencyLayer (SavedState& finishedLayerState)
  2583. {
  2584. if (clip != nullptr)
  2585. {
  2586. jassert (finishedLayerState.previousTarget != nullptr);
  2587. state->flush();
  2588. state->target = *finishedLayerState.previousTarget;
  2589. finishedLayerState.previousTarget = nullptr;
  2590. state->target.makeActiveFor2D();
  2591. const Rectangle<int> clipBounds (clip->getClipBounds());
  2592. clip->drawImage (finishedLayerState.transparencyLayer,
  2593. AffineTransform::translation ((float) clipBounds.getX(), (float) clipBounds.getY()),
  2594. finishedLayerState.transparencyLayerAlpha, clipBounds, nullptr);
  2595. }
  2596. }
  2597. //==============================================================================
  2598. void fillRect (const Rectangle<int>& r, const bool replaceContents)
  2599. {
  2600. if (clip != nullptr)
  2601. {
  2602. if (transform.isOnlyTranslated)
  2603. {
  2604. clip->fillRect (r.translated (transform.xOffset, transform.yOffset),
  2605. getFillType(), replaceContents);
  2606. }
  2607. else
  2608. {
  2609. Path p;
  2610. p.addRectangle (r);
  2611. fillPath (p, AffineTransform::identity);
  2612. }
  2613. }
  2614. }
  2615. void fillRect (const Rectangle<float>& r)
  2616. {
  2617. if (clip != nullptr)
  2618. {
  2619. if (transform.isOnlyTranslated)
  2620. {
  2621. const Rectangle<float> c (r.translated ((float) transform.xOffset, (float) transform.yOffset)
  2622. .getIntersection (clip->getClipBounds().toFloat()));
  2623. if (! c.isEmpty())
  2624. clip->fillRect (c, getFillType());
  2625. }
  2626. else
  2627. {
  2628. Path p;
  2629. p.addRectangle (r);
  2630. fillPath (p, AffineTransform::identity);
  2631. }
  2632. }
  2633. }
  2634. void fillPath (const Path& path, const AffineTransform& t)
  2635. {
  2636. if (clip != nullptr)
  2637. {
  2638. EdgeTable et (clip->getClipBounds(), path, transform.getTransformWith (t));
  2639. fillEdgeTable (et);
  2640. }
  2641. }
  2642. void drawGlyph (int glyphNumber, const AffineTransform& t)
  2643. {
  2644. if (clip != nullptr)
  2645. {
  2646. if (transform.isOnlyTranslated && t.isOnlyTranslation())
  2647. {
  2648. RenderingHelpers::GlyphCache <RenderingHelpers::CachedGlyphEdgeTable <OpenGLGraphicsContext::SavedState>, SavedState>::getInstance()
  2649. .drawGlyph (*this, font, glyphNumber,
  2650. transform.xOffset + t.getTranslationX(),
  2651. transform.yOffset + t.getTranslationY());
  2652. }
  2653. else
  2654. {
  2655. const float fontHeight = font.getHeight();
  2656. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph
  2657. (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  2658. .followedBy (t))));
  2659. if (et != nullptr)
  2660. fillEdgeTable (*et);
  2661. }
  2662. }
  2663. }
  2664. void fillEdgeTable (const EdgeTable& et, const float x, const int y)
  2665. {
  2666. if (clip != nullptr)
  2667. {
  2668. EdgeTable et2 (et);
  2669. et2.translate (x, y);
  2670. fillEdgeTable (et2);
  2671. }
  2672. }
  2673. void drawLine (const Line <float>& line)
  2674. {
  2675. Path p;
  2676. p.addLineSegment (line, 1.0f);
  2677. fillPath (p, AffineTransform::identity);
  2678. }
  2679. //==============================================================================
  2680. void drawImage (const Image& image, const AffineTransform& trans)
  2681. {
  2682. if (clip == nullptr || fillType.colour.isTransparent())
  2683. return;
  2684. const Rectangle<int> clipBounds (clip->getClipBounds());
  2685. const AffineTransform t (transform.getTransformWith (trans));
  2686. const float alpha = fillType.colour.getFloatAlpha();
  2687. if (t.isOnlyTranslation())
  2688. {
  2689. int tx = (int) (t.getTranslationX() * 256.0f);
  2690. int ty = (int) (t.getTranslationY() * 256.0f);
  2691. if (((tx | ty) & 0xf8) == 0)
  2692. {
  2693. tx = ((tx + 128) >> 8);
  2694. ty = ((ty + 128) >> 8);
  2695. clip->drawImage (image, t, alpha, Rectangle<int> (tx, ty, image.getWidth(), image.getHeight()), nullptr);
  2696. return;
  2697. }
  2698. }
  2699. if (! t.isSingularity())
  2700. {
  2701. Path p;
  2702. p.addRectangle (image.getBounds());
  2703. EdgeTable et (clipBounds, p, t);
  2704. clip->drawImage (image, t, alpha, clipBounds, &et);
  2705. }
  2706. }
  2707. void setFillType (const FillType& newFill)
  2708. {
  2709. fillType = newFill;
  2710. state->textureCache.resetGradient();
  2711. }
  2712. //==============================================================================
  2713. ClipRegionBase::Ptr clip;
  2714. RenderingHelpers::TranslationOrTransform transform;
  2715. Font font;
  2716. FillType fillType;
  2717. Graphics::ResamplingQuality interpolationQuality;
  2718. GLState* state;
  2719. private:
  2720. float transparencyLayerAlpha;
  2721. Image transparencyLayer;
  2722. ScopedPointer<OpenGLTarget> previousTarget;
  2723. void cloneClipIfMultiplyReferenced()
  2724. {
  2725. if (clip->getReferenceCount() > 1)
  2726. clip = clip->clone();
  2727. }
  2728. FillType getFillType() const
  2729. {
  2730. return fillType.transformed (transform.getTransform());
  2731. }
  2732. void fillEdgeTable (EdgeTable& et) const
  2733. {
  2734. clip->fillEdgeTable (et, getFillType());
  2735. }
  2736. SavedState& operator= (const SavedState&);
  2737. };
  2738. //==============================================================================
  2739. OpenGLGraphicsContext::OpenGLGraphicsContext (OpenGLComponent& target)
  2740. : glState (new GLState (OpenGLTarget (*target.getCurrentContext(), target.getFrameBufferID(), target.getWidth(), target.getHeight()))),
  2741. stack (new SavedState (glState))
  2742. {
  2743. jassert (target.getCurrentContext() != nullptr); // must have a valid context when this is called!
  2744. }
  2745. OpenGLGraphicsContext::OpenGLGraphicsContext (OpenGLContext& context, OpenGLFrameBuffer& target)
  2746. : glState (new GLState (OpenGLTarget (context, target, Point<int>()))),
  2747. stack (new SavedState (glState))
  2748. {
  2749. }
  2750. OpenGLGraphicsContext::OpenGLGraphicsContext (OpenGLContext& context, unsigned int frameBufferID, int width, int height)
  2751. : glState (new GLState (OpenGLTarget (context, frameBufferID, width, height))),
  2752. stack (new SavedState (glState))
  2753. {
  2754. }
  2755. OpenGLGraphicsContext::~OpenGLGraphicsContext() {}
  2756. bool OpenGLGraphicsContext::isVectorDevice() const { return false; }
  2757. void OpenGLGraphicsContext::setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
  2758. void OpenGLGraphicsContext::addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
  2759. float OpenGLGraphicsContext::getScaleFactor() { return stack->transform.getScaleFactor(); }
  2760. Rectangle<int> OpenGLGraphicsContext::getClipBounds() const { return stack->getClipBounds(); }
  2761. bool OpenGLGraphicsContext::isClipEmpty() const { return stack->clip == nullptr; }
  2762. bool OpenGLGraphicsContext::clipRegionIntersects (const Rectangle<int>& r) { return stack->clipRegionIntersects (r); }
  2763. bool OpenGLGraphicsContext::clipToRectangle (const Rectangle<int>& r) { return stack->clipToRectangle (r); }
  2764. bool OpenGLGraphicsContext::clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
  2765. void OpenGLGraphicsContext::excludeClipRectangle (const Rectangle<int>& r) { stack->excludeClipRectangle (r); }
  2766. void OpenGLGraphicsContext::clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
  2767. void OpenGLGraphicsContext::clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
  2768. void OpenGLGraphicsContext::saveState() { stack.save(); }
  2769. void OpenGLGraphicsContext::restoreState() { stack.restore(); }
  2770. void OpenGLGraphicsContext::beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
  2771. void OpenGLGraphicsContext::endTransparencyLayer() { stack.endTransparencyLayer(); }
  2772. void OpenGLGraphicsContext::setFill (const FillType& fillType) { stack->setFillType (fillType); }
  2773. void OpenGLGraphicsContext::setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
  2774. void OpenGLGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
  2775. void OpenGLGraphicsContext::fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
  2776. void OpenGLGraphicsContext::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
  2777. void OpenGLGraphicsContext::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
  2778. void OpenGLGraphicsContext::drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
  2779. void OpenGLGraphicsContext::drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
  2780. void OpenGLGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
  2781. void OpenGLGraphicsContext::drawLine (const Line <float>& line) { stack->drawLine (line); }
  2782. void OpenGLGraphicsContext::setFont (const Font& newFont) { stack->font = newFont; }
  2783. const Font& OpenGLGraphicsContext::getFont() { return stack->font; }