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.

2705 lines
101KB

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