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.

1664 lines
62KB

  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. }
  64. OpenGLTarget (OpenGLFrameBuffer& frameBuffer_, const Point<int>& origin) noexcept
  65. : frameBuffer (&frameBuffer_), frameBufferID (0), x (origin.x), y (origin.y),
  66. width (frameBuffer_.getWidth()), height (frameBuffer_.getHeight())
  67. {}
  68. OpenGLTarget (const OpenGLTarget& other) noexcept
  69. : frameBuffer (other.frameBuffer), frameBufferID (other.frameBufferID),
  70. x (other.x), y (other.y), width (other.width), height (other.height)
  71. {}
  72. void makeActiveFor2D() const
  73. {
  74. if (frameBuffer != nullptr)
  75. frameBuffer->makeCurrentRenderingTarget();
  76. else
  77. OpenGLFrameBuffer::setCurrentFrameBufferTarget (frameBufferID);
  78. applyFlippedMatrix (x, y, width, height);
  79. glDisable (GL_DEPTH_TEST);
  80. }
  81. void scissor (Rectangle<int> r) const
  82. {
  83. r = r.translated (-x, -y);
  84. OpenGLHelpers::enableScissorTest (r.withY (height - r.getBottom()));
  85. }
  86. static void applyFlippedMatrix (const int x, const int y, const int width, const int height)
  87. {
  88. glMatrixMode (GL_PROJECTION);
  89. glLoadIdentity();
  90. #if JUCE_OPENGL_ES
  91. glOrthof ((GLfloat) x, (GLfloat) (x + width), (GLfloat) (y + height), (GLfloat) y, 0.0f, 1.0f);
  92. #else
  93. glOrtho (x, x + width, y + height, y, 0, 1);
  94. #endif
  95. glViewport (0, 0, width, height);
  96. }
  97. OpenGLFrameBuffer* frameBuffer;
  98. GLuint frameBufferID;
  99. int x, y, width, height;
  100. };
  101. //==============================================================================
  102. class PositionedTexture
  103. {
  104. public:
  105. PositionedTexture (OpenGLTexture& texture, EdgeTable& et, const Rectangle<int>& clip_)
  106. {
  107. et.clipToRectangle (clip_);
  108. EdgeTableData data (et);
  109. texture.loadAlpha (data.data, data.area.getWidth(), data.area.getHeight());
  110. textureID = texture.getTextureID();
  111. clip = et.getMaximumBounds();
  112. area = data.area;
  113. }
  114. PositionedTexture (GLuint textureID_, const Rectangle<int> area_, const Rectangle<int> clip_)
  115. : textureID (textureID_), area (area_), clip (clip_)
  116. {
  117. }
  118. template <typename ValueType>
  119. void getTextureCoordAt (ValueType x, ValueType y, GLfloat& resultX, GLfloat& resultY) const noexcept
  120. {
  121. resultX = (x - area.getX()) / (float) area.getWidth();
  122. resultY = (area.getBottom() - y) / (float) area.getHeight();
  123. }
  124. void enable (GLenum multitextureIndex, const GLfloat* textureCoords) const
  125. {
  126. glActiveTexture (multitextureIndex);
  127. glClientActiveTexture (multitextureIndex);
  128. glBindTexture (GL_TEXTURE_2D, textureID);
  129. glEnable (GL_TEXTURE_2D);
  130. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  131. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  132. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  133. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  134. }
  135. void enable (GLenum multitextureIndex, const Rectangle<int>* const area, GLfloat* const textureCoords) const noexcept
  136. {
  137. if (area != nullptr)
  138. {
  139. getTextureCoordAt (area->getX(), area->getY(), textureCoords[0], textureCoords[1]);
  140. getTextureCoordAt (area->getRight(), area->getY(), textureCoords[2], textureCoords[3]);
  141. getTextureCoordAt (area->getX(), area->getBottom(), textureCoords[4], textureCoords[5]);
  142. getTextureCoordAt (area->getRight(), area->getBottom(), textureCoords[6], textureCoords[7]);
  143. }
  144. enable (multitextureIndex, textureCoords);
  145. }
  146. GLuint textureID;
  147. Rectangle<int> area, clip;
  148. private:
  149. struct EdgeTableData
  150. {
  151. EdgeTableData (const EdgeTable& et)
  152. : area (et.getMaximumBounds().withSize (nextPowerOfTwo (et.getMaximumBounds().getWidth()),
  153. nextPowerOfTwo (et.getMaximumBounds().getHeight())))
  154. {
  155. data.calloc (area.getWidth() * area.getHeight());
  156. et.iterate (*this);
  157. }
  158. inline void setEdgeTableYPos (const int y) noexcept
  159. {
  160. currentLine = data + (area.getBottom() - 1 - y) * area.getWidth() - area.getX();
  161. }
  162. inline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
  163. {
  164. currentLine[x] = (uint8) alphaLevel;
  165. }
  166. inline void handleEdgeTablePixelFull (const int x) const noexcept
  167. {
  168. currentLine[x] = 255;
  169. }
  170. inline void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept
  171. {
  172. memset (currentLine + x, (uint8) alphaLevel, width);
  173. }
  174. inline void handleEdgeTableLineFull (int x, int width) const noexcept
  175. {
  176. memset (currentLine + x, 255, width);
  177. }
  178. HeapBlock<uint8> data;
  179. const Rectangle<int> area;
  180. private:
  181. uint8* currentLine;
  182. JUCE_DECLARE_NON_COPYABLE (EdgeTableData);
  183. };
  184. };
  185. //==============================================================================
  186. class GradientTexture
  187. {
  188. public:
  189. GradientTexture() : needsRefresh (true) {}
  190. enum { textureSize = 256 };
  191. void reset() noexcept
  192. {
  193. needsRefresh = true;
  194. }
  195. void bind (const ColourGradient& gradient)
  196. {
  197. if (needsRefresh)
  198. {
  199. needsRefresh = false;
  200. PixelARGB lookup [textureSize];
  201. gradient.createLookupTable (lookup, textureSize);
  202. texture.loadARGB (lookup, textureSize, 1);
  203. }
  204. texture.bind();
  205. }
  206. private:
  207. OpenGLTexture texture;
  208. bool needsRefresh;
  209. };
  210. //==============================================================================
  211. namespace
  212. {
  213. struct TargetSaver
  214. {
  215. TargetSaver()
  216. : oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  217. {
  218. glGetIntegerv (GL_VIEWPORT, oldViewport);
  219. glPushMatrix();
  220. }
  221. ~TargetSaver()
  222. {
  223. OpenGLFrameBuffer::setCurrentFrameBufferTarget (oldFramebuffer);
  224. glPopMatrix();
  225. glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  226. }
  227. private:
  228. GLuint oldFramebuffer;
  229. GLint oldViewport[4];
  230. };
  231. struct TemporaryColourModulationMode
  232. {
  233. TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); }
  234. ~TemporaryColourModulationMode() { glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); }
  235. };
  236. void fillRectangleList (const RectangleList& list)
  237. {
  238. GLfloat vertices [8];
  239. glEnableClientState (GL_VERTEX_ARRAY);
  240. glVertexPointer (2, GL_FLOAT, 0, vertices);
  241. for (RectangleList::Iterator i (list); i.next();)
  242. {
  243. vertices[0] = vertices[4] = (GLfloat) i.getRectangle()->getX();
  244. vertices[1] = vertices[3] = (GLfloat) i.getRectangle()->getY();
  245. vertices[2] = vertices[6] = (GLfloat) i.getRectangle()->getRight();
  246. vertices[5] = vertices[7] = (GLfloat) i.getRectangle()->getBottom();
  247. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  248. }
  249. }
  250. void fillRectangleList (const RectangleList& list, const Rectangle<int>& clip)
  251. {
  252. GLfloat vertices [8];
  253. glEnableClientState (GL_VERTEX_ARRAY);
  254. glVertexPointer (2, GL_FLOAT, 0, vertices);
  255. for (RectangleList::Iterator i (list); i.next();)
  256. {
  257. const Rectangle<int> r (i.getRectangle()->getIntersection (clip));
  258. vertices[0] = vertices[4] = (GLfloat) r.getX();
  259. vertices[1] = vertices[3] = (GLfloat) r.getY();
  260. vertices[2] = vertices[6] = (GLfloat) r.getRight();
  261. vertices[5] = vertices[7] = (GLfloat) r.getBottom();
  262. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  263. }
  264. }
  265. inline void setColour (const float alpha) noexcept
  266. {
  267. glColor4f (alpha, alpha, alpha, alpha);
  268. }
  269. inline void setPremultipliedColour (const Colour& c) noexcept
  270. {
  271. const PixelARGB p (c.getPixelARGB());
  272. OpenGLHelpers::setColour (Colour (p.getARGB()));
  273. }
  274. void disableMultiTexture (GLenum level)
  275. {
  276. glActiveTexture (level);
  277. glDisable (GL_TEXTURE_2D);
  278. }
  279. void disableMultiTexture()
  280. {
  281. disableMultiTexture (GL_TEXTURE2);
  282. disableMultiTexture (GL_TEXTURE1);
  283. disableMultiTexture (GL_TEXTURE0);
  284. }
  285. void enableSingleTexture()
  286. {
  287. disableMultiTexture (GL_TEXTURE2);
  288. disableMultiTexture (GL_TEXTURE1);
  289. glActiveTexture (GL_TEXTURE0);
  290. glClientActiveTexture (GL_TEXTURE0);
  291. glEnable (GL_TEXTURE_2D);
  292. }
  293. void resetMultiTextureMode (GLenum index, const bool forRGBTextures)
  294. {
  295. glActiveTexture (index);
  296. glClientActiveTexture (index);
  297. glDisable (GL_TEXTURE_2D);
  298. glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  299. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
  300. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
  301. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
  302. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
  303. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, forRGBTextures ? GL_SRC_COLOR : GL_SRC_ALPHA);
  304. glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
  305. glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
  306. glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
  307. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
  308. glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
  309. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  310. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  311. }
  312. void resetMultiTextureModes (const bool forRGBTextures)
  313. {
  314. resetMultiTextureMode (GL_TEXTURE2, forRGBTextures);
  315. resetMultiTextureMode (GL_TEXTURE1, forRGBTextures);
  316. resetMultiTextureMode (GL_TEXTURE0, forRGBTextures);
  317. }
  318. void setPremultipliedBlendingMode() noexcept
  319. {
  320. glEnable (GL_BLEND);
  321. glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  322. }
  323. void setBlendMode (const bool replaceExistingContents) noexcept
  324. {
  325. if (replaceExistingContents)
  326. glDisable (GL_BLEND);
  327. else
  328. setPremultipliedBlendingMode();
  329. }
  330. void prepareMasks (const PositionedTexture* const mask1, const PositionedTexture* const mask2,
  331. GLfloat* const textureCoords1, GLfloat* const textureCoords2, const Rectangle<int>* const area)
  332. {
  333. if (mask1 != nullptr)
  334. {
  335. mask1->enable (GL_TEXTURE0, area, textureCoords1);
  336. if (mask2 != nullptr)
  337. {
  338. mask2->enable (GL_TEXTURE1, area, textureCoords2);
  339. glActiveTexture (GL_TEXTURE2);
  340. glClientActiveTexture (GL_TEXTURE2);
  341. }
  342. else
  343. {
  344. disableMultiTexture (GL_TEXTURE2);
  345. glActiveTexture (GL_TEXTURE1);
  346. glClientActiveTexture (GL_TEXTURE1);
  347. }
  348. }
  349. else
  350. {
  351. disableMultiTexture (GL_TEXTURE2);
  352. disableMultiTexture (GL_TEXTURE1);
  353. glActiveTexture (GL_TEXTURE0);
  354. glClientActiveTexture (GL_TEXTURE0);
  355. }
  356. }
  357. void renderImage (const OpenGLTarget& target, const OpenGLTextureFromImage& image,
  358. const Rectangle<int>& clip, const AffineTransform& transform, float alpha,
  359. const PositionedTexture* mask1, const PositionedTexture* mask2,
  360. const bool replaceExistingContents, const bool isTiled)
  361. {
  362. setBlendMode (replaceExistingContents);
  363. GLfloat textureCoords1[8], textureCoords2[8];
  364. if ((! isTiled) || (isPowerOfTwo (image.imageWidth) && isPowerOfTwo (image.imageHeight)))
  365. {
  366. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &clip);
  367. glEnable (GL_TEXTURE_2D);
  368. glBindTexture (GL_TEXTURE_2D, image.textureID);
  369. glEnableClientState (GL_VERTEX_ARRAY);
  370. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  371. TemporaryColourModulationMode tmm;
  372. setColour (alpha);
  373. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, isTiled ? GL_REPEAT : GL_CLAMP_TO_EDGE);
  374. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, isTiled ? GL_REPEAT : GL_CLAMP_TO_EDGE);
  375. const GLfloat clipX = (GLfloat) clip.getX();
  376. const GLfloat clipY = (GLfloat) clip.getY();
  377. const GLfloat clipR = (GLfloat) clip.getRight();
  378. const GLfloat clipB = (GLfloat) clip.getBottom();
  379. const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  380. GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  381. {
  382. const AffineTransform t (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  383. image.fullHeightProportion / image.imageHeight));
  384. t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  385. t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  386. textureCoords[1] = 1.0f - textureCoords[1];
  387. textureCoords[3] = 1.0f - textureCoords[3];
  388. textureCoords[5] = 1.0f - textureCoords[5];
  389. textureCoords[7] = 1.0f - textureCoords[7];
  390. }
  391. glVertexPointer (2, GL_FLOAT, 0, vertices);
  392. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  393. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  394. }
  395. else
  396. {
  397. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, nullptr);
  398. glEnable (GL_TEXTURE_2D);
  399. glBindTexture (GL_TEXTURE_2D, image.textureID);
  400. glEnableClientState (GL_VERTEX_ARRAY);
  401. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  402. TemporaryColourModulationMode tmm;
  403. setColour (alpha);
  404. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  405. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  406. target.scissor (clip);
  407. glPushMatrix();
  408. OpenGLHelpers::applyTransform (transform);
  409. GLfloat vertices[8];
  410. const GLfloat textureCoords[] = { 0, 1.0f, image.fullWidthProportion, 1.0f,
  411. 0, 1.0f - image.fullHeightProportion, image.fullWidthProportion, 1.0f - image.fullHeightProportion };
  412. glVertexPointer (2, GL_FLOAT, 0, vertices);
  413. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  414. const Rectangle<int> targetArea (clip.toFloat().transformed (transform.inverted()).getSmallestIntegerContainer());
  415. int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), image.imageWidth);
  416. int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), image.imageHeight);
  417. const int right = targetArea.getRight();
  418. const int bottom = targetArea.getBottom();
  419. while (y < bottom)
  420. {
  421. vertices[1] = vertices[3] = (GLfloat) y;
  422. vertices[5] = vertices[7] = (GLfloat) (y + image.imageHeight);
  423. for (int x1 = x; x1 < right; x1 += image.imageWidth)
  424. {
  425. vertices[0] = vertices[4] = (GLfloat) x1;
  426. vertices[2] = vertices[6] = (GLfloat) (x1 + image.imageWidth);
  427. if (mask1 != nullptr)
  428. {
  429. float t[] = { vertices[0], vertices[1], vertices[2], vertices[3],
  430. vertices[4], vertices[5], vertices[6], vertices[7] };
  431. transform.transformPoints (t[0], t[1], t[2], t[3]);
  432. transform.transformPoints (t[4], t[5], t[6], t[7]);
  433. mask1->getTextureCoordAt (t[0], t[1], textureCoords1[0], textureCoords1[1]);
  434. mask1->getTextureCoordAt (t[2], t[3], textureCoords1[2], textureCoords1[3]);
  435. mask1->getTextureCoordAt (t[4], t[5], textureCoords1[4], textureCoords1[5]);
  436. mask1->getTextureCoordAt (t[6], t[7], textureCoords1[6], textureCoords1[7]);
  437. if (mask2 != nullptr)
  438. {
  439. mask2->getTextureCoordAt (t[0], t[1], textureCoords2[0], textureCoords2[1]);
  440. mask2->getTextureCoordAt (t[2], t[3], textureCoords2[2], textureCoords2[3]);
  441. mask2->getTextureCoordAt (t[4], t[5], textureCoords2[4], textureCoords2[5]);
  442. mask2->getTextureCoordAt (t[6], t[7], textureCoords2[6], textureCoords2[7]);
  443. }
  444. }
  445. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  446. }
  447. y += image.imageHeight;
  448. }
  449. glPopMatrix();
  450. glDisable (GL_SCISSOR_TEST);
  451. }
  452. }
  453. void fillWithLinearGradient (GradientTexture& gradientTexture, const Rectangle<int>& rect, const ColourGradient& grad,
  454. const AffineTransform& transform, const PositionedTexture* mask1, const PositionedTexture* mask2)
  455. {
  456. const Point<float> p1 (grad.point1.transformedBy (transform));
  457. const Point<float> p2 (grad.point2.transformedBy (transform));
  458. const Point<float> p3 (Point<float> (grad.point1.x - (grad.point2.y - grad.point1.y) / gradientTexture.textureSize,
  459. grad.point1.y + (grad.point2.x - grad.point1.x) / gradientTexture.textureSize).transformedBy (transform));
  460. const AffineTransform textureTransform (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  461. p2.x, p2.y, 1.0f, 0.0f,
  462. p3.x, p3.y, 0.0f, 1.0f));
  463. const GLfloat l = (GLfloat) rect.getX();
  464. const GLfloat r = (GLfloat) rect.getRight();
  465. const GLfloat t = (GLfloat) rect.getY();
  466. const GLfloat b = (GLfloat) rect.getBottom();
  467. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  468. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  469. textureTransform.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  470. textureTransform.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  471. GLfloat textureCoords1[8], textureCoords2[8];
  472. prepareMasks (mask1, mask2, textureCoords1, textureCoords2, &rect);
  473. TemporaryColourModulationMode tmm;
  474. gradientTexture.bind (grad);
  475. setColour (1.0f);
  476. OpenGLHelpers::drawTriangleStrip (vertices, textureCoords, 4);
  477. }
  478. void fillWithRadialGradient (GradientTexture& gradientTexture, const OpenGLTarget& target, const Rectangle<int>& rect,
  479. const ColourGradient& grad, const AffineTransform& transform,
  480. const PositionedTexture* mask1, const PositionedTexture* mask2)
  481. {
  482. const Point<float> centre (grad.point1.transformedBy (transform));
  483. const float screenRadius = centre.getDistanceFrom (rect.getCentre().toFloat())
  484. + Point<int> (rect.getWidth() / 2,
  485. rect.getHeight() / 2).getDistanceFromOrigin()
  486. + 8.0f;
  487. const AffineTransform inverse (transform.inverted());
  488. const float sourceRadius = jmax (Point<float> (screenRadius, 0.0f).transformedBy (inverse).getDistanceFromOrigin(),
  489. Point<float> (0.0f, screenRadius).transformedBy (inverse).getDistanceFromOrigin());
  490. const int numDivisions = 90;
  491. GLfloat vertices [4 + numDivisions * 2];
  492. GLfloat textureCoords1 [4 + numDivisions * 2];
  493. GLfloat textureCoords2 [4 + numDivisions * 2];
  494. GLfloat textureCoords3 [4 + numDivisions * 2];
  495. {
  496. GLfloat* t = textureCoords1;
  497. *t++ = 0.0f;
  498. *t++ = 0.0f;
  499. const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2);
  500. for (int i = numDivisions + 1; --i >= 0;)
  501. {
  502. *t++ = texturePos;
  503. *t++ = 0.0f;
  504. }
  505. }
  506. {
  507. GLfloat* v = vertices;
  508. *v++ = centre.x;
  509. *v++ = centre.y;
  510. const Point<float> first (grad.point1.translated (0, -sourceRadius)
  511. .transformedBy (transform));
  512. *v++ = first.x;
  513. *v++ = first.y;
  514. for (int i = 1; i < numDivisions; ++i)
  515. {
  516. const float angle = i * (float_Pi * 2.0f / numDivisions);
  517. const Point<float> p (grad.point1.translated (std::sin (angle) * sourceRadius,
  518. std::cos (angle) * -sourceRadius)
  519. .transformedBy (transform));
  520. *v++ = p.x;
  521. *v++ = p.y;
  522. }
  523. *v++ = first.x;
  524. *v++ = first.y;
  525. }
  526. prepareMasks (mask1, mask2, textureCoords2, textureCoords3, nullptr);
  527. if (mask1 != nullptr)
  528. {
  529. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  530. mask1->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords2[i], textureCoords2[i + 1]);
  531. if (mask2 != nullptr)
  532. for (int i = 0; i < 2 * (numDivisions + 2); i += 2)
  533. mask2->getTextureCoordAt (vertices[i], vertices[i + 1], textureCoords3[i], textureCoords3[i + 1]);
  534. }
  535. gradientTexture.bind (grad);
  536. target.scissor (rect);
  537. glEnable (GL_TEXTURE_2D);
  538. TemporaryColourModulationMode tmm;
  539. glEnableClientState (GL_VERTEX_ARRAY);
  540. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  541. glVertexPointer (2, GL_FLOAT, 0, vertices);
  542. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords1);
  543. setColour (1.0f);
  544. glDrawArrays (GL_TRIANGLE_FAN, 0, numDivisions + 2);
  545. glDisable (GL_SCISSOR_TEST);
  546. }
  547. void fillTexture (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, GradientTexture& gradientTexture,
  548. const PositionedTexture* mask1, const PositionedTexture* mask2, const bool replaceExistingContents)
  549. {
  550. jassert (! (mask1 == nullptr && mask2 != nullptr));
  551. if (fill.isColour())
  552. {
  553. GLfloat textureCoords1[8], textureCoords2[8];
  554. disableMultiTexture (GL_TEXTURE2);
  555. if (mask1 != nullptr)
  556. {
  557. setBlendMode (replaceExistingContents);
  558. mask1->enable (GL_TEXTURE0, &area, textureCoords1);
  559. if (mask2 != nullptr)
  560. mask2->enable (GL_TEXTURE1, &area, textureCoords2);
  561. else
  562. disableMultiTexture (GL_TEXTURE1);
  563. }
  564. else
  565. {
  566. setBlendMode (replaceExistingContents || fill.colour.isOpaque());
  567. disableMultiTexture (GL_TEXTURE1);
  568. disableMultiTexture (GL_TEXTURE0);
  569. }
  570. setPremultipliedColour (fill.colour);
  571. glEnableClientState (GL_VERTEX_ARRAY);
  572. OpenGLHelpers::fillRect (area);
  573. }
  574. else if (fill.isGradient())
  575. {
  576. ColourGradient g2 (*(fill.gradient));
  577. g2.multiplyOpacity (fill.getOpacity());
  578. if (g2.point1 == g2.point2)
  579. {
  580. fillTexture (target, area, g2.getColourAtPosition (1.0), gradientTexture, mask1, mask2, replaceExistingContents);
  581. }
  582. else
  583. {
  584. setBlendMode (replaceExistingContents || (mask1 == nullptr && fill.colour.isOpaque() && fill.gradient->isOpaque()));
  585. if (g2.isRadial)
  586. fillWithRadialGradient (gradientTexture, target, area, g2, fill.transform, mask1, mask2);
  587. else
  588. fillWithLinearGradient (gradientTexture, area, g2, fill.transform, mask1, mask2);
  589. }
  590. }
  591. else if (fill.isTiledImage())
  592. {
  593. renderImage (target, fill.image, area, fill.transform, fill.colour.getFloatAlpha(),
  594. mask1, mask2, replaceExistingContents, true);
  595. }
  596. }
  597. //==============================================================================
  598. struct VariableAlphaColour
  599. {
  600. VariableAlphaColour (const Colour& c) noexcept
  601. : r (c.getFloatRed()), g (c.getFloatGreen()), b (c.getFloatBlue()),
  602. alphaScale (c.getFloatAlpha() / 255.0f), lastAlpha (-1)
  603. {}
  604. void setForAlpha (const int alpha) noexcept
  605. {
  606. if (lastAlpha != alpha)
  607. {
  608. lastAlpha = alpha;
  609. const float a = alpha * alphaScale;
  610. glColor4f (r * a, g * a, b * a, a);
  611. }
  612. }
  613. private:
  614. const float r, g, b, alphaScale;
  615. int lastAlpha;
  616. JUCE_DECLARE_NON_COPYABLE (VariableAlphaColour);
  617. };
  618. //==============================================================================
  619. struct EdgeTableRenderer
  620. {
  621. EdgeTableRenderer (const Colour& c) noexcept
  622. : colour (c)
  623. {}
  624. void draw (const EdgeTable& et)
  625. {
  626. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  627. glEnableClientState (GL_VERTEX_ARRAY);
  628. glVertexPointer (2, GL_FLOAT, 0, vertices);
  629. et.iterate (*this);
  630. }
  631. void setEdgeTableYPos (const int y) noexcept
  632. {
  633. vertices[1] = vertices[5] = (GLfloat) y;
  634. vertices[3] = vertices[7] = (GLfloat) (y + 1);
  635. }
  636. void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
  637. {
  638. drawHorizontal (x, 1, alphaLevel);
  639. }
  640. void handleEdgeTablePixelFull (const int x) noexcept
  641. {
  642. drawHorizontal (x, 1, 255);
  643. }
  644. void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept
  645. {
  646. drawHorizontal (x, width, alphaLevel);
  647. }
  648. void handleEdgeTableLineFull (const int x, const int width) noexcept
  649. {
  650. drawHorizontal (x, width, 255);
  651. }
  652. private:
  653. GLfloat vertices[8];
  654. VariableAlphaColour colour;
  655. void drawHorizontal (int x, const int w, const int alpha) noexcept
  656. {
  657. vertices[0] = vertices[2] = (GLfloat) x;
  658. vertices[4] = vertices[6] = (GLfloat) (x + w);
  659. colour.setForAlpha (alpha);
  660. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  661. }
  662. JUCE_DECLARE_NON_COPYABLE (EdgeTableRenderer);
  663. };
  664. //==============================================================================
  665. struct FloatRectangleRenderer
  666. {
  667. FloatRectangleRenderer (const Colour& c) noexcept
  668. : colour (c)
  669. {}
  670. void draw (const Rectangle<float>& r)
  671. {
  672. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  673. glEnableClientState (GL_VERTEX_ARRAY);
  674. glVertexPointer (2, GL_FLOAT, 0, vertices);
  675. RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (*this);
  676. }
  677. void operator() (const int x, const int y, const int w, const int h, const int alpha)
  678. {
  679. vertices[0] = vertices[2] = (GLfloat) x;
  680. vertices[1] = vertices[5] = (GLfloat) y;
  681. vertices[4] = vertices[6] = (GLfloat) (x + w);
  682. vertices[3] = vertices[7] = (GLfloat) (y + h);
  683. colour.setForAlpha (alpha);
  684. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  685. }
  686. private:
  687. GLfloat vertices[8];
  688. VariableAlphaColour colour;
  689. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer);
  690. };
  691. }
  692. //==============================================================================
  693. class ClipRegion_Mask;
  694. //==============================================================================
  695. class ClipRegionBase : public SingleThreadedReferenceCountedObject
  696. {
  697. public:
  698. ClipRegionBase() noexcept {}
  699. virtual ~ClipRegionBase() {}
  700. typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
  701. virtual Ptr clone() const = 0;
  702. virtual Ptr applyClipTo (const Ptr& target) = 0;
  703. virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
  704. virtual Ptr clipToRectangleList (const RectangleList&) = 0;
  705. virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
  706. virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
  707. virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
  708. virtual Ptr clipToTexture (const PositionedTexture&) = 0;
  709. virtual Rectangle<int> getClipBounds() const = 0;
  710. virtual void fillRect (const OpenGLTarget&, const Rectangle<int>& area, const FillType&, GradientTexture&, bool replaceContents) = 0;
  711. virtual void fillRect (const OpenGLTarget&, const Rectangle<float>& area, const FillType&, GradientTexture&) = 0;
  712. virtual void fillMask (const OpenGLTarget& target, const Rectangle<int>& area, const PositionedTexture&, const FillType&, GradientTexture&) = 0;
  713. virtual void fillEdgeTable (const OpenGLTarget& target, EdgeTable& et, const FillType& fill, GradientTexture& gradientTexture) = 0;
  714. virtual void drawImage (const OpenGLTarget&, const OpenGLTextureFromImage&, const AffineTransform&, float alpha,
  715. const Rectangle<int>& clip, const PositionedTexture* mask) = 0;
  716. private:
  717. JUCE_DECLARE_NON_COPYABLE (ClipRegionBase);
  718. };
  719. //==============================================================================
  720. class ClipRegion_Mask : public ClipRegionBase
  721. {
  722. public:
  723. ClipRegion_Mask (const ClipRegion_Mask& other)
  724. : clip (other.clip),
  725. maskOrigin (other.clip.getPosition())
  726. {
  727. TargetSaver ts;
  728. mask.initialise (clip.getWidth(), clip.getHeight());
  729. OpenGLTarget m (mask, maskOrigin);
  730. m.makeActiveFor2D();
  731. glDisable (GL_BLEND);
  732. setColour (1.0f);
  733. drawFrameBuffer (other.mask, other.maskOrigin);
  734. }
  735. explicit ClipRegion_Mask (const RectangleList& r)
  736. : clip (r.getBounds()),
  737. maskOrigin (clip.getPosition())
  738. {
  739. TargetSaver ts;
  740. initialiseClear();
  741. disableMultiTexture();
  742. setColour (1.0f);
  743. fillRectangleList (r);
  744. }
  745. Ptr clone() const { return new ClipRegion_Mask (*this); }
  746. Rectangle<int> getClipBounds() const { return clip; }
  747. Ptr applyClipTo (const Ptr& target)
  748. {
  749. return target->clipToTexture (PositionedTexture (mask.getTextureID(), Rectangle<int> (maskOrigin.x, maskOrigin.y,
  750. mask.getWidth(), mask.getHeight()), clip));
  751. }
  752. Ptr clipToRectangle (const Rectangle<int>& r)
  753. {
  754. clip = clip.getIntersection (r);
  755. return clip.isEmpty() ? nullptr : this;
  756. }
  757. Ptr clipToRectangleList (const RectangleList& r)
  758. {
  759. clip = clip.getIntersection (r.getBounds());
  760. if (clip.isEmpty())
  761. return nullptr;
  762. RectangleList excluded (clip);
  763. if (excluded.subtract (r))
  764. {
  765. if (excluded.getNumRectangles() == 1)
  766. return excludeClipRectangle (excluded.getRectangle (0));
  767. TargetSaver ts;
  768. makeMaskActive();
  769. disableMultiTexture();
  770. glDisable (GL_BLEND);
  771. setColour (0);
  772. fillRectangleList (excluded);
  773. }
  774. return this;
  775. }
  776. Ptr excludeClipRectangle (const Rectangle<int>& r)
  777. {
  778. if (r.contains (clip))
  779. return nullptr;
  780. TargetSaver ts;
  781. makeMaskActive();
  782. disableMultiTexture();
  783. glDisable (GL_BLEND);
  784. setColour (0);
  785. OpenGLHelpers::fillRect (r);
  786. return this;
  787. }
  788. Ptr clipToPath (const Path& p, const AffineTransform& t)
  789. {
  790. EdgeTable et (clip, p, t);
  791. if (! et.isEmpty())
  792. {
  793. OpenGLTexture texture;
  794. PositionedTexture pt (texture, et, et.getMaximumBounds());
  795. return clipToTexture (pt);
  796. }
  797. return nullptr;
  798. }
  799. Ptr clipToTexture (const PositionedTexture& pt)
  800. {
  801. clip = clip.getIntersection (pt.clip);
  802. if (clip.isEmpty())
  803. return nullptr;
  804. TargetSaver ts;
  805. makeMaskActive();
  806. glEnable (GL_BLEND);
  807. glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
  808. setColour (1.0f);
  809. enableSingleTexture();
  810. OpenGLHelpers::drawTextureQuad (pt.textureID, pt.area);
  811. return this;
  812. }
  813. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  814. {
  815. TargetSaver ts;
  816. makeMaskActive();
  817. glEnable (GL_BLEND);
  818. glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
  819. setColour (1.0f);
  820. glBindTexture (GL_TEXTURE_2D, image.textureID);
  821. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  822. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  823. const GLfloat l = (GLfloat) maskOrigin.x;
  824. const GLfloat t = (GLfloat) maskOrigin.y;
  825. const GLfloat r = (GLfloat) (maskOrigin.x + mask.getWidth());
  826. const GLfloat b = (GLfloat) (maskOrigin.y + mask.getHeight());
  827. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  828. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  829. const AffineTransform inv (transform.inverted().scaled (image.fullWidthProportion / image.imageWidth,
  830. image.fullHeightProportion / image.imageHeight));
  831. inv.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  832. inv.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  833. textureCoords[1] = 1.0f - textureCoords[1];
  834. textureCoords[3] = 1.0f - textureCoords[3];
  835. textureCoords[5] = 1.0f - textureCoords[5];
  836. textureCoords[7] = 1.0f - textureCoords[7];
  837. OpenGLHelpers::drawTriangleStrip (vertices, textureCoords, 4);
  838. return this;
  839. }
  840. void fillRect (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, GradientTexture& gradientTexture, bool replaceContents)
  841. {
  842. jassert (! replaceContents);
  843. const Rectangle<int> r (clip.getIntersection (area));
  844. if (! r.isEmpty())
  845. fillRectInternal (target, r, fill, gradientTexture, false);
  846. }
  847. void fillRect (const OpenGLTarget& target, const Rectangle<float>& area, const FillType& fill, GradientTexture& gradientTexture)
  848. {
  849. EdgeTable et (area);
  850. fillEdgeTable (target, et, fill, gradientTexture);
  851. }
  852. void fillMask (const OpenGLTarget& target, const Rectangle<int>& area, const PositionedTexture& texture, const FillType& fill, GradientTexture& gradientTexture)
  853. {
  854. PositionedTexture pt (mask.getTextureID(), Rectangle<int> (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()), area);
  855. fillTexture (target, area, fill, gradientTexture, &texture, &pt, false);
  856. }
  857. void fillEdgeTable (const OpenGLTarget& target, EdgeTable& et, const FillType& fill, GradientTexture& gradientTexture)
  858. {
  859. OpenGLTexture texture;
  860. PositionedTexture pt (texture, et, clip);
  861. fillMask (target, pt.clip, pt, fill, gradientTexture);
  862. }
  863. void fillRectInternal (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, GradientTexture& gradientTexture, bool replaceContents)
  864. {
  865. PositionedTexture pt (mask.getTextureID(), Rectangle<int> (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()), area);
  866. fillTexture (target, area, fill, gradientTexture, &pt, nullptr, replaceContents);
  867. }
  868. void drawImage (const OpenGLTarget& target, const OpenGLTextureFromImage& source, const AffineTransform& transform,
  869. float alpha, const Rectangle<int>& clipArea, const PositionedTexture* mask1)
  870. {
  871. const Rectangle<int> bufferArea (clipArea.getIntersection (clip));
  872. if (! bufferArea.isEmpty())
  873. {
  874. PositionedTexture pt (mask.getTextureID(), Rectangle<int> (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()), bufferArea);
  875. renderImage (target, source, bufferArea, transform, alpha, mask1, &pt, false, false);
  876. }
  877. }
  878. private:
  879. OpenGLFrameBuffer mask;
  880. Rectangle<int> clip;
  881. Point<int> maskOrigin;
  882. void prepareFor2D() const
  883. {
  884. OpenGLTarget::applyFlippedMatrix (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight());
  885. }
  886. void makeMaskActive()
  887. {
  888. const bool b = mask.makeCurrentRenderingTarget();
  889. (void) b; jassert (b);
  890. prepareFor2D();
  891. }
  892. void initialiseClear()
  893. {
  894. jassert (! clip.isEmpty());
  895. mask.initialise (clip.getWidth(), clip.getHeight());
  896. mask.makeCurrentAndClear();
  897. glDisable (GL_TEXTURE_2D);
  898. glDisable (GL_BLEND);
  899. prepareFor2D();
  900. }
  901. void drawFrameBuffer (const OpenGLFrameBuffer& buffer, const Point<int>& topLeft)
  902. {
  903. enableSingleTexture();
  904. OpenGLHelpers::drawTextureQuad (buffer.getTextureID(), Rectangle<int> (topLeft.x, topLeft.y,
  905. buffer.getWidth(), buffer.getHeight()));
  906. }
  907. ClipRegion_Mask& operator= (const ClipRegion_Mask&);
  908. };
  909. //==============================================================================
  910. class ClipRegion_RectangleList : public ClipRegionBase
  911. {
  912. public:
  913. explicit ClipRegion_RectangleList (const Rectangle<int>& r) noexcept
  914. : clip (r)
  915. {}
  916. explicit ClipRegion_RectangleList (const RectangleList& r) noexcept
  917. : clip (r)
  918. {}
  919. Ptr clone() const { return new ClipRegion_RectangleList (clip); }
  920. Rectangle<int> getClipBounds() const { return clip.getBounds(); }
  921. Ptr applyClipTo (const Ptr& target) { return target->clipToRectangleList (clip); }
  922. Ptr clipToRectangle (const Rectangle<int>& r) { return clip.clipTo (r) ? this : nullptr; }
  923. Ptr clipToRectangleList (const RectangleList& r) { return clip.clipTo (r) ? this : nullptr; }
  924. Ptr excludeClipRectangle (const Rectangle<int>& r) { clip.subtract (r); return clip.isEmpty() ? nullptr : this; }
  925. Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); }
  926. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  927. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  928. void fillRect (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, GradientTexture& gradientTexture, bool replaceContents)
  929. {
  930. if (fill.isColour())
  931. {
  932. disableMultiTexture();
  933. setBlendMode (replaceContents || fill.colour.isOpaque());
  934. setPremultipliedColour (fill.colour);
  935. fillRectangleList (clip, area);
  936. }
  937. else
  938. {
  939. for (RectangleList::Iterator i (clip); i.next();)
  940. {
  941. const Rectangle<int> r (i.getRectangle()->getIntersection (area));
  942. if (! r.isEmpty())
  943. fillTexture (target, r, fill, gradientTexture, nullptr, nullptr, replaceContents);
  944. }
  945. }
  946. }
  947. void fillRect (const OpenGLTarget& target, const Rectangle<float>& area, const FillType& fill, GradientTexture& gradientTexture)
  948. {
  949. if (fill.isColour())
  950. {
  951. disableMultiTexture();
  952. setPremultipliedBlendingMode();
  953. setPremultipliedColour (fill.colour);
  954. for (RectangleList::Iterator i (clip); i.next();)
  955. {
  956. const Rectangle<float> r (i.getRectangle()->toFloat().getIntersection (area));
  957. if (! r.isEmpty())
  958. {
  959. FloatRectangleRenderer frr (fill.colour);
  960. frr.draw (r);
  961. }
  962. }
  963. }
  964. else
  965. {
  966. EdgeTable et (area);
  967. fillEdgeTable (target, et, fill, gradientTexture);
  968. }
  969. }
  970. void drawImage (const OpenGLTarget& target, const OpenGLTextureFromImage& source, const AffineTransform& transform,
  971. float alpha, const Rectangle<int>& clipArea, const PositionedTexture* mask)
  972. {
  973. for (RectangleList::Iterator i (clip); i.next();)
  974. {
  975. const Rectangle<int> bufferArea (i.getRectangle()->getIntersection (clipArea));
  976. if (! bufferArea.isEmpty())
  977. renderImage (target, source, bufferArea, transform, alpha, mask, nullptr, false, false);
  978. }
  979. }
  980. void fillEdgeTable (const OpenGLTarget& target, EdgeTable& et, const FillType& fill, GradientTexture& gradientTexture)
  981. {
  982. if (fill.isColour())
  983. {
  984. setPremultipliedBlendingMode();
  985. disableMultiTexture (GL_TEXTURE2);
  986. disableMultiTexture (GL_TEXTURE1);
  987. disableMultiTexture (GL_TEXTURE0);
  988. for (RectangleList::Iterator i (clip); i.next();)
  989. {
  990. const Rectangle<int> r (i.getRectangle()->getIntersection (et.getMaximumBounds()));
  991. if (! r.isEmpty())
  992. {
  993. target.scissor (r);
  994. EdgeTableRenderer etr (fill.colour);
  995. etr.draw (et);
  996. }
  997. }
  998. glDisable (GL_SCISSOR_TEST);
  999. }
  1000. else
  1001. {
  1002. OpenGLTexture texture;
  1003. PositionedTexture pt (texture, et, clip.getBounds());
  1004. fillMask (target, pt.clip, pt, fill, gradientTexture);
  1005. }
  1006. }
  1007. void fillMask (const OpenGLTarget& target, const Rectangle<int>& area, const PositionedTexture& texture, const FillType& fill, GradientTexture& gradientTexture)
  1008. {
  1009. fillTexture (target, area, fill, gradientTexture, &texture, nullptr, false);
  1010. }
  1011. private:
  1012. RectangleList clip;
  1013. Ptr toMask() const
  1014. {
  1015. return new ClipRegion_Mask (clip);
  1016. }
  1017. ClipRegion_RectangleList& operator= (const ClipRegion_RectangleList&);
  1018. };
  1019. //==============================================================================
  1020. class OpenGLRenderer::SavedState
  1021. {
  1022. public:
  1023. SavedState (const OpenGLTarget& target_)
  1024. : clip (new ClipRegion_RectangleList (Rectangle<int> (target_.width, target_.height))),
  1025. transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
  1026. target (target_), transparencyLayerAlpha (1.0f)
  1027. {
  1028. }
  1029. SavedState (const SavedState& other)
  1030. : clip (other.clip), transform (other.transform), font (other.font),
  1031. fillType (other.fillType), interpolationQuality (other.interpolationQuality),
  1032. target (other.target), transparencyLayerAlpha (other.transparencyLayerAlpha),
  1033. transparencyLayer (other.transparencyLayer)
  1034. {
  1035. }
  1036. bool clipToRectangle (const Rectangle<int>& r)
  1037. {
  1038. if (clip != nullptr)
  1039. {
  1040. if (transform.isOnlyTranslated)
  1041. {
  1042. cloneClipIfMultiplyReferenced();
  1043. clip = clip->clipToRectangle (transform.translated (r));
  1044. }
  1045. else
  1046. {
  1047. Path p;
  1048. p.addRectangle (r);
  1049. clipToPath (p, AffineTransform::identity);
  1050. }
  1051. }
  1052. return clip != nullptr;
  1053. }
  1054. bool clipToRectangleList (const RectangleList& r)
  1055. {
  1056. if (clip != nullptr)
  1057. {
  1058. if (transform.isOnlyTranslated)
  1059. {
  1060. cloneClipIfMultiplyReferenced();
  1061. RectangleList offsetList (r);
  1062. offsetList.offsetAll (transform.xOffset, transform.yOffset);
  1063. clip = clip->clipToRectangleList (offsetList);
  1064. }
  1065. else
  1066. {
  1067. clipToPath (r.toPath(), AffineTransform::identity);
  1068. }
  1069. }
  1070. return clip != nullptr;
  1071. }
  1072. bool excludeClipRectangle (const Rectangle<int>& r)
  1073. {
  1074. if (clip != nullptr)
  1075. {
  1076. cloneClipIfMultiplyReferenced();
  1077. if (transform.isOnlyTranslated)
  1078. {
  1079. clip = clip->excludeClipRectangle (transform.translated (r));
  1080. }
  1081. else
  1082. {
  1083. Path p;
  1084. p.addRectangle (r.toFloat());
  1085. p.applyTransform (transform.complexTransform);
  1086. p.addRectangle (clip->getClipBounds().toFloat());
  1087. p.setUsingNonZeroWinding (false);
  1088. clip = clip->clipToPath (p, AffineTransform::identity);
  1089. }
  1090. }
  1091. return clip != nullptr;
  1092. }
  1093. void clipToPath (const Path& p, const AffineTransform& t)
  1094. {
  1095. if (clip != nullptr)
  1096. {
  1097. cloneClipIfMultiplyReferenced();
  1098. clip = clip->clipToPath (p, transform.getTransformWith (t));
  1099. }
  1100. }
  1101. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
  1102. {
  1103. if (clip != nullptr)
  1104. {
  1105. Path p;
  1106. p.addRectangle (sourceImage.getBounds());
  1107. clipToPath (p, t);
  1108. if (sourceImage.hasAlphaChannel() && clip != nullptr)
  1109. {
  1110. cloneClipIfMultiplyReferenced();
  1111. clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
  1112. }
  1113. }
  1114. }
  1115. bool clipRegionIntersects (const Rectangle<int>& r) const
  1116. {
  1117. return clip != nullptr
  1118. && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
  1119. : getClipBounds().intersects (r));
  1120. }
  1121. Rectangle<int> getClipBounds() const
  1122. {
  1123. return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
  1124. : Rectangle<int>();
  1125. }
  1126. SavedState* beginTransparencyLayer (float opacity)
  1127. {
  1128. SavedState* s = new SavedState (*this);
  1129. if (clip != nullptr)
  1130. {
  1131. const Rectangle<int> clipBounds (clip->getClipBounds());
  1132. s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
  1133. s->target = OpenGLTarget (*OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
  1134. s->transparencyLayerAlpha = opacity;
  1135. s->cloneClipIfMultiplyReferenced();
  1136. s->target.makeActiveFor2D();
  1137. }
  1138. return s;
  1139. }
  1140. void endTransparencyLayer (SavedState& finishedLayerState)
  1141. {
  1142. if (clip != nullptr)
  1143. {
  1144. target.makeActiveFor2D();
  1145. const Rectangle<int> clipBounds (clip->getClipBounds());
  1146. clip->drawImage (target, finishedLayerState.transparencyLayer,
  1147. AffineTransform::translation ((float) clipBounds.getX(), (float) clipBounds.getY()),
  1148. finishedLayerState.transparencyLayerAlpha, clipBounds, nullptr);
  1149. }
  1150. }
  1151. //==============================================================================
  1152. void fillRect (const Rectangle<int>& r, const bool replaceContents)
  1153. {
  1154. if (clip != nullptr)
  1155. {
  1156. if (transform.isOnlyTranslated)
  1157. {
  1158. clip->fillRect (target, r.translated (transform.xOffset, transform.yOffset),
  1159. getFillType(), gradientTexture, replaceContents);
  1160. }
  1161. else
  1162. {
  1163. Path p;
  1164. p.addRectangle (r);
  1165. fillPath (p, AffineTransform::identity);
  1166. }
  1167. }
  1168. }
  1169. void fillRect (const Rectangle<float>& r)
  1170. {
  1171. if (clip != nullptr)
  1172. {
  1173. if (transform.isOnlyTranslated)
  1174. {
  1175. const Rectangle<float> c (r.translated ((float) transform.xOffset, (float) transform.yOffset)
  1176. .getIntersection (clip->getClipBounds().toFloat()));
  1177. if (! c.isEmpty())
  1178. clip->fillRect (target, c, getFillType(), gradientTexture);
  1179. }
  1180. else
  1181. {
  1182. Path p;
  1183. p.addRectangle (r);
  1184. fillPath (p, AffineTransform::identity);
  1185. }
  1186. }
  1187. }
  1188. void fillPath (const Path& path, const AffineTransform& t)
  1189. {
  1190. if (clip != nullptr)
  1191. {
  1192. EdgeTable et (clip->getClipBounds(), path, transform.getTransformWith (t));
  1193. fillEdgeTable (et);
  1194. }
  1195. }
  1196. void drawGlyph (int glyphNumber, const AffineTransform& t)
  1197. {
  1198. if (clip != nullptr)
  1199. {
  1200. if (transform.isOnlyTranslated && t.isOnlyTranslation())
  1201. {
  1202. RenderingHelpers::GlyphCache <CachedGlyphEdgeTable, SavedState>::getInstance()
  1203. .drawGlyph (*this, font, glyphNumber,
  1204. transform.xOffset + t.getTranslationX(),
  1205. transform.yOffset + t.getTranslationY());
  1206. }
  1207. else
  1208. {
  1209. const float fontHeight = font.getHeight();
  1210. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph
  1211. (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  1212. .followedBy (t))));
  1213. if (et != nullptr)
  1214. fillEdgeTable (*et);
  1215. }
  1216. }
  1217. }
  1218. void fillEdgeTable (const EdgeTable& et, const float x, const int y)
  1219. {
  1220. if (clip != nullptr)
  1221. {
  1222. EdgeTable et2 (et);
  1223. et2.translate (x, y);
  1224. fillEdgeTable (et2);
  1225. }
  1226. }
  1227. void drawLine (const Line <float>& line)
  1228. {
  1229. Path p;
  1230. p.addLineSegment (line, 1.0f);
  1231. fillPath (p, AffineTransform::identity);
  1232. }
  1233. //==============================================================================
  1234. void drawImage (const Image& image, const AffineTransform& trans)
  1235. {
  1236. if (clip == nullptr || fillType.colour.isTransparent())
  1237. return;
  1238. const Rectangle<int> clipBounds (clip->getClipBounds());
  1239. const AffineTransform t (transform.getTransformWith (trans));
  1240. const float alpha = fillType.colour.getFloatAlpha();
  1241. if (t.isOnlyTranslation())
  1242. {
  1243. int tx = (int) (t.getTranslationX() * 256.0f);
  1244. int ty = (int) (t.getTranslationY() * 256.0f);
  1245. if (((tx | ty) & 0xf8) == 0)
  1246. {
  1247. tx = ((tx + 128) >> 8);
  1248. ty = ((ty + 128) >> 8);
  1249. clip->drawImage (target, image, t, alpha, Rectangle<int> (tx, ty, image.getWidth(), image.getHeight()), nullptr);
  1250. return;
  1251. }
  1252. }
  1253. if (! t.isSingularity())
  1254. {
  1255. Path p;
  1256. p.addRectangle (image.getBounds());
  1257. OpenGLTexture texture;
  1258. EdgeTable et (clipBounds, p, t);
  1259. PositionedTexture pt (texture, et, clipBounds);
  1260. clip->drawImage (target, image, t, alpha, clipBounds, &pt);
  1261. }
  1262. }
  1263. void setFillType (const FillType& newFill)
  1264. {
  1265. fillType = newFill;
  1266. gradientTexture.reset();
  1267. }
  1268. //==============================================================================
  1269. ClipRegionBase::Ptr clip;
  1270. RenderingHelpers::TranslationOrTransform transform;
  1271. Font font;
  1272. FillType fillType;
  1273. Graphics::ResamplingQuality interpolationQuality;
  1274. OpenGLTarget target;
  1275. private:
  1276. float transparencyLayerAlpha;
  1277. Image transparencyLayer;
  1278. GradientTexture gradientTexture;
  1279. void cloneClipIfMultiplyReferenced()
  1280. {
  1281. if (clip->getReferenceCount() > 1)
  1282. clip = clip->clone();
  1283. }
  1284. FillType getFillType() const
  1285. {
  1286. return fillType.transformed (transform.getTransform());
  1287. }
  1288. void fillEdgeTable (EdgeTable& et)
  1289. {
  1290. clip->fillEdgeTable (target, et, getFillType(), gradientTexture);
  1291. }
  1292. class CachedGlyphEdgeTable
  1293. {
  1294. public:
  1295. CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}
  1296. void draw (OpenGLRenderer::SavedState& state, float x, const float y) const
  1297. {
  1298. if (snapToIntegerCoordinate)
  1299. x = std::floor (x + 0.5f);
  1300. if (edgeTable != nullptr)
  1301. state.fillEdgeTable (*edgeTable, x, roundToInt (y));
  1302. }
  1303. void generate (const Font& newFont, const int glyphNumber)
  1304. {
  1305. font = newFont;
  1306. snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
  1307. glyph = glyphNumber;
  1308. const float fontHeight = font.getHeight();
  1309. edgeTable = font.getTypeface()->getEdgeTableForGlyph (glyphNumber,
  1310. AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  1311. #if JUCE_MAC || JUCE_IOS
  1312. .translated (0.0f, -0.5f)
  1313. #endif
  1314. );
  1315. }
  1316. Font font;
  1317. int glyph, lastAccessCount;
  1318. bool snapToIntegerCoordinate;
  1319. private:
  1320. ScopedPointer <EdgeTable> edgeTable;
  1321. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable);
  1322. };
  1323. SavedState& operator= (const SavedState&);
  1324. };
  1325. //==============================================================================
  1326. OpenGLRenderer::OpenGLRenderer (OpenGLComponent& target)
  1327. : stack (new SavedState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight())))
  1328. {
  1329. initialise();
  1330. }
  1331. OpenGLRenderer::OpenGLRenderer (OpenGLFrameBuffer& target)
  1332. : stack (new SavedState (OpenGLTarget (target, Point<int>())))
  1333. {
  1334. initialise();
  1335. }
  1336. OpenGLRenderer::OpenGLRenderer (unsigned int frameBufferID, int width, int height)
  1337. : stack (new SavedState (OpenGLTarget (frameBufferID, width, height)))
  1338. {
  1339. initialise();
  1340. }
  1341. void OpenGLRenderer::initialise()
  1342. {
  1343. // This object can only be created and used when the current thread has an active OpenGL context.
  1344. jassert (OpenGLHelpers::isContextActive());
  1345. previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget();
  1346. initialiseMultiTextureExtensions();
  1347. stack->target.makeActiveFor2D();
  1348. glDisableClientState (GL_COLOR_ARRAY);
  1349. glDisableClientState (GL_NORMAL_ARRAY);
  1350. resetMultiTextureModes (false);
  1351. }
  1352. OpenGLRenderer::~OpenGLRenderer()
  1353. {
  1354. OpenGLFrameBuffer::setCurrentFrameBufferTarget (previousFrameBufferTarget);
  1355. resetMultiTextureModes (true);
  1356. }
  1357. bool OpenGLRenderer::isVectorDevice() const { return false; }
  1358. void OpenGLRenderer::setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
  1359. void OpenGLRenderer::addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
  1360. float OpenGLRenderer::getScaleFactor() { return stack->transform.getScaleFactor(); }
  1361. Rectangle<int> OpenGLRenderer::getClipBounds() const { return stack->getClipBounds(); }
  1362. bool OpenGLRenderer::isClipEmpty() const { return stack->clip == nullptr; }
  1363. bool OpenGLRenderer::clipRegionIntersects (const Rectangle<int>& r) { return stack->clipRegionIntersects (r); }
  1364. bool OpenGLRenderer::clipToRectangle (const Rectangle<int>& r) { return stack->clipToRectangle (r); }
  1365. bool OpenGLRenderer::clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
  1366. void OpenGLRenderer::excludeClipRectangle (const Rectangle<int>& r) { stack->excludeClipRectangle (r); }
  1367. void OpenGLRenderer::clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
  1368. void OpenGLRenderer::clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
  1369. void OpenGLRenderer::saveState() { stack.save(); }
  1370. void OpenGLRenderer::restoreState() { stack.restore(); }
  1371. void OpenGLRenderer::beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
  1372. void OpenGLRenderer::endTransparencyLayer() { stack.endTransparencyLayer(); }
  1373. void OpenGLRenderer::setFill (const FillType& fillType) { stack->setFillType (fillType); }
  1374. void OpenGLRenderer::setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
  1375. void OpenGLRenderer::setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
  1376. void OpenGLRenderer::fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
  1377. void OpenGLRenderer::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
  1378. void OpenGLRenderer::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
  1379. void OpenGLRenderer::drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
  1380. void OpenGLRenderer::drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
  1381. void OpenGLRenderer::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
  1382. void OpenGLRenderer::drawLine (const Line <float>& line) { stack->drawLine (line); }
  1383. void OpenGLRenderer::setFont (const Font& newFont) { stack->font = newFont; }
  1384. Font OpenGLRenderer::getFont() { return stack->font; }
  1385. END_JUCE_NAMESPACE