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.

1739 lines
63KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. namespace OpenGLRendering
  18. {
  19. struct TextureInfo
  20. {
  21. GLuint textureID;
  22. int imageWidth, imageHeight;
  23. float fullWidthProportion, fullHeightProportion;
  24. };
  25. //==============================================================================
  26. // This list persists in the OpenGLContext, and will re-use cached textures which
  27. // are created from Images.
  28. struct CachedImageList : public ReferenceCountedObject,
  29. private ImagePixelData::Listener
  30. {
  31. CachedImageList (size_t totalCacheSizeInPixels = 8 * 1024 * 1024) noexcept
  32. : totalSize (0), maxCacheSize (totalCacheSizeInPixels) {}
  33. static CachedImageList* get (OpenGLContext& context)
  34. {
  35. const char cacheValueID[] = "CachedImages";
  36. CachedImageList* list = static_cast<CachedImageList*> (context.getAssociatedObject (cacheValueID));
  37. if (list == nullptr)
  38. {
  39. list = new CachedImageList();
  40. context.setAssociatedObject (cacheValueID, list);
  41. }
  42. return list;
  43. }
  44. TextureInfo getTextureFor (const Image& image)
  45. {
  46. ImagePixelData* const pixelData = image.getPixelData();
  47. CachedImage* c = findCachedImage (pixelData);
  48. if (c == nullptr)
  49. {
  50. if (OpenGLFrameBuffer* const fb = OpenGLImageType::getFrameBufferFrom (image))
  51. {
  52. TextureInfo t;
  53. t.textureID = fb->getTextureID();
  54. t.imageWidth = image.getWidth();
  55. t.imageHeight = image.getHeight();
  56. t.fullWidthProportion = 1.0f;
  57. t.fullHeightProportion = 1.0f;
  58. return t;
  59. }
  60. c = images.add (new CachedImage (*this, pixelData));
  61. totalSize += c->imageSize;
  62. while (totalSize > maxCacheSize && images.size() > 1 && totalSize > 0)
  63. removeOldestItem();
  64. }
  65. return c->getTextureInfo();
  66. }
  67. typedef ReferenceCountedObjectPtr<CachedImageList> Ptr;
  68. private:
  69. void imageDataChanged (ImagePixelData* im) override
  70. {
  71. if (CachedImage* c = findCachedImage (im))
  72. c->texture.release();
  73. }
  74. void imageDataBeingDeleted (ImagePixelData* im) override
  75. {
  76. for (int i = images.size(); --i >= 0;)
  77. {
  78. if (images.getUnchecked(i)->pixelData == im)
  79. {
  80. totalSize -= images.getUnchecked(i)->imageSize;
  81. images.remove (i);
  82. break;
  83. }
  84. }
  85. }
  86. struct CachedImage
  87. {
  88. CachedImage (CachedImageList& list, ImagePixelData* im)
  89. : owner (list), pixelData (im),
  90. lastUsed (Time::getCurrentTime()),
  91. imageSize (im->width * im->height)
  92. {
  93. pixelData->listeners.add (&owner);
  94. }
  95. ~CachedImage()
  96. {
  97. if (pixelData != nullptr)
  98. pixelData->listeners.remove (&owner);
  99. }
  100. TextureInfo getTextureInfo()
  101. {
  102. TextureInfo t;
  103. if (texture.getTextureID() == 0)
  104. texture.loadImage (Image (pixelData));
  105. t.textureID = texture.getTextureID();
  106. t.imageWidth = pixelData->width;
  107. t.imageHeight = pixelData->height;
  108. t.fullWidthProportion = t.imageWidth / (float) texture.getWidth();
  109. t.fullHeightProportion = t.imageHeight / (float) texture.getHeight();
  110. lastUsed = Time::getCurrentTime();
  111. return t;
  112. }
  113. CachedImageList& owner;
  114. ImagePixelData* pixelData;
  115. OpenGLTexture texture;
  116. Time lastUsed;
  117. const size_t imageSize;
  118. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedImage)
  119. };
  120. OwnedArray<CachedImage> images;
  121. size_t totalSize, maxCacheSize;
  122. CachedImage* findCachedImage (ImagePixelData* const pixelData) const
  123. {
  124. for (int i = 0; i < images.size(); ++i)
  125. {
  126. CachedImage* c = images.getUnchecked(i);
  127. if (c->pixelData == pixelData)
  128. return c;
  129. }
  130. return nullptr;
  131. }
  132. void removeOldestItem()
  133. {
  134. CachedImage* oldest = nullptr;
  135. for (int i = 0; i < images.size(); ++i)
  136. {
  137. CachedImage* c = images.getUnchecked(i);
  138. if (oldest == nullptr || c->lastUsed < oldest->lastUsed)
  139. oldest = c;
  140. }
  141. if (oldest != nullptr)
  142. {
  143. totalSize -= oldest->imageSize;
  144. images.removeObject (oldest);
  145. }
  146. }
  147. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedImageList)
  148. };
  149. //==============================================================================
  150. struct Target
  151. {
  152. Target (OpenGLContext& c, GLuint fbID, int width, int height) noexcept
  153. : context (c), frameBufferID (fbID), bounds (width, height)
  154. {}
  155. Target (OpenGLContext& c, OpenGLFrameBuffer& fb, Point<int> origin) noexcept
  156. : context (c), frameBufferID (fb.getFrameBufferID()),
  157. bounds (origin.x, origin.y, fb.getWidth(), fb.getHeight())
  158. {
  159. jassert (frameBufferID != 0); // trying to render into an uninitialised framebuffer object.
  160. }
  161. Target (const Target& other) noexcept
  162. : context (other.context), frameBufferID (other.frameBufferID), bounds (other.bounds)
  163. {}
  164. Target& operator= (const Target& other) noexcept
  165. {
  166. frameBufferID = other.frameBufferID;
  167. bounds = other.bounds;
  168. return *this;
  169. }
  170. void makeActive() const noexcept
  171. {
  172. #if JUCE_WINDOWS
  173. if (context.extensions.glBindFramebuffer != nullptr)
  174. #endif
  175. context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferID);
  176. glViewport (0, 0, bounds.getWidth(), bounds.getHeight());
  177. glDisable (GL_DEPTH_TEST);
  178. }
  179. OpenGLContext& context;
  180. GLuint frameBufferID;
  181. Rectangle<int> bounds;
  182. };
  183. //==============================================================================
  184. class PositionedTexture
  185. {
  186. public:
  187. PositionedTexture (OpenGLTexture& texture, const EdgeTable& et, const Rectangle<int>& clipRegion)
  188. : clip (clipRegion.getIntersection (et.getMaximumBounds()))
  189. {
  190. if (clip.contains (et.getMaximumBounds()))
  191. {
  192. createMap (texture, et);
  193. }
  194. else
  195. {
  196. EdgeTable et2 (clip);
  197. et2.clipToEdgeTable (et);
  198. createMap (texture, et2);
  199. }
  200. }
  201. PositionedTexture (GLuint texture, const Rectangle<int> r, const Rectangle<int> clipRegion) noexcept
  202. : textureID (texture), area (r), clip (clipRegion)
  203. {}
  204. GLuint textureID;
  205. Rectangle<int> area, clip;
  206. private:
  207. void createMap (OpenGLTexture& texture, const EdgeTable& et)
  208. {
  209. EdgeTableAlphaMap alphaMap (et);
  210. texture.loadAlpha (alphaMap.data, alphaMap.area.getWidth(), alphaMap.area.getHeight());
  211. textureID = texture.getTextureID();
  212. area = alphaMap.area;
  213. }
  214. struct EdgeTableAlphaMap
  215. {
  216. EdgeTableAlphaMap (const EdgeTable& et)
  217. : area (et.getMaximumBounds().withSize (nextPowerOfTwo (et.getMaximumBounds().getWidth()),
  218. nextPowerOfTwo (et.getMaximumBounds().getHeight())))
  219. {
  220. data.calloc ((size_t) (area.getWidth() * area.getHeight()));
  221. et.iterate (*this);
  222. }
  223. inline void setEdgeTableYPos (const int y) noexcept
  224. {
  225. currentLine = data + (area.getBottom() - 1 - y) * area.getWidth() - area.getX();
  226. }
  227. inline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
  228. {
  229. currentLine[x] = (uint8) alphaLevel;
  230. }
  231. inline void handleEdgeTablePixelFull (const int x) const noexcept
  232. {
  233. currentLine[x] = 255;
  234. }
  235. inline void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept
  236. {
  237. memset (currentLine + x, (uint8) alphaLevel, (size_t) width);
  238. }
  239. inline void handleEdgeTableLineFull (int x, int width) const noexcept
  240. {
  241. memset (currentLine + x, 255, (size_t) width);
  242. }
  243. HeapBlock<uint8> data;
  244. const Rectangle<int> area;
  245. private:
  246. uint8* currentLine;
  247. JUCE_DECLARE_NON_COPYABLE (EdgeTableAlphaMap)
  248. };
  249. };
  250. //==============================================================================
  251. class ShaderPrograms : public ReferenceCountedObject
  252. {
  253. public:
  254. ShaderPrograms (OpenGLContext& context)
  255. : solidColourProgram (context),
  256. solidColourMasked (context),
  257. radialGradient (context),
  258. radialGradientMasked (context),
  259. linearGradient1 (context),
  260. linearGradient1Masked (context),
  261. linearGradient2 (context),
  262. linearGradient2Masked (context),
  263. image (context),
  264. imageMasked (context),
  265. tiledImage (context),
  266. tiledImageMasked (context),
  267. copyTexture (context),
  268. maskTexture (context)
  269. {}
  270. typedef ReferenceCountedObjectPtr<ShaderPrograms> Ptr;
  271. //==============================================================================
  272. struct ShaderProgramHolder
  273. {
  274. ShaderProgramHolder (OpenGLContext& context, const char* fragmentShader)
  275. : program (context)
  276. {
  277. JUCE_CHECK_OPENGL_ERROR
  278. program.addVertexShader ("attribute vec2 position;"
  279. "attribute vec4 colour;"
  280. "uniform vec4 screenBounds;"
  281. "varying " JUCE_MEDIUMP " vec4 frontColour;"
  282. "varying " JUCE_HIGHP " vec2 pixelPos;"
  283. "void main()"
  284. "{"
  285. " frontColour = colour;"
  286. " vec2 adjustedPos = position - screenBounds.xy;"
  287. " pixelPos = adjustedPos;"
  288. " vec2 scaledPos = adjustedPos / screenBounds.zw;"
  289. " gl_Position = vec4 (scaledPos.x - 1.0, 1.0 - scaledPos.y, 0, 1.0);"
  290. "}");
  291. program.addFragmentShader (fragmentShader);
  292. program.link();
  293. JUCE_CHECK_OPENGL_ERROR
  294. }
  295. OpenGLShaderProgram program;
  296. };
  297. struct ShaderBase : public ShaderProgramHolder
  298. {
  299. ShaderBase (OpenGLContext& context, const char* fragmentShader)
  300. : ShaderProgramHolder (context, fragmentShader),
  301. positionAttribute (program, "position"),
  302. colourAttribute (program, "colour"),
  303. screenBounds (program, "screenBounds")
  304. {}
  305. void set2DBounds (const Rectangle<float>& bounds)
  306. {
  307. screenBounds.set (bounds.getX(), bounds.getY(), 0.5f * bounds.getWidth(), 0.5f * bounds.getHeight());
  308. }
  309. void bindAttributes (OpenGLContext& context)
  310. {
  311. context.extensions.glVertexAttribPointer ((GLuint) positionAttribute.attributeID, 2, GL_SHORT, GL_FALSE, 8, (void*) 0);
  312. context.extensions.glVertexAttribPointer ((GLuint) colourAttribute.attributeID, 4, GL_UNSIGNED_BYTE, GL_TRUE, 8, (void*) 4);
  313. context.extensions.glEnableVertexAttribArray ((GLuint) positionAttribute.attributeID);
  314. context.extensions.glEnableVertexAttribArray ((GLuint) colourAttribute.attributeID);
  315. }
  316. void unbindAttributes (OpenGLContext& context)
  317. {
  318. context.extensions.glDisableVertexAttribArray ((GLuint) positionAttribute.attributeID);
  319. context.extensions.glDisableVertexAttribArray ((GLuint) colourAttribute.attributeID);
  320. }
  321. OpenGLShaderProgram::Attribute positionAttribute, colourAttribute;
  322. private:
  323. OpenGLShaderProgram::Uniform screenBounds;
  324. };
  325. struct MaskedShaderParams
  326. {
  327. MaskedShaderParams (OpenGLShaderProgram& program)
  328. : maskTexture (program, "maskTexture"),
  329. maskBounds (program, "maskBounds")
  330. {}
  331. void setBounds (const Rectangle<int>& area, const Target& target, const GLint textureIndex) const
  332. {
  333. maskTexture.set (textureIndex);
  334. maskBounds.set (area.getX() - target.bounds.getX(),
  335. area.getY() - target.bounds.getY(),
  336. area.getWidth(), area.getHeight());
  337. }
  338. OpenGLShaderProgram::Uniform maskTexture, maskBounds;
  339. };
  340. //==============================================================================
  341. #define JUCE_DECLARE_VARYING_COLOUR "varying " JUCE_MEDIUMP " vec4 frontColour;"
  342. #define JUCE_DECLARE_VARYING_PIXELPOS "varying " JUCE_HIGHP " vec2 pixelPos;"
  343. struct SolidColourProgram : public ShaderBase
  344. {
  345. SolidColourProgram (OpenGLContext& context)
  346. : ShaderBase (context, JUCE_DECLARE_VARYING_COLOUR
  347. "void main() { gl_FragColor = frontColour; }")
  348. {}
  349. };
  350. #if JUCE_ANDROID
  351. #define JUCE_DECLARE_SWIZZLE_FUNCTION "\n" JUCE_MEDIUMP " vec4 swizzleRGBOrder (in " JUCE_MEDIUMP " vec4 c) { return vec4 (c.b, c.g, c.r, c.a); }\n"
  352. #else
  353. #define JUCE_DECLARE_SWIZZLE_FUNCTION "\n" JUCE_MEDIUMP " vec4 swizzleRGBOrder (in " JUCE_MEDIUMP " vec4 c) { return c; }\n"
  354. #endif
  355. #define JUCE_DECLARE_MASK_UNIFORMS "uniform sampler2D maskTexture;" \
  356. "uniform ivec4 maskBounds;"
  357. #define JUCE_FRAGCOORD_TO_MASK_POS "vec2 ((pixelPos.x - float (maskBounds.x)) / float (maskBounds.z)," \
  358. "1.0 - (pixelPos.y - float (maskBounds.y)) / float (maskBounds.w))"
  359. #define JUCE_GET_MASK_ALPHA "texture2D (maskTexture, " JUCE_FRAGCOORD_TO_MASK_POS ").a"
  360. struct SolidColourMaskedProgram : public ShaderBase
  361. {
  362. SolidColourMaskedProgram (OpenGLContext& context)
  363. : ShaderBase (context,
  364. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS
  365. "void main() {"
  366. "gl_FragColor = frontColour * " JUCE_GET_MASK_ALPHA ";"
  367. "}"),
  368. maskParams (program)
  369. {}
  370. MaskedShaderParams maskParams;
  371. };
  372. //==============================================================================
  373. struct RadialGradientParams
  374. {
  375. RadialGradientParams (OpenGLShaderProgram& program)
  376. : gradientTexture (program, "gradientTexture"),
  377. matrix (program, "matrix")
  378. {}
  379. void setMatrix (const Point<float> p1, const Point<float> p2, const Point<float> p3)
  380. {
  381. const AffineTransform t (AffineTransform::fromTargetPoints (p1.x, p1.y, 0.0f, 0.0f,
  382. p2.x, p2.y, 1.0f, 0.0f,
  383. p3.x, p3.y, 0.0f, 1.0f));
  384. const GLfloat m[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  385. matrix.set (m, 6);
  386. }
  387. OpenGLShaderProgram::Uniform gradientTexture, matrix;
  388. };
  389. #define JUCE_DECLARE_MATRIX_UNIFORM "uniform " JUCE_HIGHP " float matrix[6];"
  390. #define JUCE_DECLARE_RADIAL_UNIFORMS "uniform sampler2D gradientTexture;" JUCE_DECLARE_MATRIX_UNIFORM
  391. #define JUCE_MATRIX_TIMES_FRAGCOORD "(mat2 (matrix[0], matrix[3], matrix[1], matrix[4]) * pixelPos" \
  392. " + vec2 (matrix[2], matrix[5]))"
  393. #define JUCE_GET_TEXTURE_COLOUR "(frontColour.a * swizzleRGBOrder (texture2D (gradientTexture, vec2 (gradientPos, 0.5))))"
  394. struct RadialGradientProgram : public ShaderBase
  395. {
  396. RadialGradientProgram (OpenGLContext& context)
  397. : ShaderBase (context, JUCE_DECLARE_VARYING_PIXELPOS
  398. JUCE_DECLARE_RADIAL_UNIFORMS JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_SWIZZLE_FUNCTION
  399. "void main()"
  400. "{"
  401. JUCE_MEDIUMP " float gradientPos = length (" JUCE_MATRIX_TIMES_FRAGCOORD ");"
  402. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  403. "}"),
  404. gradientParams (program)
  405. {}
  406. RadialGradientParams gradientParams;
  407. };
  408. struct RadialGradientMaskedProgram : public ShaderBase
  409. {
  410. RadialGradientMaskedProgram (OpenGLContext& context)
  411. : ShaderBase (context, JUCE_DECLARE_VARYING_PIXELPOS
  412. JUCE_DECLARE_RADIAL_UNIFORMS JUCE_DECLARE_VARYING_COLOUR
  413. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  414. "void main()"
  415. "{"
  416. JUCE_MEDIUMP " float gradientPos = length (" JUCE_MATRIX_TIMES_FRAGCOORD ");"
  417. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  418. "}"),
  419. gradientParams (program),
  420. maskParams (program)
  421. {}
  422. RadialGradientParams gradientParams;
  423. MaskedShaderParams maskParams;
  424. };
  425. //==============================================================================
  426. struct LinearGradientParams
  427. {
  428. LinearGradientParams (OpenGLShaderProgram& program)
  429. : gradientTexture (program, "gradientTexture"),
  430. gradientInfo (program, "gradientInfo")
  431. {}
  432. OpenGLShaderProgram::Uniform gradientTexture, gradientInfo;
  433. };
  434. #define JUCE_DECLARE_LINEAR_UNIFORMS "uniform sampler2D gradientTexture;" \
  435. "uniform " JUCE_MEDIUMP " vec4 gradientInfo;" \
  436. JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS
  437. #define JUCE_CALC_LINEAR_GRAD_POS1 JUCE_MEDIUMP " float gradientPos = (pixelPos.y - (gradientInfo.y + (gradientInfo.z * (pixelPos.x - gradientInfo.x)))) / gradientInfo.w;"
  438. #define JUCE_CALC_LINEAR_GRAD_POS2 JUCE_MEDIUMP " float gradientPos = (pixelPos.x - (gradientInfo.x + (gradientInfo.z * (pixelPos.y - gradientInfo.y)))) / gradientInfo.w;"
  439. struct LinearGradient1Program : public ShaderBase
  440. {
  441. LinearGradient1Program (OpenGLContext& context)
  442. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  443. JUCE_DECLARE_SWIZZLE_FUNCTION
  444. "void main()"
  445. "{"
  446. JUCE_CALC_LINEAR_GRAD_POS1
  447. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  448. "}"),
  449. gradientParams (program)
  450. {}
  451. LinearGradientParams gradientParams;
  452. };
  453. struct LinearGradient1MaskedProgram : public ShaderBase
  454. {
  455. LinearGradient1MaskedProgram (OpenGLContext& context)
  456. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (y2 - y1) / (x2 - x1), w = length
  457. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  458. "void main()"
  459. "{"
  460. JUCE_CALC_LINEAR_GRAD_POS1
  461. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  462. "}"),
  463. gradientParams (program),
  464. maskParams (program)
  465. {}
  466. LinearGradientParams gradientParams;
  467. MaskedShaderParams maskParams;
  468. };
  469. struct LinearGradient2Program : public ShaderBase
  470. {
  471. LinearGradient2Program (OpenGLContext& context)
  472. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  473. JUCE_DECLARE_SWIZZLE_FUNCTION
  474. "void main()"
  475. "{"
  476. JUCE_CALC_LINEAR_GRAD_POS2
  477. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR ";"
  478. "}"),
  479. gradientParams (program)
  480. {}
  481. LinearGradientParams gradientParams;
  482. };
  483. struct LinearGradient2MaskedProgram : public ShaderBase
  484. {
  485. LinearGradient2MaskedProgram (OpenGLContext& context)
  486. : ShaderBase (context, JUCE_DECLARE_LINEAR_UNIFORMS // gradientInfo: x = x1, y = y1, z = (x2 - x1) / (y2 - y1), y = y1, w = length
  487. JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  488. "void main()"
  489. "{"
  490. JUCE_CALC_LINEAR_GRAD_POS2
  491. "gl_FragColor = " JUCE_GET_TEXTURE_COLOUR " * " JUCE_GET_MASK_ALPHA ";"
  492. "}"),
  493. gradientParams (program),
  494. maskParams (program)
  495. {}
  496. LinearGradientParams gradientParams;
  497. MaskedShaderParams maskParams;
  498. };
  499. //==============================================================================
  500. struct ImageParams
  501. {
  502. ImageParams (OpenGLShaderProgram& program)
  503. : imageTexture (program, "imageTexture"),
  504. matrix (program, "matrix"),
  505. imageLimits (program, "imageLimits")
  506. {}
  507. void setMatrix (const AffineTransform& trans,
  508. const int imageWidth, const int imageHeight,
  509. float fullWidthProportion, float fullHeightProportion,
  510. const float targetX, const float targetY,
  511. const bool isForTiling) const
  512. {
  513. const AffineTransform t (trans.translated (-targetX, -targetY)
  514. .inverted().scaled (fullWidthProportion / imageWidth,
  515. fullHeightProportion / imageHeight));
  516. const GLfloat m[] = { t.mat00, t.mat01, t.mat02, t.mat10, t.mat11, t.mat12 };
  517. matrix.set (m, 6);
  518. if (isForTiling)
  519. {
  520. fullWidthProportion -= 0.5f / imageWidth;
  521. fullHeightProportion -= 0.5f / imageHeight;
  522. }
  523. imageLimits.set (fullWidthProportion, fullHeightProportion);
  524. }
  525. void setMatrix (const AffineTransform& trans, const TextureInfo& textureInfo,
  526. const float targetX, const float targetY,
  527. bool isForTiling) const
  528. {
  529. setMatrix (trans,
  530. textureInfo.imageWidth, textureInfo.imageHeight,
  531. textureInfo.fullWidthProportion, textureInfo.fullHeightProportion,
  532. targetX, targetY, isForTiling);
  533. }
  534. OpenGLShaderProgram::Uniform imageTexture, matrix, imageLimits;
  535. };
  536. #define JUCE_DECLARE_IMAGE_UNIFORMS "uniform sampler2D imageTexture;" \
  537. "uniform " JUCE_MEDIUMP " vec2 imageLimits;" \
  538. JUCE_DECLARE_MATRIX_UNIFORM JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS
  539. #define JUCE_GET_IMAGE_PIXEL "swizzleRGBOrder (texture2D (imageTexture, vec2 (texturePos.x, 1.0 - texturePos.y)))"
  540. #define JUCE_CLAMP_TEXTURE_COORD JUCE_HIGHP " vec2 texturePos = clamp (" JUCE_MATRIX_TIMES_FRAGCOORD ", vec2 (0, 0), imageLimits);"
  541. #define JUCE_MOD_TEXTURE_COORD JUCE_HIGHP " vec2 texturePos = mod (" JUCE_MATRIX_TIMES_FRAGCOORD ", imageLimits);"
  542. struct ImageProgram : public ShaderBase
  543. {
  544. ImageProgram (OpenGLContext& context)
  545. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  546. "void main()"
  547. "{"
  548. JUCE_CLAMP_TEXTURE_COORD
  549. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL ";"
  550. "}"),
  551. imageParams (program)
  552. {}
  553. ImageParams imageParams;
  554. };
  555. struct ImageMaskedProgram : public ShaderBase
  556. {
  557. ImageMaskedProgram (OpenGLContext& context)
  558. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  559. "void main()"
  560. "{"
  561. JUCE_CLAMP_TEXTURE_COORD
  562. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL " * " JUCE_GET_MASK_ALPHA ";"
  563. "}"),
  564. imageParams (program),
  565. maskParams (program)
  566. {}
  567. ImageParams imageParams;
  568. MaskedShaderParams maskParams;
  569. };
  570. struct TiledImageProgram : public ShaderBase
  571. {
  572. TiledImageProgram (OpenGLContext& context)
  573. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  574. "void main()"
  575. "{"
  576. JUCE_MOD_TEXTURE_COORD
  577. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL ";"
  578. "}"),
  579. imageParams (program)
  580. {}
  581. ImageParams imageParams;
  582. };
  583. struct TiledImageMaskedProgram : public ShaderBase
  584. {
  585. TiledImageMaskedProgram (OpenGLContext& context)
  586. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_MASK_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  587. "void main()"
  588. "{"
  589. JUCE_MOD_TEXTURE_COORD
  590. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL " * " JUCE_GET_MASK_ALPHA ";"
  591. "}"),
  592. imageParams (program),
  593. maskParams (program)
  594. {}
  595. ImageParams imageParams;
  596. MaskedShaderParams maskParams;
  597. };
  598. struct CopyTextureProgram : public ShaderBase
  599. {
  600. CopyTextureProgram (OpenGLContext& context)
  601. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  602. "void main()"
  603. "{"
  604. JUCE_MOD_TEXTURE_COORD
  605. "gl_FragColor = frontColour.a * " JUCE_GET_IMAGE_PIXEL ";"
  606. "}"),
  607. imageParams (program)
  608. {}
  609. ImageParams imageParams;
  610. };
  611. struct MaskTextureProgram : public ShaderBase
  612. {
  613. MaskTextureProgram (OpenGLContext& context)
  614. : ShaderBase (context, JUCE_DECLARE_IMAGE_UNIFORMS JUCE_DECLARE_SWIZZLE_FUNCTION
  615. "void main()"
  616. "{"
  617. JUCE_HIGHP " vec2 texturePos = " JUCE_MATRIX_TIMES_FRAGCOORD ";"
  618. JUCE_HIGHP " float roundingError = 0.00001;"
  619. "if (texturePos.x >= -roundingError"
  620. "&& texturePos.y >= -roundingError"
  621. "&& texturePos.x <= imageLimits.x + roundingError"
  622. "&& texturePos.y <= imageLimits.y + roundingError)"
  623. "gl_FragColor = frontColour * " JUCE_GET_IMAGE_PIXEL ".a;"
  624. "else "
  625. "gl_FragColor = vec4 (0, 0, 0, 0);"
  626. "}"),
  627. imageParams (program)
  628. {}
  629. ImageParams imageParams;
  630. };
  631. SolidColourProgram solidColourProgram;
  632. SolidColourMaskedProgram solidColourMasked;
  633. RadialGradientProgram radialGradient;
  634. RadialGradientMaskedProgram radialGradientMasked;
  635. LinearGradient1Program linearGradient1;
  636. LinearGradient1MaskedProgram linearGradient1Masked;
  637. LinearGradient2Program linearGradient2;
  638. LinearGradient2MaskedProgram linearGradient2Masked;
  639. ImageProgram image;
  640. ImageMaskedProgram imageMasked;
  641. TiledImageProgram tiledImage;
  642. TiledImageMaskedProgram tiledImageMasked;
  643. CopyTextureProgram copyTexture;
  644. MaskTextureProgram maskTexture;
  645. };
  646. //==============================================================================
  647. struct StateHelpers
  648. {
  649. struct BlendingMode
  650. {
  651. BlendingMode() noexcept
  652. : blendingEnabled (false), srcFunction (0), dstFunction (0)
  653. {}
  654. void resync() noexcept
  655. {
  656. glDisable (GL_BLEND);
  657. srcFunction = dstFunction = 0;
  658. }
  659. template <class QuadQueueType>
  660. void setPremultipliedBlendingMode (QuadQueueType& quadQueue) noexcept
  661. {
  662. setBlendFunc (quadQueue, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  663. }
  664. template <class QuadQueueType>
  665. void setBlendFunc (QuadQueueType& quadQueue, GLenum src, GLenum dst)
  666. {
  667. if (! blendingEnabled)
  668. {
  669. quadQueue.flush();
  670. blendingEnabled = true;
  671. glEnable (GL_BLEND);
  672. }
  673. if (srcFunction != src || dstFunction != dst)
  674. {
  675. quadQueue.flush();
  676. srcFunction = src;
  677. dstFunction = dst;
  678. glBlendFunc (src, dst);
  679. }
  680. }
  681. template <class QuadQueueType>
  682. void disableBlend (QuadQueueType& quadQueue) noexcept
  683. {
  684. if (blendingEnabled)
  685. {
  686. quadQueue.flush();
  687. blendingEnabled = false;
  688. glDisable (GL_BLEND);
  689. }
  690. }
  691. template <class QuadQueueType>
  692. void setBlendMode (QuadQueueType& quadQueue, const bool replaceExistingContents) noexcept
  693. {
  694. if (replaceExistingContents)
  695. disableBlend (quadQueue);
  696. else
  697. setPremultipliedBlendingMode (quadQueue);
  698. }
  699. private:
  700. bool blendingEnabled;
  701. GLenum srcFunction, dstFunction;
  702. };
  703. //==============================================================================
  704. template <class QuadQueueType>
  705. struct EdgeTableRenderer
  706. {
  707. EdgeTableRenderer (QuadQueueType& q, const PixelARGB c) noexcept
  708. : quadQueue (q), colour (c)
  709. {}
  710. void setEdgeTableYPos (const int y) noexcept
  711. {
  712. currentY = y;
  713. }
  714. void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
  715. {
  716. PixelARGB c (colour);
  717. c.multiplyAlpha (alphaLevel);
  718. quadQueue.add (x, currentY, 1, 1, c);
  719. }
  720. void handleEdgeTablePixelFull (const int x) noexcept
  721. {
  722. quadQueue.add (x, currentY, 1, 1, colour);
  723. }
  724. void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept
  725. {
  726. PixelARGB c (colour);
  727. c.multiplyAlpha (alphaLevel);
  728. quadQueue.add (x, currentY, width, 1, c);
  729. }
  730. void handleEdgeTableLineFull (const int x, const int width) noexcept
  731. {
  732. quadQueue.add (x, currentY, width, 1, colour);
  733. }
  734. private:
  735. QuadQueueType& quadQueue;
  736. const PixelARGB colour;
  737. int currentY;
  738. JUCE_DECLARE_NON_COPYABLE (EdgeTableRenderer)
  739. };
  740. template <class QuadQueueType>
  741. struct FloatRectangleRenderer
  742. {
  743. FloatRectangleRenderer (QuadQueueType& q, const PixelARGB c) noexcept
  744. : quadQueue (q), colour (c)
  745. {}
  746. void operator() (const int x, const int y, const int w, const int h, const int alpha) noexcept
  747. {
  748. if (w > 0 && h > 0)
  749. {
  750. PixelARGB c (colour);
  751. c.multiplyAlpha (alpha);
  752. quadQueue.add (x, y, w, h, c);
  753. }
  754. }
  755. private:
  756. QuadQueueType& quadQueue;
  757. const PixelARGB colour;
  758. JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer)
  759. };
  760. //==============================================================================
  761. struct ActiveTextures
  762. {
  763. ActiveTextures (const OpenGLContext& c) noexcept
  764. : texturesEnabled (0), currentActiveTexture (-1), context (c)
  765. {}
  766. void clear() noexcept
  767. {
  768. zeromem (currentTextureID, sizeof (currentTextureID));
  769. }
  770. template <class QuadQueueType>
  771. void setTexturesEnabled (QuadQueueType& quadQueue, const int textureIndexMask) noexcept
  772. {
  773. if (texturesEnabled != textureIndexMask)
  774. {
  775. quadQueue.flush();
  776. for (int i = 3; --i >= 0;)
  777. {
  778. if ((texturesEnabled & (1 << i)) != (textureIndexMask & (1 << i)))
  779. {
  780. setActiveTexture (i);
  781. JUCE_CHECK_OPENGL_ERROR
  782. #if ! JUCE_ANDROID
  783. if ((textureIndexMask & (1 << i)) != 0)
  784. glEnable (GL_TEXTURE_2D);
  785. else
  786. {
  787. glDisable (GL_TEXTURE_2D);
  788. currentTextureID[i] = 0;
  789. }
  790. clearGLError();
  791. #endif
  792. }
  793. }
  794. texturesEnabled = textureIndexMask;
  795. }
  796. }
  797. template <class QuadQueueType>
  798. void disableTextures (QuadQueueType& quadQueue) noexcept
  799. {
  800. setTexturesEnabled (quadQueue, 0);
  801. }
  802. template <class QuadQueueType>
  803. void setSingleTextureMode (QuadQueueType& quadQueue) noexcept
  804. {
  805. setTexturesEnabled (quadQueue, 1);
  806. setActiveTexture (0);
  807. }
  808. template <class QuadQueueType>
  809. void setTwoTextureMode (QuadQueueType& quadQueue, GLuint texture1, GLuint texture2)
  810. {
  811. JUCE_CHECK_OPENGL_ERROR
  812. setTexturesEnabled (quadQueue, 3);
  813. if (currentActiveTexture == 0)
  814. {
  815. bindTexture (texture1);
  816. setActiveTexture (1);
  817. bindTexture (texture2);
  818. }
  819. else
  820. {
  821. setActiveTexture (1);
  822. bindTexture (texture2);
  823. setActiveTexture (0);
  824. bindTexture (texture1);
  825. }
  826. JUCE_CHECK_OPENGL_ERROR
  827. }
  828. void setActiveTexture (const int index) noexcept
  829. {
  830. if (currentActiveTexture != index)
  831. {
  832. currentActiveTexture = index;
  833. context.extensions.glActiveTexture ((GLenum) (GL_TEXTURE0 + index));
  834. JUCE_CHECK_OPENGL_ERROR
  835. }
  836. }
  837. void bindTexture (const GLuint textureID) noexcept
  838. {
  839. jassert (currentActiveTexture >= 0);
  840. if (currentTextureID [currentActiveTexture] != textureID)
  841. {
  842. currentTextureID [currentActiveTexture] = textureID;
  843. glBindTexture (GL_TEXTURE_2D, textureID);
  844. JUCE_CHECK_OPENGL_ERROR
  845. }
  846. else
  847. {
  848. #if JUCE_DEBUG
  849. GLint t = 0;
  850. glGetIntegerv (GL_TEXTURE_BINDING_2D, &t);
  851. jassert (t == (GLint) textureID);
  852. #endif
  853. }
  854. }
  855. private:
  856. GLuint currentTextureID [3];
  857. int texturesEnabled, currentActiveTexture;
  858. const OpenGLContext& context;
  859. ActiveTextures& operator= (const ActiveTextures&);
  860. };
  861. //==============================================================================
  862. struct TextureCache
  863. {
  864. TextureCache() noexcept
  865. : activeGradientIndex (0), gradientNeedsRefresh (true)
  866. {}
  867. OpenGLTexture* getTexture (ActiveTextures& activeTextures, int w, int h)
  868. {
  869. if (textures.size() < numTexturesToCache)
  870. {
  871. activeTextures.clear();
  872. return new OpenGLTexture();
  873. }
  874. for (int i = 0; i < numTexturesToCache - 2; ++i)
  875. {
  876. const OpenGLTexture* const t = textures.getUnchecked(i);
  877. if (t->getWidth() == w && t->getHeight() == h)
  878. return textures.removeAndReturn (i);
  879. }
  880. return textures.removeAndReturn (0);
  881. }
  882. void resetGradient() noexcept
  883. {
  884. gradientNeedsRefresh = true;
  885. }
  886. void bindTextureForGradient (ActiveTextures& activeTextures, const ColourGradient& gradient)
  887. {
  888. if (gradientNeedsRefresh)
  889. {
  890. gradientNeedsRefresh = false;
  891. if (gradientTextures.size() < numGradientTexturesToCache)
  892. {
  893. activeGradientIndex = gradientTextures.size();
  894. activeTextures.clear();
  895. gradientTextures.add (new OpenGLTexture());
  896. }
  897. else
  898. {
  899. activeGradientIndex = (activeGradientIndex + 1) % numGradientTexturesToCache;
  900. }
  901. JUCE_CHECK_OPENGL_ERROR;
  902. PixelARGB lookup [gradientTextureSize];
  903. gradient.createLookupTable (lookup, gradientTextureSize);
  904. gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1);
  905. }
  906. activeTextures.bindTexture (gradientTextures.getUnchecked (activeGradientIndex)->getTextureID());
  907. }
  908. enum { gradientTextureSize = 256 };
  909. private:
  910. enum { numTexturesToCache = 8, numGradientTexturesToCache = 10 };
  911. OwnedArray<OpenGLTexture> textures, gradientTextures;
  912. int activeGradientIndex;
  913. bool gradientNeedsRefresh;
  914. };
  915. //==============================================================================
  916. struct ShaderQuadQueue
  917. {
  918. ShaderQuadQueue (const OpenGLContext& c) noexcept
  919. : context (c), numVertices (0)
  920. {}
  921. ~ShaderQuadQueue() noexcept
  922. {
  923. static_jassert (sizeof (VertexInfo) == 8);
  924. context.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
  925. context.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
  926. context.extensions.glDeleteBuffers (2, buffers);
  927. }
  928. void initialise() noexcept
  929. {
  930. JUCE_CHECK_OPENGL_ERROR
  931. for (int i = 0, v = 0; i < numQuads * 6; i += 6, v += 4)
  932. {
  933. indexData[i] = (GLushort) v;
  934. indexData[i + 1] = indexData[i + 3] = (GLushort) (v + 1);
  935. indexData[i + 2] = indexData[i + 4] = (GLushort) (v + 2);
  936. indexData[i + 5] = (GLushort) (v + 3);
  937. }
  938. context.extensions.glGenBuffers (2, buffers);
  939. context.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffers[0]);
  940. context.extensions.glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indexData), indexData, GL_STATIC_DRAW);
  941. context.extensions.glBindBuffer (GL_ARRAY_BUFFER, buffers[1]);
  942. context.extensions.glBufferData (GL_ARRAY_BUFFER, sizeof (vertexData), vertexData, GL_STREAM_DRAW);
  943. JUCE_CHECK_OPENGL_ERROR
  944. }
  945. void add (const int x, const int y, const int w, const int h, const PixelARGB colour) noexcept
  946. {
  947. jassert (w > 0 && h > 0);
  948. VertexInfo* const v = vertexData + numVertices;
  949. v[0].x = v[2].x = (GLshort) x;
  950. v[0].y = v[1].y = (GLshort) y;
  951. v[1].x = v[3].x = (GLshort) (x + w);
  952. v[2].y = v[3].y = (GLshort) (y + h);
  953. const GLuint rgba = colour.getInRGBAMemoryOrder();
  954. v[0].colour = rgba;
  955. v[1].colour = rgba;
  956. v[2].colour = rgba;
  957. v[3].colour = rgba;
  958. numVertices += 4;
  959. if (numVertices > numQuads * 4 - 4)
  960. draw();
  961. }
  962. void add (const Rectangle<int>& r, const PixelARGB colour) noexcept
  963. {
  964. add (r.getX(), r.getY(), r.getWidth(), r.getHeight(), colour);
  965. }
  966. void add (const Rectangle<float>& r, const PixelARGB colour) noexcept
  967. {
  968. FloatRectangleRenderer<ShaderQuadQueue> frr (*this, colour);
  969. RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (frr);
  970. }
  971. void add (const RectangleList<int>& list, const PixelARGB colour) noexcept
  972. {
  973. for (const Rectangle<int>* i = list.begin(), * const e = list.end(); i != e; ++i)
  974. add (*i, colour);
  975. }
  976. void add (const RectangleList<int>& list, const Rectangle<int>& clip, const PixelARGB colour) noexcept
  977. {
  978. for (const Rectangle<int>* i = list.begin(), * const e = list.end(); i != e; ++i)
  979. {
  980. const Rectangle<int> r (i->getIntersection (clip));
  981. if (! r.isEmpty())
  982. add (r, colour);
  983. }
  984. }
  985. template <class IteratorType>
  986. void add (const IteratorType& et, const PixelARGB colour)
  987. {
  988. EdgeTableRenderer<ShaderQuadQueue> etr (*this, colour);
  989. et.iterate (etr);
  990. }
  991. void flush() noexcept
  992. {
  993. if (numVertices > 0)
  994. draw();
  995. }
  996. private:
  997. struct VertexInfo
  998. {
  999. GLshort x, y;
  1000. GLuint colour;
  1001. };
  1002. enum { numQuads = 256 };
  1003. GLuint buffers[2];
  1004. VertexInfo vertexData [numQuads * 4];
  1005. GLushort indexData [numQuads * 6];
  1006. const OpenGLContext& context;
  1007. int numVertices;
  1008. void draw() noexcept
  1009. {
  1010. context.extensions.glBufferSubData (GL_ARRAY_BUFFER, 0, (GLsizeiptr) ((size_t) numVertices * sizeof (VertexInfo)), vertexData);
  1011. // NB: If you get a random crash in here and are running in a Parallels VM, it seems to be a bug in
  1012. // their driver.. Can't find a workaround unfortunately.
  1013. glDrawElements (GL_TRIANGLES, (numVertices * 3) / 2, GL_UNSIGNED_SHORT, 0);
  1014. JUCE_CHECK_OPENGL_ERROR
  1015. numVertices = 0;
  1016. }
  1017. JUCE_DECLARE_NON_COPYABLE (ShaderQuadQueue)
  1018. };
  1019. //==============================================================================
  1020. struct CurrentShader
  1021. {
  1022. CurrentShader (OpenGLContext& c) noexcept
  1023. : context (c), activeShader (nullptr)
  1024. {
  1025. const char programValueID[] = "GraphicsContextPrograms";
  1026. programs = static_cast<ShaderPrograms*> (context.getAssociatedObject (programValueID));
  1027. if (programs == nullptr)
  1028. {
  1029. programs = new ShaderPrograms (context);
  1030. context.setAssociatedObject (programValueID, programs);
  1031. }
  1032. }
  1033. ~CurrentShader()
  1034. {
  1035. jassert (activeShader == nullptr);
  1036. }
  1037. void setShader (const Rectangle<int>& bounds, ShaderQuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  1038. {
  1039. if (activeShader != &shader)
  1040. {
  1041. clearShader (quadQueue);
  1042. activeShader = &shader;
  1043. shader.program.use();
  1044. shader.bindAttributes (context);
  1045. currentBounds = bounds;
  1046. shader.set2DBounds (bounds.toFloat());
  1047. JUCE_CHECK_OPENGL_ERROR
  1048. }
  1049. else if (bounds != currentBounds)
  1050. {
  1051. currentBounds = bounds;
  1052. shader.set2DBounds (bounds.toFloat());
  1053. }
  1054. }
  1055. void setShader (Target& target, ShaderQuadQueue& quadQueue, ShaderPrograms::ShaderBase& shader)
  1056. {
  1057. setShader (target.bounds, quadQueue, shader);
  1058. }
  1059. void clearShader (ShaderQuadQueue& quadQueue)
  1060. {
  1061. if (activeShader != nullptr)
  1062. {
  1063. quadQueue.flush();
  1064. activeShader->unbindAttributes (context);
  1065. activeShader = nullptr;
  1066. context.extensions.glUseProgram (0);
  1067. }
  1068. }
  1069. OpenGLContext& context;
  1070. ShaderPrograms::Ptr programs;
  1071. private:
  1072. ShaderPrograms::ShaderBase* activeShader;
  1073. Rectangle<int> currentBounds;
  1074. CurrentShader& operator= (const CurrentShader&);
  1075. };
  1076. };
  1077. //==============================================================================
  1078. class GLState
  1079. {
  1080. public:
  1081. GLState (const Target& t) noexcept
  1082. : target (t),
  1083. activeTextures (t.context),
  1084. currentShader (t.context),
  1085. shaderQuadQueue (t.context),
  1086. previousFrameBufferTarget (OpenGLFrameBuffer::getCurrentFrameBufferTarget())
  1087. {
  1088. // This object can only be created and used when the current thread has an active OpenGL context.
  1089. jassert (OpenGLHelpers::isContextActive());
  1090. JUCE_CHECK_OPENGL_ERROR
  1091. target.makeActive();
  1092. blendMode.resync();
  1093. JUCE_CHECK_OPENGL_ERROR
  1094. activeTextures.clear();
  1095. shaderQuadQueue.initialise();
  1096. cachedImageList = CachedImageList::get (t.context);
  1097. JUCE_CHECK_OPENGL_ERROR
  1098. }
  1099. ~GLState()
  1100. {
  1101. flush();
  1102. target.context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget);
  1103. }
  1104. void flush()
  1105. {
  1106. shaderQuadQueue.flush();
  1107. currentShader.clearShader (shaderQuadQueue);
  1108. JUCE_CHECK_OPENGL_ERROR
  1109. }
  1110. void setShader (ShaderPrograms::ShaderBase& shader)
  1111. {
  1112. currentShader.setShader (target, shaderQuadQueue, shader);
  1113. JUCE_CHECK_OPENGL_ERROR
  1114. }
  1115. void setShaderForGradientFill (const ColourGradient& g, const AffineTransform& transform,
  1116. const int maskTextureID, const Rectangle<int>* const maskArea)
  1117. {
  1118. JUCE_CHECK_OPENGL_ERROR
  1119. activeTextures.disableTextures (shaderQuadQueue);
  1120. blendMode.setPremultipliedBlendingMode (shaderQuadQueue);
  1121. JUCE_CHECK_OPENGL_ERROR
  1122. if (maskArea != nullptr)
  1123. {
  1124. activeTextures.setTexturesEnabled (shaderQuadQueue, 3);
  1125. activeTextures.setActiveTexture (1);
  1126. activeTextures.bindTexture ((GLuint) maskTextureID);
  1127. activeTextures.setActiveTexture (0);
  1128. textureCache.bindTextureForGradient (activeTextures, g);
  1129. }
  1130. else
  1131. {
  1132. activeTextures.setSingleTextureMode (shaderQuadQueue);
  1133. textureCache.bindTextureForGradient (activeTextures, g);
  1134. }
  1135. const AffineTransform t (transform.translated (0.5f - target.bounds.getX(),
  1136. 0.5f - target.bounds.getY()));
  1137. Point<float> p1 (g.point1.transformedBy (t));
  1138. const Point<float> p2 (g.point2.transformedBy (t));
  1139. const Point<float> p3 (Point<float> (g.point1.x + (g.point2.y - g.point1.y),
  1140. g.point1.y - (g.point2.x - g.point1.x)).transformedBy (t));
  1141. ShaderPrograms* const programs = currentShader.programs;
  1142. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1143. if (g.isRadial)
  1144. {
  1145. ShaderPrograms::RadialGradientParams* gradientParams;
  1146. if (maskArea == nullptr)
  1147. {
  1148. setShader (programs->radialGradient);
  1149. gradientParams = &programs->radialGradient.gradientParams;
  1150. }
  1151. else
  1152. {
  1153. setShader (programs->radialGradientMasked);
  1154. gradientParams = &programs->radialGradientMasked.gradientParams;
  1155. maskParams = &programs->radialGradientMasked.maskParams;
  1156. }
  1157. gradientParams->setMatrix (p1, p2, p3);
  1158. }
  1159. else
  1160. {
  1161. p1 = Line<float> (p1, p3).findNearestPointTo (p2);
  1162. const Point<float> delta (p2.x - p1.x, p1.y - p2.y);
  1163. const ShaderPrograms::LinearGradientParams* gradientParams;
  1164. float grad, length;
  1165. if (std::abs (delta.x) < std::abs (delta.y))
  1166. {
  1167. if (maskArea == nullptr)
  1168. {
  1169. setShader (programs->linearGradient1);
  1170. gradientParams = &(programs->linearGradient1.gradientParams);
  1171. }
  1172. else
  1173. {
  1174. setShader (programs->linearGradient1Masked);
  1175. gradientParams = &(programs->linearGradient1Masked.gradientParams);
  1176. maskParams = &programs->linearGradient1Masked.maskParams;
  1177. }
  1178. grad = delta.x / delta.y;
  1179. length = (p2.y - grad * p2.x) - (p1.y - grad * p1.x);
  1180. }
  1181. else
  1182. {
  1183. if (maskArea == nullptr)
  1184. {
  1185. setShader (programs->linearGradient2);
  1186. gradientParams = &(programs->linearGradient2.gradientParams);
  1187. }
  1188. else
  1189. {
  1190. setShader (programs->linearGradient2Masked);
  1191. gradientParams = &(programs->linearGradient2Masked.gradientParams);
  1192. maskParams = &programs->linearGradient2Masked.maskParams;
  1193. }
  1194. grad = delta.y / delta.x;
  1195. length = (p2.x - grad * p2.y) - (p1.x - grad * p1.y);
  1196. }
  1197. gradientParams->gradientInfo.set (p1.x, p1.y, grad, length);
  1198. }
  1199. if (maskParams != nullptr)
  1200. maskParams->setBounds (*maskArea, target, 1);
  1201. JUCE_CHECK_OPENGL_ERROR
  1202. }
  1203. void setShaderForTiledImageFill (const TextureInfo& textureInfo, const AffineTransform& transform,
  1204. const int maskTextureID, const Rectangle<int>* const maskArea, bool isTiledFill)
  1205. {
  1206. blendMode.setPremultipliedBlendingMode (shaderQuadQueue);
  1207. ShaderPrograms* const programs = currentShader.programs;
  1208. const ShaderPrograms::MaskedShaderParams* maskParams = nullptr;
  1209. const ShaderPrograms::ImageParams* imageParams;
  1210. if (maskArea != nullptr)
  1211. {
  1212. activeTextures.setTwoTextureMode (shaderQuadQueue, textureInfo.textureID, (GLuint) maskTextureID);
  1213. if (isTiledFill)
  1214. {
  1215. setShader (programs->tiledImageMasked);
  1216. imageParams = &programs->tiledImageMasked.imageParams;
  1217. maskParams = &programs->tiledImageMasked.maskParams;
  1218. }
  1219. else
  1220. {
  1221. setShader (programs->imageMasked);
  1222. imageParams = &programs->imageMasked.imageParams;
  1223. maskParams = &programs->imageMasked.maskParams;
  1224. }
  1225. }
  1226. else
  1227. {
  1228. activeTextures.setSingleTextureMode (shaderQuadQueue);
  1229. activeTextures.bindTexture (textureInfo.textureID);
  1230. if (isTiledFill)
  1231. {
  1232. setShader (programs->tiledImage);
  1233. imageParams = &programs->tiledImage.imageParams;
  1234. }
  1235. else
  1236. {
  1237. setShader (programs->image);
  1238. imageParams = &programs->image.imageParams;
  1239. }
  1240. }
  1241. imageParams->setMatrix (transform, textureInfo, (float) target.bounds.getX(), (float) target.bounds.getY(), isTiledFill);
  1242. if (maskParams != nullptr)
  1243. maskParams->setBounds (*maskArea, target, 1);
  1244. }
  1245. Target target;
  1246. StateHelpers::BlendingMode blendMode;
  1247. StateHelpers::ActiveTextures activeTextures;
  1248. StateHelpers::TextureCache textureCache;
  1249. StateHelpers::CurrentShader currentShader;
  1250. StateHelpers::ShaderQuadQueue shaderQuadQueue;
  1251. CachedImageList::Ptr cachedImageList;
  1252. private:
  1253. GLuint previousFrameBufferTarget;
  1254. };
  1255. //==============================================================================
  1256. class SavedState : public RenderingHelpers::SavedStateBase<SavedState>
  1257. {
  1258. typedef RenderingHelpers::SavedStateBase<SavedState> BaseClass;
  1259. public:
  1260. SavedState (GLState* const s)
  1261. : BaseClass (s->target.bounds), state (s)
  1262. {}
  1263. SavedState (const SavedState& other)
  1264. : BaseClass (other), font (other.font),
  1265. state (other.state), transparencyLayer (other.transparencyLayer),
  1266. previousTarget (other.previousTarget.createCopy())
  1267. {}
  1268. SavedState* beginTransparencyLayer (float opacity)
  1269. {
  1270. SavedState* const s = new SavedState (*this);
  1271. if (clip != nullptr)
  1272. {
  1273. const Rectangle<int> clipBounds (clip->getClipBounds());
  1274. state->flush();
  1275. s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
  1276. s->previousTarget = new Target (state->target);
  1277. state->target = Target (state->target.context, *OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
  1278. s->transparencyLayerAlpha = opacity;
  1279. s->cloneClipIfMultiplyReferenced();
  1280. s->state->target.makeActive();
  1281. }
  1282. return s;
  1283. }
  1284. void endTransparencyLayer (SavedState& finishedLayerState)
  1285. {
  1286. if (clip != nullptr)
  1287. {
  1288. jassert (finishedLayerState.previousTarget != nullptr);
  1289. state->flush();
  1290. state->target = *finishedLayerState.previousTarget;
  1291. finishedLayerState.previousTarget = nullptr;
  1292. state->target.makeActive();
  1293. const Rectangle<int> clipBounds (clip->getClipBounds());
  1294. clip->renderImageUntransformed (*this, finishedLayerState.transparencyLayer,
  1295. (int) (finishedLayerState.transparencyLayerAlpha * 255.0f),
  1296. clipBounds.getX(), clipBounds.getY(), false);
  1297. }
  1298. }
  1299. typedef RenderingHelpers::GlyphCache <RenderingHelpers::CachedGlyphEdgeTable <SavedState>, SavedState> GlyphCacheType;
  1300. void drawGlyph (int glyphNumber, const AffineTransform& trans)
  1301. {
  1302. if (clip != nullptr)
  1303. {
  1304. if (trans.isOnlyTranslation() && ! transform.isRotated)
  1305. {
  1306. GlyphCacheType& cache = GlyphCacheType::getInstance();
  1307. Point<float> pos (trans.getTranslationX(), trans.getTranslationY());
  1308. if (transform.isOnlyTranslated)
  1309. {
  1310. cache.drawGlyph (*this, font, glyphNumber, pos + transform.offset.toFloat());
  1311. }
  1312. else
  1313. {
  1314. pos = transform.transformed (pos);
  1315. Font f (font);
  1316. f.setHeight (font.getHeight() * transform.complexTransform.mat11);
  1317. const float xScale = transform.complexTransform.mat00 / transform.complexTransform.mat11;
  1318. if (std::abs (xScale - 1.0f) > 0.01f)
  1319. f.setHorizontalScale (xScale);
  1320. cache.drawGlyph (*this, f, glyphNumber, pos);
  1321. }
  1322. }
  1323. else
  1324. {
  1325. const float fontHeight = font.getHeight();
  1326. AffineTransform t (transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
  1327. .followedBy (trans)));
  1328. const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t, fontHeight));
  1329. if (et != nullptr)
  1330. fillShape (new EdgeTableRegionType (*et), false);
  1331. }
  1332. }
  1333. }
  1334. Rectangle<int> getMaximumBounds() const { return state->target.bounds; }
  1335. void setFillType (const FillType& newFill)
  1336. {
  1337. BaseClass::setFillType (newFill);
  1338. state->textureCache.resetGradient();
  1339. }
  1340. //==============================================================================
  1341. template <typename IteratorType>
  1342. void renderImageTransformed (IteratorType& iter, const Image& src, const int alpha,
  1343. const AffineTransform& trans, Graphics::ResamplingQuality, bool tiledFill) const
  1344. {
  1345. state->shaderQuadQueue.flush();
  1346. state->setShaderForTiledImageFill (state->cachedImageList->getTextureFor (src), trans, 0, nullptr, tiledFill);
  1347. state->shaderQuadQueue.add (iter, PixelARGB ((uint8) alpha, (uint8) alpha, (uint8) alpha, (uint8) alpha));
  1348. state->shaderQuadQueue.flush();
  1349. state->currentShader.clearShader (state->shaderQuadQueue);
  1350. }
  1351. template <typename IteratorType>
  1352. void renderImageUntransformed (IteratorType& iter, const Image& src, const int alpha, int x, int y, bool tiledFill) const
  1353. {
  1354. renderImageTransformed (iter, src, alpha, AffineTransform::translation ((float) x, (float) y),
  1355. Graphics::lowResamplingQuality, tiledFill);
  1356. }
  1357. template <typename IteratorType>
  1358. void fillWithSolidColour (IteratorType& iter, const PixelARGB colour, bool replaceContents) const
  1359. {
  1360. state->activeTextures.disableTextures (state->shaderQuadQueue);
  1361. state->blendMode.setBlendMode (state->shaderQuadQueue, replaceContents);
  1362. state->setShader (state->currentShader.programs->solidColourProgram);
  1363. state->shaderQuadQueue.add (iter, colour);
  1364. }
  1365. template <typename IteratorType>
  1366. void fillWithGradient (IteratorType& iter, ColourGradient& gradient, const AffineTransform& trans, bool /*isIdentity*/) const
  1367. {
  1368. state->setShaderForGradientFill (gradient, trans, 0, nullptr);
  1369. state->shaderQuadQueue.add (iter, fillType.colour.getPixelARGB());
  1370. }
  1371. //==============================================================================
  1372. Font font;
  1373. GLState* state;
  1374. private:
  1375. Image transparencyLayer;
  1376. ScopedPointer<Target> previousTarget;
  1377. SavedState& operator= (const SavedState&);
  1378. };
  1379. //==============================================================================
  1380. class ShaderContext : public RenderingHelpers::StackBasedLowLevelGraphicsContext <SavedState>
  1381. {
  1382. public:
  1383. ShaderContext (const Target& target) : glState (target)
  1384. {
  1385. stack.initialise (new SavedState (&glState));
  1386. }
  1387. private:
  1388. GLState glState;
  1389. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ShaderContext)
  1390. };
  1391. class NonShaderContext : public LowLevelGraphicsSoftwareRenderer
  1392. {
  1393. public:
  1394. NonShaderContext (const Target& t, const Image& im)
  1395. : LowLevelGraphicsSoftwareRenderer (im), target (t), image (im)
  1396. {}
  1397. ~NonShaderContext()
  1398. {
  1399. JUCE_CHECK_OPENGL_ERROR
  1400. const GLuint previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget();
  1401. #if ! JUCE_ANDROID
  1402. target.context.extensions.glActiveTexture (GL_TEXTURE0);
  1403. glEnable (GL_TEXTURE_2D);
  1404. clearGLError();
  1405. #endif
  1406. OpenGLTexture texture;
  1407. texture.loadImage (image);
  1408. texture.bind();
  1409. target.makeActive();
  1410. target.context.copyTexture (target.bounds, Rectangle<int> (texture.getWidth(),
  1411. texture.getHeight()),
  1412. target.bounds.getWidth(), target.bounds.getHeight(),
  1413. false);
  1414. glBindTexture (GL_TEXTURE_2D, 0);
  1415. #if JUCE_WINDOWS
  1416. if (target.context.extensions.glBindFramebuffer != nullptr)
  1417. #endif
  1418. target.context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget);
  1419. JUCE_CHECK_OPENGL_ERROR
  1420. }
  1421. private:
  1422. Target target;
  1423. Image image;
  1424. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NonShaderContext)
  1425. };
  1426. LowLevelGraphicsContext* createOpenGLContext (const Target&);
  1427. LowLevelGraphicsContext* createOpenGLContext (const Target& target)
  1428. {
  1429. if (target.context.areShadersAvailable())
  1430. return new ShaderContext (target);
  1431. Image tempImage (Image::ARGB, target.bounds.getWidth(), target.bounds.getHeight(), true, SoftwareImageType());
  1432. return new NonShaderContext (target, tempImage);
  1433. }
  1434. }
  1435. //==============================================================================
  1436. LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, int width, int height)
  1437. {
  1438. return createOpenGLGraphicsContext (context, context.getFrameBufferID(), width, height);
  1439. }
  1440. LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, OpenGLFrameBuffer& target)
  1441. {
  1442. return OpenGLRendering::createOpenGLContext (OpenGLRendering::Target (context, target, Point<int>()));
  1443. }
  1444. LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, unsigned int frameBufferID, int width, int height)
  1445. {
  1446. using namespace OpenGLRendering;
  1447. return OpenGLRendering::createOpenGLContext (OpenGLRendering::Target (context, frameBufferID, width, height));
  1448. }
  1449. void clearOpenGLGlyphCache();
  1450. void clearOpenGLGlyphCache()
  1451. {
  1452. OpenGLRendering::SavedState::GlyphCacheType::getInstance().reset();
  1453. }