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.

2280 lines
83KB

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