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.

1720 lines
65KB

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