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.

1274 lines
49KB

  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. struct OpenGLTarget
  20. {
  21. OpenGLTarget (GLuint frameBufferID_, int width_, int height_) noexcept
  22. : frameBuffer (nullptr), frameBufferID (frameBufferID_),
  23. x (0), y (0), width (width_), height (height_)
  24. {}
  25. OpenGLTarget (OpenGLFrameBuffer& frameBuffer_, const Point<int>& origin) noexcept
  26. : frameBuffer (&frameBuffer_), frameBufferID (0), x (origin.getX()), y (origin.getY()),
  27. width (frameBuffer_.getWidth()), height (frameBuffer_.getHeight())
  28. {}
  29. OpenGLTarget (const OpenGLTarget& other) noexcept
  30. : frameBuffer (other.frameBuffer), frameBufferID (other.frameBufferID),
  31. x (other.x), y (other.y), width (other.width), height (other.height)
  32. {}
  33. void makeActiveFor2D() const
  34. {
  35. if (frameBuffer != nullptr)
  36. frameBuffer->makeCurrentRenderingTarget();
  37. else
  38. OpenGLFrameBuffer::setCurrentFrameBufferTarget (frameBufferID);
  39. applyFlippedMatrix (x, y, width, height);
  40. glDisable (GL_DEPTH_TEST);
  41. }
  42. void scissor (Rectangle<int> r) const
  43. {
  44. r = r.translated (-x, -y);
  45. OpenGLHelpers::enableScissorTest (r.withY (height - r.getBottom()));
  46. }
  47. static void applyFlippedMatrix (const int x, const int y, const int width, const int height)
  48. {
  49. glMatrixMode (GL_PROJECTION);
  50. glLoadIdentity();
  51. #if JUCE_OPENGL_ES
  52. glOrthof ((GLfloat) x, (GLfloat) (x + width), (GLfloat) (y + height), (GLfloat) y, 0.0f, 1.0f);
  53. #else
  54. glOrtho (x, x + width, y + height, y, 0, 1);
  55. #endif
  56. glViewport (0, 0, width, height);
  57. }
  58. OpenGLFrameBuffer* frameBuffer;
  59. GLuint frameBufferID;
  60. int x, y, width, height;
  61. };
  62. //==============================================================================
  63. namespace
  64. {
  65. enum { defaultOversamplingLevel = 4 };
  66. void fillRectangleList (const RectangleList& list)
  67. {
  68. glEnableClientState (GL_VERTEX_ARRAY);
  69. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  70. GLfloat vertices [8];
  71. glVertexPointer (2, GL_FLOAT, 0, vertices);
  72. for (RectangleList::Iterator i (list); i.next();)
  73. {
  74. vertices[0] = vertices[4] = (GLfloat) i.getRectangle()->getX();
  75. vertices[1] = vertices[3] = (GLfloat) i.getRectangle()->getY();
  76. vertices[2] = vertices[6] = (GLfloat) i.getRectangle()->getRight();
  77. vertices[5] = vertices[7] = (GLfloat) i.getRectangle()->getBottom();
  78. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  79. }
  80. }
  81. inline void setColour (const float alpha) noexcept
  82. {
  83. glColor4f (alpha, alpha, alpha, alpha);
  84. }
  85. void clipFrameBuffers (const OpenGLTarget& dest, OpenGLFrameBuffer& source, const Point<int> sourceOrigin)
  86. {
  87. dest.makeActiveFor2D();
  88. glEnable (GL_BLEND);
  89. glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
  90. setColour (1.0f);
  91. OpenGLHelpers::drawTextureQuad (source.getTextureID(), sourceOrigin.getX(), sourceOrigin.getY(),
  92. source.getWidth(), source.getHeight());
  93. }
  94. void renderPath (const Path& path, const AffineTransform& transform, int oversamplingLevel)
  95. {
  96. glEnableClientState (GL_VERTEX_ARRAY);
  97. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  98. glDisable (GL_TEXTURE_2D);
  99. glEnable (GL_BLEND);
  100. glBlendFunc (GL_ONE, GL_ONE);
  101. TriangulatedPath (path, transform).draw (oversamplingLevel);
  102. }
  103. void setPremultipliedBlendingMode() noexcept
  104. {
  105. glEnable (GL_BLEND);
  106. glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  107. }
  108. void setBlendMode (const bool replaceExistingContents) noexcept
  109. {
  110. if (replaceExistingContents)
  111. glDisable (GL_BLEND);
  112. else
  113. setPremultipliedBlendingMode();
  114. }
  115. void fillRectWithTiledTexture (const OpenGLTarget& target, int textureWidth, int textureHeight,
  116. const Rectangle<int>& clip, const AffineTransform& transform, float alpha)
  117. {
  118. glEnable (GL_TEXTURE_2D);
  119. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  120. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  121. glEnableClientState (GL_VERTEX_ARRAY);
  122. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  123. glDisableClientState (GL_COLOR_ARRAY);
  124. glDisableClientState (GL_NORMAL_ARRAY);
  125. glColor4f (1.0f, 1.0f, 1.0f, alpha);
  126. static bool canDoNonPowerOfTwos = OpenGLHelpers::isExtensionSupported ("GL_ARB_texture_non_power_of_two");
  127. if (canDoNonPowerOfTwos || (isPowerOfTwo (textureWidth) && isPowerOfTwo (textureHeight)))
  128. {
  129. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  130. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  131. const GLfloat clipX = (GLfloat) clip.getX();
  132. const GLfloat clipY = (GLfloat) clip.getY();
  133. const GLfloat clipR = (GLfloat) clip.getRight();
  134. const GLfloat clipB = (GLfloat) clip.getBottom();
  135. const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  136. GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
  137. {
  138. const AffineTransform t (transform.inverted().scaled (1.0f / textureWidth,
  139. 1.0f / textureHeight));
  140. t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  141. t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  142. textureCoords[1] = 1.0f - textureCoords[1];
  143. textureCoords[3] = 1.0f - textureCoords[3];
  144. textureCoords[5] = 1.0f - textureCoords[5];
  145. textureCoords[7] = 1.0f - textureCoords[7];
  146. }
  147. glVertexPointer (2, GL_FLOAT, 0, vertices);
  148. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  149. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  150. }
  151. else
  152. {
  153. // For hardware that can't handle non-power-of-two textures, this is a fallback algorithm
  154. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  155. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  156. target.scissor (clip);
  157. glPushMatrix();
  158. OpenGLHelpers::applyTransform (transform);
  159. GLfloat vertices[8];
  160. const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f };
  161. glVertexPointer (2, GL_FLOAT, 0, vertices);
  162. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  163. const Rectangle<int> targetArea (clip.toFloat().transformed (transform.inverted()).getSmallestIntegerContainer());
  164. int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), textureWidth);
  165. int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), textureHeight);
  166. const int right = targetArea.getRight();
  167. const int bottom = targetArea.getBottom();
  168. while (y < bottom)
  169. {
  170. vertices[1] = vertices[3] = (GLfloat) y;
  171. vertices[5] = vertices[7] = (GLfloat) (y + textureHeight);
  172. for (int x1 = x; x1 < right; x1 += textureWidth)
  173. {
  174. vertices[0] = vertices[4] = (GLfloat) x1;
  175. vertices[2] = vertices[6] = (GLfloat) (x1 + textureWidth);
  176. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  177. }
  178. y += textureHeight;
  179. }
  180. glPopMatrix();
  181. glDisable (GL_SCISSOR_TEST);
  182. }
  183. }
  184. void fillWithLinearGradient (const Rectangle<int>& rect,
  185. const ColourGradient& grad,
  186. const AffineTransform& transform,
  187. const int textureSize)
  188. {
  189. const Point<float> p1 (grad.point1.transformedBy (transform));
  190. const Point<float> p2 (grad.point2.transformedBy (transform));
  191. const Point<float> p3 (Point<float> (grad.point1.getX() - (grad.point2.getY() - grad.point1.getY()) / textureSize,
  192. grad.point1.getY() + (grad.point2.getX() - grad.point1.getX()) / textureSize).transformedBy (transform));
  193. const AffineTransform textureTransform (AffineTransform::fromTargetPoints (p1.getX(), p1.getY(), 0.0f, 0.0f,
  194. p2.getX(), p2.getY(), 1.0f, 0.0f,
  195. p3.getX(), p3.getY(), 0.0f, 1.0f));
  196. const GLfloat l = (GLfloat) rect.getX();
  197. const GLfloat r = (GLfloat) rect.getRight();
  198. const GLfloat t = (GLfloat) rect.getY();
  199. const GLfloat b = (GLfloat) rect.getBottom();
  200. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  201. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  202. textureTransform.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  203. textureTransform.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  204. setColour (1.0f);
  205. OpenGLHelpers::drawTriangleStrip (vertices, textureCoords, 4);
  206. }
  207. void fillWithRadialGradient (const OpenGLTarget& target, const Rectangle<int>& rect,
  208. const ColourGradient& grad, const AffineTransform& transform)
  209. {
  210. const Point<float> centre (grad.point1.transformedBy (transform));
  211. const float screenRadius = centre.getDistanceFrom (rect.getCentre().toFloat())
  212. + Point<int> (rect.getWidth() / 2,
  213. rect.getHeight() / 2).getDistanceFromOrigin()
  214. + 8.0f;
  215. const AffineTransform inverse (transform.inverted());
  216. const float sourceRadius = jmax (Point<float> (screenRadius, 0.0f).transformedBy (inverse).getDistanceFromOrigin(),
  217. Point<float> (0.0f, screenRadius).transformedBy (inverse).getDistanceFromOrigin());
  218. const int numDivisions = 90;
  219. GLfloat vertices [4 + numDivisions * 2];
  220. GLfloat textureCoords [4 + numDivisions * 2];
  221. {
  222. GLfloat* t = textureCoords;
  223. *t++ = 0.0f;
  224. *t++ = 0.0f;
  225. const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2);
  226. for (int i = numDivisions + 1; --i >= 0;)
  227. {
  228. *t++ = texturePos;
  229. *t++ = 0.0f;
  230. }
  231. }
  232. {
  233. GLfloat* v = vertices;
  234. *v++ = centre.getX();
  235. *v++ = centre.getY();
  236. const Point<float> first (grad.point1.translated (0, -sourceRadius)
  237. .transformedBy (transform));
  238. *v++ = first.getX();
  239. *v++ = first.getY();
  240. for (int i = 1; i < numDivisions; ++i)
  241. {
  242. const float angle = i * (float_Pi * 2.0f / numDivisions);
  243. const Point<float> p (grad.point1.translated (std::sin (angle) * sourceRadius,
  244. std::cos (angle) * -sourceRadius)
  245. .transformedBy (transform));
  246. *v++ = p.getX();
  247. *v++ = p.getY();
  248. }
  249. *v++ = first.getX();
  250. *v++ = first.getY();
  251. }
  252. target.scissor (rect);
  253. glEnable (GL_TEXTURE_2D);
  254. glEnableClientState (GL_VERTEX_ARRAY);
  255. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  256. glDisableClientState (GL_COLOR_ARRAY);
  257. glDisableClientState (GL_NORMAL_ARRAY);
  258. glVertexPointer (2, GL_FLOAT, 0, vertices);
  259. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  260. setColour (1.0f);
  261. glDrawArrays (GL_TRIANGLE_FAN, 0, numDivisions + 2);
  262. glDisable (GL_SCISSOR_TEST);
  263. }
  264. void fillRectWithColourGradient (const OpenGLTarget& target, const Rectangle<int>& rect,
  265. const ColourGradient& gradient, const AffineTransform& transform)
  266. {
  267. if (gradient.point1 == gradient.point2)
  268. {
  269. OpenGLHelpers::fillRectWithColour (rect, gradient.getColourAtPosition (1.0));
  270. }
  271. else
  272. {
  273. const int textureSize = 256;
  274. OpenGLTexture texture;
  275. HeapBlock<PixelARGB> lookup (textureSize);
  276. gradient.createLookupTable (lookup, textureSize);
  277. texture.load (lookup, textureSize, 1);
  278. texture.bind();
  279. if (gradient.isRadial)
  280. fillWithRadialGradient (target, rect, gradient, transform);
  281. else
  282. fillWithLinearGradient (rect, gradient, transform, textureSize);
  283. }
  284. }
  285. void fillRectWithFillType (const OpenGLTarget& target, const Rectangle<int>& rect,
  286. const FillType& fill, const bool replaceExistingContents)
  287. {
  288. if (fill.isGradient())
  289. {
  290. target.makeActiveFor2D();
  291. setBlendMode (replaceExistingContents);
  292. ColourGradient g2 (*(fill.gradient));
  293. g2.multiplyOpacity (fill.getOpacity());
  294. fillRectWithColourGradient (target, rect, g2, fill.transform);
  295. }
  296. else if (fill.isTiledImage())
  297. {
  298. OpenGLTextureFromImage t (fill.image);
  299. target.makeActiveFor2D();
  300. setBlendMode (replaceExistingContents);
  301. glBindTexture (GL_TEXTURE_2D, t.textureID);
  302. fillRectWithTiledTexture (target, t.width, t.height, rect,
  303. fill.transform, fill.colour.getFloatAlpha());
  304. glBindTexture (GL_TEXTURE_2D, 0);
  305. }
  306. }
  307. }
  308. //==============================================================================
  309. class OpenGLRenderer::ScratchBufferManager
  310. {
  311. public:
  312. ScratchBufferManager() {}
  313. OpenGLFrameBuffer* get (int width, int height)
  314. {
  315. for (int i = 0; i < buffers.size(); ++i)
  316. {
  317. OpenGLFrameBuffer* b = buffers.getUnchecked(i);
  318. if (width <= b->getWidth() && height <= b->getHeight())
  319. return buffers.removeAndReturn (i);
  320. }
  321. OpenGLFrameBuffer* b = new OpenGLFrameBuffer();
  322. b->initialise (width, height);
  323. return b;
  324. }
  325. void release (OpenGLFrameBuffer* buffer)
  326. {
  327. buffers.add (buffer);
  328. if (buffers.size() > 10)
  329. buffers.remove (0);
  330. }
  331. private:
  332. OwnedArray<OpenGLFrameBuffer> buffers;
  333. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScratchBufferManager);
  334. };
  335. class ClipRegion_Mask;
  336. //==============================================================================
  337. class ClipRegionBase : public SingleThreadedReferenceCountedObject
  338. {
  339. public:
  340. ClipRegionBase (OpenGLRenderer::ScratchBufferManager& scratchBuffer_) noexcept : scratchBuffer (scratchBuffer_) {}
  341. virtual ~ClipRegionBase() {}
  342. typedef ReferenceCountedObjectPtr<ClipRegionBase> Ptr;
  343. virtual Ptr clone() const = 0;
  344. virtual Ptr applyClipTo (const Ptr& target) = 0;
  345. virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
  346. virtual Ptr clipToRectangleList (const RectangleList&) = 0;
  347. virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
  348. virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
  349. virtual Ptr clipToEdgeTable (const EdgeTable&) = 0;
  350. virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
  351. virtual Ptr clipToMask (ClipRegion_Mask*) = 0;
  352. virtual const Rectangle<int>& getClipBounds() const = 0;
  353. virtual void fillAll (const OpenGLTarget&, const FillType& fill, bool replaceContents) = 0;
  354. virtual void fillRect (const OpenGLTarget&, const Rectangle<int>& area, const FillType& fill, bool replaceContents) = 0;
  355. virtual void drawImage (const OpenGLTarget&, const OpenGLTextureFromImage&, float alpha, const Rectangle<int>& targetArea) = 0;
  356. OpenGLRenderer::ScratchBufferManager& scratchBuffer;
  357. private:
  358. JUCE_DECLARE_NON_COPYABLE (ClipRegionBase);
  359. };
  360. //==============================================================================
  361. class ClipRegion_Mask : public ClipRegionBase
  362. {
  363. public:
  364. ClipRegion_Mask (const ClipRegion_Mask& other)
  365. : ClipRegionBase (other.scratchBuffer),
  366. clip (other.clip),
  367. maskOrigin (other.clip.getPosition())
  368. {
  369. mask = scratchBuffer.get (clip.getWidth(), clip.getHeight());
  370. OpenGLTarget m (*mask, maskOrigin);
  371. m.makeActiveFor2D();
  372. glDisable (GL_BLEND);
  373. setColour (1.0f);
  374. drawFrameBuffer (*(other.mask), other.maskOrigin);
  375. }
  376. explicit ClipRegion_Mask (const Rectangle<int>& r, OpenGLRenderer::ScratchBufferManager& scratchBuffer_)
  377. : ClipRegionBase (scratchBuffer_),
  378. clip (r),
  379. maskOrigin (r.getPosition())
  380. {
  381. mask = scratchBuffer_.get (r.getWidth(), r.getHeight());
  382. mask->clear (Colours::white);
  383. }
  384. explicit ClipRegion_Mask (const Rectangle<float>& r, OpenGLRenderer::ScratchBufferManager& scratchBuffer_)
  385. : ClipRegionBase (scratchBuffer_),
  386. clip (r.getSmallestIntegerContainer()),
  387. maskOrigin (clip.getPosition())
  388. {
  389. initialiseClear();
  390. glEnableClientState (GL_VERTEX_ARRAY);
  391. glDisableClientState (GL_TEXTURE_COORD_ARRAY);
  392. RenderingHelpers::FloatRectangleRasterisingInfo fr (r);
  393. FillFloatRectCallback callback;
  394. fr.iterate (callback);
  395. }
  396. explicit ClipRegion_Mask (const EdgeTable& e, OpenGLRenderer::ScratchBufferManager& scratchBuffer_)
  397. : ClipRegionBase (scratchBuffer_),
  398. clip (e.getMaximumBounds()),
  399. maskOrigin (clip.getPosition())
  400. {
  401. initialiseClear();
  402. OpenGLHelpers::fillEdgeTable (e);
  403. }
  404. ClipRegion_Mask (OpenGLRenderer::ScratchBufferManager& scratchBuffer_, const Rectangle<int>& bounds,
  405. const Path& p, const AffineTransform& transform, int oversamplingLevel)
  406. : ClipRegionBase (scratchBuffer_),
  407. clip (bounds), maskOrigin (clip.getPosition())
  408. {
  409. initialiseClear();
  410. renderPath (p, transform, oversamplingLevel);
  411. }
  412. ~ClipRegion_Mask()
  413. {
  414. scratchBuffer.release (mask);
  415. }
  416. static ClipRegion_Mask* createFromPath (OpenGLRenderer::ScratchBufferManager& scratchBuffer, Rectangle<int> bounds,
  417. const Path& p, const AffineTransform& transform)
  418. {
  419. bounds = bounds.getIntersection (p.getBoundsTransformed (transform).getSmallestIntegerContainer());
  420. return bounds.isEmpty() ? nullptr
  421. : new ClipRegion_Mask (scratchBuffer, bounds, p, transform, (int) defaultOversamplingLevel);
  422. }
  423. Ptr clone() const { return new ClipRegion_Mask (*this); }
  424. const Rectangle<int>& getClipBounds() const { return clip; }
  425. Ptr applyClipTo (const Ptr& target) { return target->clipToMask (this); }
  426. Ptr clipToRectangle (const Rectangle<int>& r)
  427. {
  428. clip = clip.getIntersection (r);
  429. return clip.isEmpty() ? nullptr : this;
  430. }
  431. Ptr clipToRectangleList (const RectangleList& r)
  432. {
  433. clip = clip.getIntersection (r.getBounds());
  434. if (clip.isEmpty())
  435. return nullptr;
  436. RectangleList excluded (clip);
  437. if (excluded.subtract (r))
  438. {
  439. if (excluded.getNumRectangles() == 1)
  440. return excludeClipRectangle (excluded.getRectangle (0));
  441. makeMaskActive();
  442. glDisable (GL_BLEND);
  443. setColour (0);
  444. fillRectangleList (excluded);
  445. }
  446. return this;
  447. }
  448. Ptr excludeClipRectangle (const Rectangle<int>& r)
  449. {
  450. if (r.contains (clip))
  451. return nullptr;
  452. makeMaskActive();
  453. glDisable (GL_BLEND);
  454. setColour (0);
  455. OpenGLHelpers::fillRect (r);
  456. return this;
  457. }
  458. Ptr clipToPath (const Path& p, const AffineTransform& t)
  459. {
  460. ClipRegion_Mask* tempMask = createFromPath (scratchBuffer, clip, p, t);
  461. const Ptr tempMaskPtr (tempMask);
  462. return tempMask == nullptr ? nullptr : clipToMask (tempMask);
  463. }
  464. Ptr clipToEdgeTable (const EdgeTable& et)
  465. {
  466. ClipRegion_Mask* const tempMask = new ClipRegion_Mask (et, scratchBuffer);
  467. const Ptr tempMaskPtr (tempMask);
  468. return clipToMask (tempMask);
  469. }
  470. Ptr clipToMask (ClipRegion_Mask* m)
  471. {
  472. jassert (m != nullptr && m != this);
  473. clip = clip.getIntersection (m->clip);
  474. if (clip.isEmpty())
  475. return nullptr;
  476. clipFrameBuffers (OpenGLTarget (*mask, maskOrigin), *(m->mask), m->maskOrigin);
  477. return this;
  478. }
  479. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
  480. {
  481. makeMaskActive();
  482. glEnable (GL_BLEND);
  483. glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
  484. fillMaskWithSourceImage (image, transform);
  485. return this;
  486. }
  487. void fillAll (const OpenGLTarget& target, const FillType& fill, bool replaceContents)
  488. {
  489. jassert (! replaceContents);
  490. fillRectInternal (target, clip, fill, false);
  491. }
  492. void fillRect (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  493. {
  494. jassert (! replaceContents);
  495. const Rectangle<int> r (clip.getIntersection (area));
  496. if (! r.isEmpty())
  497. fillRectInternal (target, r, fill, false);
  498. }
  499. void fillRectInternal (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  500. {
  501. if (fill.isColour())
  502. {
  503. target.makeActiveFor2D();
  504. setBlendMode (replaceContents);
  505. PixelARGB p (fill.colour.getARGB());
  506. p.premultiply();
  507. OpenGLHelpers::setColour (Colour (p.getARGB()));
  508. target.scissor (area);
  509. drawFrameBuffer (*mask, maskOrigin);
  510. glDisable (GL_SCISSOR_TEST);
  511. }
  512. else
  513. {
  514. OpenGLFrameBuffer* patternBuffer = scratchBuffer.get (area.getWidth(), area.getHeight());
  515. fillRectWithFillType (OpenGLTarget (*patternBuffer, area.getPosition()), area, fill, true);
  516. clipAndDraw (target, OpenGLTarget (*patternBuffer, area.getPosition()), area);
  517. scratchBuffer.release (patternBuffer);
  518. }
  519. }
  520. void drawImage (const OpenGLTarget& target, const OpenGLTextureFromImage& source, float alpha, const Rectangle<int>& targetArea)
  521. {
  522. const Rectangle<int> bufferArea (targetArea.getIntersection (clip));
  523. if (! bufferArea.isEmpty())
  524. {
  525. OpenGLFrameBuffer* buffer = scratchBuffer.get (bufferArea.getWidth(), bufferArea.getHeight());
  526. OpenGLTarget bufferTarget (*buffer, bufferArea.getPosition());
  527. bufferTarget.makeActiveFor2D();
  528. glDisable (GL_BLEND);
  529. OpenGLHelpers::fillRectWithTexture (targetArea, source.textureID, alpha);
  530. clipAndDraw (target, bufferTarget, bufferArea);
  531. scratchBuffer.release (buffer);
  532. }
  533. }
  534. void drawImageSelfDestructively (const OpenGLTarget& target, const OpenGLTextureFromImage& source,
  535. float alpha, const AffineTransform& transform)
  536. {
  537. makeMaskActive();
  538. glEnable (GL_BLEND);
  539. glBlendFunc (GL_DST_ALPHA, GL_ZERO);
  540. fillMaskWithSourceImage (source, transform);
  541. target.makeActiveFor2D();
  542. setColour (alpha);
  543. glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  544. target.scissor (clip);
  545. drawFrameBuffer (*mask, maskOrigin);
  546. glDisable (GL_SCISSOR_TEST);
  547. }
  548. private:
  549. OpenGLFrameBuffer* mask;
  550. Rectangle<int> clip;
  551. Point<int> maskOrigin;
  552. void prepareFor2D() const
  553. {
  554. OpenGLTarget::applyFlippedMatrix (maskOrigin.getX(), maskOrigin.getY(), mask->getWidth(), mask->getHeight());
  555. }
  556. void makeMaskActive()
  557. {
  558. const bool b = mask->makeCurrentRenderingTarget();
  559. (void) b; jassert (b);
  560. prepareFor2D();
  561. }
  562. void initialiseClear()
  563. {
  564. jassert (! clip.isEmpty());
  565. mask = scratchBuffer.get (clip.getWidth(), clip.getHeight());
  566. mask->makeCurrentAndClear();
  567. glDisable (GL_TEXTURE_2D);
  568. glDisable (GL_BLEND);
  569. prepareFor2D();
  570. }
  571. struct FillFloatRectCallback
  572. {
  573. void operator() (const int x, const int y, const int w, const int h, const int alpha) const
  574. {
  575. const GLfloat l = (GLfloat) x;
  576. const GLfloat t = (GLfloat) y;
  577. const GLfloat r = (GLfloat) (x + w);
  578. const GLfloat b = (GLfloat) (y + h);
  579. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  580. setColour (alpha / 255.0f);
  581. glVertexPointer (2, GL_FLOAT, 0, vertices);
  582. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  583. }
  584. };
  585. void clipAndDraw (const OpenGLTarget& target, const OpenGLTarget& buffer, const Rectangle<int>& clip)
  586. {
  587. clipFrameBuffers (buffer, *mask, maskOrigin);
  588. target.makeActiveFor2D();
  589. glEnable (GL_BLEND);
  590. glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  591. setColour (1.0f);
  592. target.scissor (clip);
  593. drawFrameBuffer (*buffer.frameBuffer, Point<int> (buffer.x, buffer.y));
  594. glDisable (GL_SCISSOR_TEST);
  595. }
  596. void drawFrameBuffer (const OpenGLFrameBuffer& buffer, const Point<int>& topLeft)
  597. {
  598. OpenGLHelpers::drawTextureQuad (buffer.getTextureID(), topLeft.getX(), topLeft.getY(),
  599. buffer.getWidth(), buffer.getHeight());
  600. }
  601. void fillMaskWithSourceImage (const OpenGLTextureFromImage& image, const AffineTransform& transform) const
  602. {
  603. setColour (1.0f);
  604. glBindTexture (GL_TEXTURE_2D, image.textureID);
  605. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  606. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  607. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  608. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  609. const GLfloat l = (GLfloat) maskOrigin.getX();
  610. const GLfloat t = (GLfloat) maskOrigin.getY();
  611. const GLfloat r = (GLfloat) (maskOrigin.getX() + mask->getWidth());
  612. const GLfloat b = (GLfloat) (maskOrigin.getY() + mask->getHeight());
  613. const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
  614. GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
  615. const AffineTransform inv (transform.inverted().scaled (1.0f / image.width,
  616. 1.0f / image.height));
  617. inv.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
  618. inv.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
  619. textureCoords[1] = 1.0f - textureCoords[1];
  620. textureCoords[3] = 1.0f - textureCoords[3];
  621. textureCoords[5] = 1.0f - textureCoords[5];
  622. textureCoords[7] = 1.0f - textureCoords[7];
  623. OpenGLHelpers::drawTriangleStrip (vertices, textureCoords, 4);
  624. }
  625. ClipRegion_Mask& operator= (const ClipRegion_Mask&);
  626. };
  627. //==============================================================================
  628. class ClipRegion_Rectangle : public ClipRegionBase
  629. {
  630. public:
  631. explicit ClipRegion_Rectangle (const Rectangle<int>& r, OpenGLRenderer::ScratchBufferManager& scratchBuffer_) noexcept
  632. : ClipRegionBase (scratchBuffer_),
  633. clip (r)
  634. {}
  635. Ptr clone() const { return new ClipRegion_Rectangle (clip, scratchBuffer); }
  636. const Rectangle<int>& getClipBounds() const { return clip; }
  637. Ptr applyClipTo (const Ptr& target) { return target->clipToRectangle (clip); }
  638. Ptr clipToRectangle (const Rectangle<int>& r)
  639. {
  640. clip = clip.getIntersection (r);
  641. return clip.isEmpty() ? nullptr : this;
  642. }
  643. Ptr clipToRectangleList (const RectangleList& r)
  644. {
  645. if (r.getNumRectangles() <= 1)
  646. return clipToRectangle (r.getRectangle (0));
  647. if (r.containsRectangle (clip))
  648. return this;
  649. return toMask()->clipToRectangleList (r);
  650. }
  651. Ptr excludeClipRectangle (const Rectangle<int>& r)
  652. {
  653. return r.contains (clip) ? nullptr
  654. : toMask()->excludeClipRectangle (r);
  655. }
  656. Ptr clipToMask (ClipRegion_Mask* m) { return m->clipToRectangle (clip); }
  657. Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
  658. Ptr clipToEdgeTable (const EdgeTable& et) { return toMask()->clipToEdgeTable (et); }
  659. Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
  660. void fillAll (const OpenGLTarget& target, const FillType& fill, bool replaceContents)
  661. {
  662. fillRectInternal (target, clip, fill, replaceContents);
  663. }
  664. void fillRect (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  665. {
  666. const Rectangle<int> r (clip.getIntersection (area));
  667. if (! r.isEmpty())
  668. fillRectInternal (target, r, fill, replaceContents);
  669. }
  670. void drawImage (const OpenGLTarget& target, const OpenGLTextureFromImage& source, float alpha, const Rectangle<int>& targetArea)
  671. {
  672. target.makeActiveFor2D();
  673. target.scissor (clip);
  674. setPremultipliedBlendingMode();
  675. OpenGLHelpers::fillRectWithTexture (targetArea, source.textureID, alpha);
  676. glDisable (GL_SCISSOR_TEST);
  677. }
  678. private:
  679. Rectangle<int> clip;
  680. void fillRectInternal (const OpenGLTarget& target, const Rectangle<int>& area, const FillType& fill, bool replaceContents)
  681. {
  682. if (fill.isColour())
  683. {
  684. target.makeActiveFor2D();
  685. setBlendMode (replaceContents);
  686. glDisable (GL_TEXTURE_2D);
  687. OpenGLHelpers::fillRectWithColour (area, fill.colour);
  688. }
  689. else
  690. {
  691. fillRectWithFillType (target, area, fill, replaceContents);
  692. }
  693. }
  694. Ptr toMask() const
  695. {
  696. return new ClipRegion_Mask (clip, scratchBuffer);
  697. }
  698. ClipRegion_Rectangle& operator= (const ClipRegion_Rectangle&);
  699. };
  700. //==============================================================================
  701. class OpenGLRenderer::SavedState
  702. {
  703. public:
  704. SavedState (const OpenGLTarget& target_, ScratchBufferManager& scratchBuffer)
  705. : clip (new ClipRegion_Rectangle (Rectangle<int> (target_.width, target_.height), scratchBuffer)),
  706. transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
  707. target (target_), transparencyLayerAlpha (1.0f)
  708. {
  709. }
  710. SavedState (const SavedState& other)
  711. : clip (other.clip), transform (other.transform), font (other.font),
  712. fillType (other.fillType), interpolationQuality (other.interpolationQuality),
  713. target (other.target), transparencyLayerAlpha (other.transparencyLayerAlpha),
  714. transparencyLayer (other.transparencyLayer)
  715. {
  716. }
  717. bool clipToRectangle (const Rectangle<int>& r)
  718. {
  719. if (clip != nullptr)
  720. {
  721. if (transform.isOnlyTranslated)
  722. {
  723. cloneClipIfMultiplyReferenced();
  724. clip = clip->clipToRectangle (transform.translated (r));
  725. }
  726. else
  727. {
  728. Path p;
  729. p.addRectangle (r);
  730. clipToPath (p, AffineTransform::identity);
  731. }
  732. }
  733. return clip != nullptr;
  734. }
  735. bool clipToRectangleList (const RectangleList& r)
  736. {
  737. if (clip != nullptr)
  738. {
  739. if (transform.isOnlyTranslated)
  740. {
  741. cloneClipIfMultiplyReferenced();
  742. RectangleList offsetList (r);
  743. offsetList.offsetAll (transform.xOffset, transform.yOffset);
  744. clip = clip->clipToRectangleList (offsetList);
  745. }
  746. else
  747. {
  748. clipToPath (r.toPath(), AffineTransform::identity);
  749. }
  750. }
  751. return clip != nullptr;
  752. }
  753. bool excludeClipRectangle (const Rectangle<int>& r)
  754. {
  755. if (clip != nullptr)
  756. {
  757. cloneClipIfMultiplyReferenced();
  758. if (transform.isOnlyTranslated)
  759. {
  760. clip = clip->excludeClipRectangle (transform.translated (r));
  761. }
  762. else
  763. {
  764. Path p;
  765. p.addRectangle (r.toFloat());
  766. p.applyTransform (transform.complexTransform);
  767. p.addRectangle (clip->getClipBounds().toFloat());
  768. p.setUsingNonZeroWinding (false);
  769. clip = clip->clipToPath (p, AffineTransform::identity);
  770. }
  771. }
  772. return clip != nullptr;
  773. }
  774. void clipToPath (const Path& p, const AffineTransform& t)
  775. {
  776. if (clip != nullptr)
  777. {
  778. cloneClipIfMultiplyReferenced();
  779. clip = clip->clipToPath (p, transform.getTransformWith (t));
  780. }
  781. }
  782. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
  783. {
  784. if (clip != nullptr)
  785. {
  786. Path p;
  787. p.addRectangle (sourceImage.getBounds());
  788. clipToPath (p, t);
  789. if (sourceImage.hasAlphaChannel() && clip != nullptr)
  790. {
  791. cloneClipIfMultiplyReferenced();
  792. clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
  793. }
  794. }
  795. }
  796. bool clipRegionIntersects (const Rectangle<int>& r) const
  797. {
  798. return clip != nullptr
  799. && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
  800. : getClipBounds().intersects (r));
  801. }
  802. Rectangle<int> getClipBounds() const
  803. {
  804. return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
  805. : Rectangle<int>();
  806. }
  807. SavedState* beginTransparencyLayer (float opacity)
  808. {
  809. SavedState* s = new SavedState (*this);
  810. if (clip != nullptr)
  811. {
  812. const Rectangle<int>& clipBounds = clip->getClipBounds();
  813. OpenGLFrameBufferImage* fbi = new OpenGLFrameBufferImage (clipBounds.getWidth(), clipBounds.getHeight());
  814. fbi->frameBuffer.clear (Colours::transparentBlack);
  815. s->transparencyLayer = Image (fbi);
  816. s->target = OpenGLTarget (fbi->frameBuffer, clipBounds.getPosition());
  817. s->transparencyLayerAlpha = opacity;
  818. s->cloneClipIfMultiplyReferenced();
  819. }
  820. return s;
  821. }
  822. void endTransparencyLayer (SavedState& finishedLayerState)
  823. {
  824. if (clip != nullptr)
  825. clip->drawImage (target, finishedLayerState.transparencyLayer,
  826. finishedLayerState.transparencyLayerAlpha, clip->getClipBounds());
  827. }
  828. //==============================================================================
  829. void fillRect (const Rectangle<int>& r, const bool replaceContents)
  830. {
  831. if (clip != nullptr)
  832. {
  833. if (transform.isOnlyTranslated)
  834. {
  835. clip->fillRect (target, r.translated (transform.xOffset, transform.yOffset),
  836. getFillType(), replaceContents);
  837. }
  838. else
  839. {
  840. Path p;
  841. p.addRectangle (r);
  842. fillPath (p, AffineTransform::identity);
  843. }
  844. }
  845. }
  846. void fillRect (const Rectangle<float>& r)
  847. {
  848. if (clip != nullptr)
  849. {
  850. if (transform.isOnlyTranslated)
  851. {
  852. fillShape (new ClipRegion_Mask (r.translated ((float) transform.xOffset,
  853. (float) transform.yOffset), clip->scratchBuffer), false);
  854. }
  855. else
  856. {
  857. Path p;
  858. p.addRectangle (r);
  859. fillPath (p, AffineTransform::identity);
  860. }
  861. }
  862. }
  863. void fillPath (const Path& path, const AffineTransform& t)
  864. {
  865. if (clip != nullptr)
  866. {
  867. ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->scratchBuffer, clip->getClipBounds(), path,
  868. transform.getTransformWith (t));
  869. if (m != nullptr)
  870. fillShape (m, false);
  871. }
  872. }
  873. void drawGlyph (int glyphNumber, const AffineTransform& t)
  874. {
  875. if (clip != nullptr)
  876. {
  877. if (transform.isOnlyTranslated && t.isOnlyTranslation())
  878. {
  879. RenderingHelpers::GlyphCache <CachedGlyphEdgeTable, SavedState>::getInstance()
  880. .drawGlyph (*this, font, glyphNumber,
  881. transform.xOffset + t.getTranslationX(),
  882. transform.yOffset + t.getTranslationY());
  883. }
  884. else
  885. {
  886. const float fontHeight = font.getHeight();
  887. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph
  888. (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  889. .followedBy (t))));
  890. if (et != nullptr)
  891. fillShape (new ClipRegion_Mask (*et, clip->scratchBuffer), false);
  892. }
  893. }
  894. }
  895. void fillEdgeTable (const EdgeTable& et, float x, int y)
  896. {
  897. EdgeTable et2 (et);
  898. et2.translate (x, y);
  899. fillShape (new ClipRegion_Mask (et2, clip->scratchBuffer), false);
  900. }
  901. void drawLine (const Line <float>& line)
  902. {
  903. Path p;
  904. p.addLineSegment (line, 1.0f);
  905. fillPath (p, AffineTransform::identity);
  906. }
  907. void fillShape (ClipRegionBase::Ptr shapeToFill, const bool replaceContents)
  908. {
  909. jassert (clip != nullptr && shapeToFill != nullptr);
  910. if (! fillType.isInvisible())
  911. {
  912. shapeToFill = clip->applyClipTo (shapeToFill);
  913. if (shapeToFill != nullptr)
  914. shapeToFill->fillAll (target, getFillType(), replaceContents);
  915. }
  916. }
  917. //==============================================================================
  918. void drawImage (const Image& image, const AffineTransform& trans)
  919. {
  920. if (clip == nullptr || fillType.colour.isTransparent())
  921. return;
  922. const AffineTransform t (transform.getTransformWith (trans));
  923. const float alpha = fillType.colour.getFloatAlpha();
  924. if (t.isOnlyTranslation())
  925. {
  926. int tx = (int) (t.getTranslationX() * 256.0f);
  927. int ty = (int) (t.getTranslationY() * 256.0f);
  928. if (((tx | ty) & 0xf8) == 0)
  929. {
  930. tx = ((tx + 128) >> 8);
  931. ty = ((ty + 128) >> 8);
  932. clip->drawImage (target, image, alpha, Rectangle<int> (tx, ty, image.getWidth(), image.getHeight()));
  933. return;
  934. }
  935. }
  936. if (t.isSingularity())
  937. return;
  938. Path p;
  939. p.addRectangle (image.getBounds());
  940. ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->scratchBuffer, clip->getClipBounds(), p, t);
  941. if (m != nullptr)
  942. {
  943. ClipRegionBase::Ptr c (clip->applyClipTo (m));
  944. if (c != nullptr)
  945. {
  946. m = dynamic_cast<ClipRegion_Mask*> (c.getObject());
  947. jassert (m != nullptr);
  948. m->drawImageSelfDestructively (target, image, alpha, t);
  949. }
  950. }
  951. }
  952. //==============================================================================
  953. ClipRegionBase::Ptr clip;
  954. RenderingHelpers::TranslationOrTransform transform;
  955. Font font;
  956. FillType fillType;
  957. Graphics::ResamplingQuality interpolationQuality;
  958. private:
  959. OpenGLTarget target;
  960. float transparencyLayerAlpha;
  961. Image transparencyLayer;
  962. void cloneClipIfMultiplyReferenced()
  963. {
  964. if (clip->getReferenceCount() > 1)
  965. clip = clip->clone();
  966. }
  967. FillType getFillType() const
  968. {
  969. return fillType.transformed (transform.getTransform());
  970. }
  971. class CachedGlyphEdgeTable
  972. {
  973. public:
  974. CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}
  975. void draw (OpenGLRenderer::SavedState& state, float x, const float y) const
  976. {
  977. if (snapToIntegerCoordinate)
  978. x = std::floor (x + 0.5f);
  979. if (edgeTable != nullptr)
  980. state.fillEdgeTable (*edgeTable, x, roundToInt (y));
  981. }
  982. void generate (const Font& newFont, const int glyphNumber)
  983. {
  984. font = newFont;
  985. snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
  986. glyph = glyphNumber;
  987. const float fontHeight = font.getHeight();
  988. edgeTable = font.getTypeface()->getEdgeTableForGlyph (glyphNumber,
  989. AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  990. #if JUCE_MAC || JUCE_IOS
  991. .translated (0.0f, -0.5f)
  992. #endif
  993. );
  994. }
  995. Font font;
  996. int glyph, lastAccessCount;
  997. bool snapToIntegerCoordinate;
  998. private:
  999. ScopedPointer <EdgeTable> edgeTable;
  1000. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable);
  1001. };
  1002. SavedState& operator= (const SavedState&);
  1003. };
  1004. //==============================================================================
  1005. OpenGLRenderer::OpenGLRenderer (OpenGLComponent& target)
  1006. : scratchBufferManager (new ScratchBufferManager()),
  1007. stack (new SavedState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight()), *scratchBufferManager))
  1008. {
  1009. target.makeCurrentRenderingTarget();
  1010. }
  1011. OpenGLRenderer::OpenGLRenderer (OpenGLFrameBuffer& target)
  1012. : scratchBufferManager (new ScratchBufferManager()),
  1013. stack (new SavedState (OpenGLTarget (target, Point<int>()), *scratchBufferManager))
  1014. {
  1015. // This object can only be created and used when the current thread has an active OpenGL context.
  1016. jassert (OpenGLHelpers::isContextActive());
  1017. }
  1018. OpenGLRenderer::OpenGLRenderer (unsigned int frameBufferID, int width, int height)
  1019. : scratchBufferManager (new ScratchBufferManager()),
  1020. stack (new SavedState (OpenGLTarget (frameBufferID, width, height), *scratchBufferManager))
  1021. {
  1022. // This object can only be created and used when the current thread has an active OpenGL context.
  1023. jassert (OpenGLHelpers::isContextActive());
  1024. }
  1025. OpenGLRenderer::~OpenGLRenderer() {}
  1026. bool OpenGLRenderer::isVectorDevice() const { return false; }
  1027. void OpenGLRenderer::setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
  1028. void OpenGLRenderer::addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
  1029. float OpenGLRenderer::getScaleFactor() { return stack->transform.getScaleFactor(); }
  1030. Rectangle<int> OpenGLRenderer::getClipBounds() const { return stack->getClipBounds(); }
  1031. bool OpenGLRenderer::isClipEmpty() const { return stack->clip == nullptr; }
  1032. bool OpenGLRenderer::clipRegionIntersects (const Rectangle<int>& r) { return stack->clipRegionIntersects (r); }
  1033. bool OpenGLRenderer::clipToRectangle (const Rectangle<int>& r) { return stack->clipToRectangle (r); }
  1034. bool OpenGLRenderer::clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
  1035. void OpenGLRenderer::excludeClipRectangle (const Rectangle<int>& r) { stack->excludeClipRectangle (r); }
  1036. void OpenGLRenderer::clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
  1037. void OpenGLRenderer::clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
  1038. void OpenGLRenderer::saveState() { stack.save(); }
  1039. void OpenGLRenderer::restoreState() { stack.restore(); }
  1040. void OpenGLRenderer::beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
  1041. void OpenGLRenderer::endTransparencyLayer() { stack.endTransparencyLayer(); }
  1042. void OpenGLRenderer::setFill (const FillType& fillType) { stack->fillType = fillType; }
  1043. void OpenGLRenderer::setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
  1044. void OpenGLRenderer::setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
  1045. void OpenGLRenderer::fillRect (const Rectangle<int>& r, bool replace) { stack->fillRect (r, replace); }
  1046. void OpenGLRenderer::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
  1047. void OpenGLRenderer::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
  1048. void OpenGLRenderer::drawVerticalLine (int x, float top, float bottom) { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }
  1049. void OpenGLRenderer::drawHorizontalLine (int y, float left, float right) { if (left < right) stack->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); }
  1050. void OpenGLRenderer::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
  1051. void OpenGLRenderer::drawLine (const Line <float>& line) { stack->drawLine (line); }
  1052. void OpenGLRenderer::setFont (const Font& newFont) { stack->font = newFont; }
  1053. Font OpenGLRenderer::getFont() { return stack->font; }
  1054. END_JUCE_NAMESPACE