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.

871 lines
28KB

  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. class OpenGLContext::CachedImage : public CachedComponentImage,
  18. public Thread
  19. {
  20. public:
  21. CachedImage (OpenGLContext& c, Component& comp,
  22. const OpenGLPixelFormat& pixFormat, void* contextToShare)
  23. : Thread ("OpenGL Rendering"),
  24. context (c), component (comp),
  25. scale (1.0),
  26. #if JUCE_OPENGL_ES
  27. shadersAvailable (true),
  28. #else
  29. shadersAvailable (false),
  30. #endif
  31. hasInitialised (false),
  32. needsUpdate (1)
  33. {
  34. nativeContext = new NativeContext (component, pixFormat, contextToShare, c.useMultisampling);
  35. if (nativeContext->createdOk())
  36. context.nativeContext = nativeContext;
  37. else
  38. nativeContext = nullptr;
  39. }
  40. ~CachedImage()
  41. {
  42. stop();
  43. }
  44. void start()
  45. {
  46. #if ! JUCE_ANDROID
  47. if (nativeContext != nullptr)
  48. startThread (6);
  49. #endif
  50. }
  51. void stop()
  52. {
  53. #if ! JUCE_ANDROID
  54. stopThread (10000);
  55. #endif
  56. hasInitialised = false;
  57. }
  58. //==============================================================================
  59. void paint (Graphics&) override
  60. {
  61. if (ComponentPeer* const peer = component.getPeer())
  62. peer->addMaskedRegion (peer->getComponent().getLocalArea (&component, component.getLocalBounds()));
  63. }
  64. void invalidateAll() override
  65. {
  66. validArea.clear();
  67. triggerRepaint();
  68. }
  69. void invalidate (const Rectangle<int>& area) override
  70. {
  71. validArea.subtract (area);
  72. triggerRepaint();
  73. }
  74. void releaseResources() override {}
  75. void triggerRepaint()
  76. {
  77. needsUpdate = 1;
  78. #if JUCE_ANDROID
  79. if (nativeContext != nullptr)
  80. nativeContext->triggerRepaint();
  81. #else
  82. notify();
  83. #endif
  84. }
  85. //==============================================================================
  86. bool ensureFrameBufferSize()
  87. {
  88. const int fbW = cachedImageFrameBuffer.getWidth();
  89. const int fbH = cachedImageFrameBuffer.getHeight();
  90. if (fbW != viewportArea.getWidth() || fbH != viewportArea.getHeight() || ! cachedImageFrameBuffer.isValid())
  91. {
  92. if (! cachedImageFrameBuffer.initialise (context, viewportArea.getWidth(), viewportArea.getHeight()))
  93. return false;
  94. validArea.clear();
  95. JUCE_CHECK_OPENGL_ERROR
  96. }
  97. return true;
  98. }
  99. void clearRegionInFrameBuffer (const RectangleList<int>& list, const float scaleFactor)
  100. {
  101. glClearColor (0, 0, 0, 0);
  102. glEnable (GL_SCISSOR_TEST);
  103. const GLuint previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget();
  104. cachedImageFrameBuffer.makeCurrentRenderingTarget();
  105. const int imageH = cachedImageFrameBuffer.getHeight();
  106. for (const Rectangle<int>* i = list.begin(), * const e = list.end(); i != e; ++i)
  107. {
  108. const Rectangle<int> r ((i->toFloat() * scaleFactor).getSmallestIntegerContainer());
  109. glScissor (r.getX(), imageH - r.getBottom(), r.getWidth(), r.getHeight());
  110. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  111. }
  112. glDisable (GL_SCISSOR_TEST);
  113. context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, previousFrameBufferTarget);
  114. JUCE_CHECK_OPENGL_ERROR
  115. }
  116. bool renderFrame()
  117. {
  118. ScopedPointer<MessageManagerLock> mmLock;
  119. const bool isUpdating = needsUpdate.compareAndSetBool (0, 1);
  120. if (context.renderComponents && isUpdating)
  121. {
  122. mmLock = new MessageManagerLock (this); // need to acquire this before locking the context.
  123. if (! mmLock->lockWasGained())
  124. return false;
  125. }
  126. if (! context.makeActive())
  127. return false;
  128. NativeContext::Locker locker (*nativeContext);
  129. JUCE_CHECK_OPENGL_ERROR
  130. if (context.renderer != nullptr)
  131. {
  132. glViewport (0, 0, viewportArea.getWidth(), viewportArea.getHeight());
  133. context.renderer->renderOpenGL();
  134. clearGLError();
  135. }
  136. if (context.renderComponents)
  137. {
  138. if (isUpdating)
  139. {
  140. paintComponent();
  141. mmLock = nullptr;
  142. }
  143. glViewport (0, 0, viewportArea.getWidth(), viewportArea.getHeight());
  144. drawComponentBuffer();
  145. }
  146. context.swapBuffers();
  147. return true;
  148. }
  149. void updateViewportSize (bool canTriggerUpdate)
  150. {
  151. const double newScale = Desktop::getInstance().getDisplays()
  152. .getDisplayContaining (component.getScreenBounds().getCentre()).scale;
  153. Rectangle<int> newArea (roundToInt (component.getWidth() * newScale),
  154. roundToInt (component.getHeight() * newScale));
  155. if (scale != newScale || viewportArea != newArea)
  156. {
  157. scale = newScale;
  158. viewportArea = newArea;
  159. if (canTriggerUpdate)
  160. invalidateAll();
  161. }
  162. }
  163. void paintComponent()
  164. {
  165. // you mustn't set your own cached image object when attaching a GL context!
  166. jassert (get (component) == this);
  167. updateViewportSize (false);
  168. if (! ensureFrameBufferSize())
  169. return;
  170. RectangleList<int> invalid (viewportArea);
  171. invalid.subtract (validArea);
  172. validArea = viewportArea;
  173. if (! invalid.isEmpty())
  174. {
  175. clearRegionInFrameBuffer (invalid, (float) scale);
  176. {
  177. ScopedPointer<LowLevelGraphicsContext> g (createOpenGLGraphicsContext (context, cachedImageFrameBuffer));
  178. g->addTransform (AffineTransform::scale ((float) scale));
  179. g->clipToRectangleList (invalid);
  180. paintOwner (*g);
  181. JUCE_CHECK_OPENGL_ERROR
  182. }
  183. if (! context.isActive())
  184. context.makeActive();
  185. }
  186. JUCE_CHECK_OPENGL_ERROR
  187. }
  188. void drawComponentBuffer()
  189. {
  190. #if ! JUCE_ANDROID
  191. glEnable (GL_TEXTURE_2D);
  192. clearGLError();
  193. #endif
  194. context.extensions.glActiveTexture (GL_TEXTURE0);
  195. glBindTexture (GL_TEXTURE_2D, cachedImageFrameBuffer.getTextureID());
  196. const Rectangle<int> cacheBounds (cachedImageFrameBuffer.getWidth(), cachedImageFrameBuffer.getHeight());
  197. context.copyTexture (cacheBounds, cacheBounds, cacheBounds.getWidth(), cacheBounds.getHeight(), false);
  198. glBindTexture (GL_TEXTURE_2D, 0);
  199. JUCE_CHECK_OPENGL_ERROR
  200. }
  201. void paintOwner (LowLevelGraphicsContext& llgc)
  202. {
  203. Graphics g (&llgc);
  204. #if JUCE_ENABLE_REPAINT_DEBUGGING
  205. g.saveState();
  206. #endif
  207. JUCE_TRY
  208. {
  209. component.paintEntireComponent (g, false);
  210. }
  211. JUCE_CATCH_EXCEPTION
  212. #if JUCE_ENABLE_REPAINT_DEBUGGING
  213. // enabling this code will fill all areas that get repainted with a colour overlay, to show
  214. // clearly when things are being repainted.
  215. g.restoreState();
  216. static Random rng;
  217. g.fillAll (Colour ((uint8) rng.nextInt (255),
  218. (uint8) rng.nextInt (255),
  219. (uint8) rng.nextInt (255),
  220. (uint8) 0x50));
  221. #endif
  222. }
  223. void handleResize()
  224. {
  225. updateViewportSize (true);
  226. #if JUCE_MAC
  227. if (hasInitialised)
  228. {
  229. [nativeContext->view update];
  230. renderFrame();
  231. }
  232. #endif
  233. }
  234. //==============================================================================
  235. void run() override
  236. {
  237. {
  238. // Allow the message thread to finish setting-up the context before using it..
  239. MessageManagerLock mml (this);
  240. if (! mml.lockWasGained())
  241. return;
  242. }
  243. initialiseOnThread();
  244. hasInitialised = true;
  245. while (! threadShouldExit())
  246. {
  247. if (! renderFrame())
  248. wait (5); // failed to render, so avoid a tight fail-loop.
  249. }
  250. shutdownOnThread();
  251. }
  252. void initialiseOnThread()
  253. {
  254. // On android, this can get called twice, so drop any previous state..
  255. associatedObjectNames.clear();
  256. associatedObjects.clear();
  257. cachedImageFrameBuffer.release();
  258. context.makeActive();
  259. nativeContext->initialiseOnRenderThread (context);
  260. glViewport (0, 0, component.getWidth(), component.getHeight());
  261. context.extensions.initialise();
  262. nativeContext->setSwapInterval (1);
  263. #if JUCE_USE_OPENGL_SHADERS && ! JUCE_OPENGL_ES
  264. shadersAvailable = OpenGLShaderProgram::getLanguageVersion() > 0;
  265. #endif
  266. if (context.renderer != nullptr)
  267. context.renderer->newOpenGLContextCreated();
  268. }
  269. void shutdownOnThread()
  270. {
  271. if (context.renderer != nullptr)
  272. context.renderer->openGLContextClosing();
  273. cachedImageFrameBuffer.release();
  274. nativeContext->shutdownOnRenderThread();
  275. associatedObjectNames.clear();
  276. associatedObjects.clear();
  277. }
  278. //==============================================================================
  279. static CachedImage* get (Component& c) noexcept
  280. {
  281. return dynamic_cast<CachedImage*> (c.getCachedComponentImage());
  282. }
  283. //==============================================================================
  284. ScopedPointer<NativeContext> nativeContext;
  285. OpenGLContext& context;
  286. Component& component;
  287. OpenGLFrameBuffer cachedImageFrameBuffer;
  288. RectangleList<int> validArea;
  289. Rectangle<int> viewportArea;
  290. double scale;
  291. StringArray associatedObjectNames;
  292. ReferenceCountedArray<ReferenceCountedObject> associatedObjects;
  293. WaitableEvent canPaintNowFlag, finishedPaintingFlag;
  294. bool shadersAvailable, hasInitialised;
  295. Atomic<int> needsUpdate;
  296. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedImage)
  297. };
  298. //==============================================================================
  299. #if JUCE_ANDROID
  300. void OpenGLContext::NativeContext::contextCreatedCallback()
  301. {
  302. isInsideGLCallback = true;
  303. if (CachedImage* const c = CachedImage::get (component))
  304. c->initialiseOnThread();
  305. else
  306. jassertfalse;
  307. isInsideGLCallback = false;
  308. }
  309. void OpenGLContext::NativeContext::renderCallback()
  310. {
  311. isInsideGLCallback = true;
  312. if (CachedImage* const c = CachedImage::get (component))
  313. c->renderFrame();
  314. isInsideGLCallback = false;
  315. }
  316. #endif
  317. //==============================================================================
  318. class OpenGLContext::Attachment : public ComponentMovementWatcher
  319. {
  320. public:
  321. Attachment (OpenGLContext& c, Component& comp)
  322. : ComponentMovementWatcher (&comp), context (c)
  323. {
  324. if (canBeAttached (comp))
  325. attach();
  326. }
  327. ~Attachment()
  328. {
  329. detach();
  330. }
  331. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
  332. {
  333. Component& comp = *getComponent();
  334. if (isAttached (comp) != canBeAttached (comp))
  335. componentVisibilityChanged();
  336. if (comp.getWidth() > 0 && comp.getHeight() > 0
  337. && context.nativeContext != nullptr)
  338. {
  339. if (CachedImage* const c = CachedImage::get (comp))
  340. c->handleResize();
  341. if (ComponentPeer* peer = comp.getTopLevelComponent()->getPeer())
  342. context.nativeContext->updateWindowPosition (peer->getAreaCoveredBy (comp));
  343. }
  344. }
  345. void componentPeerChanged() override
  346. {
  347. detach();
  348. componentVisibilityChanged();
  349. }
  350. void componentVisibilityChanged() override
  351. {
  352. Component& comp = *getComponent();
  353. if (canBeAttached (comp))
  354. {
  355. if (! isAttached (comp))
  356. attach();
  357. }
  358. else
  359. {
  360. detach();
  361. }
  362. }
  363. #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
  364. void componentBeingDeleted (Component& component) override
  365. {
  366. /* You must call detach() or delete your OpenGLContext to remove it
  367. from a component BEFORE deleting the component that it is using!
  368. */
  369. jassertfalse;
  370. ComponentMovementWatcher::componentBeingDeleted (component);
  371. }
  372. #endif
  373. private:
  374. OpenGLContext& context;
  375. static bool canBeAttached (const Component& comp) noexcept
  376. {
  377. return comp.getWidth() > 0 && comp.getHeight() > 0 && isShowingOrMinimised (comp);
  378. }
  379. static bool isShowingOrMinimised (const Component& c)
  380. {
  381. if (! c.isVisible())
  382. return false;
  383. if (Component* p = c.getParentComponent())
  384. return isShowingOrMinimised (*p);
  385. return c.getPeer() != nullptr;
  386. }
  387. static bool isAttached (const Component& comp) noexcept
  388. {
  389. return comp.getCachedComponentImage() != nullptr;
  390. }
  391. void attach()
  392. {
  393. Component& comp = *getComponent();
  394. CachedImage* const newCachedImage = new CachedImage (context, comp,
  395. context.pixelFormat,
  396. context.contextToShareWith);
  397. comp.setCachedComponentImage (newCachedImage);
  398. newCachedImage->start(); // (must wait until this is attached before starting its thread)
  399. newCachedImage->updateViewportSize (true);
  400. }
  401. void detach()
  402. {
  403. Component& comp = *getComponent();
  404. #if JUCE_MAC
  405. [[(NSView*) comp.getWindowHandle() window] disableScreenUpdatesUntilFlush];
  406. #endif
  407. if (CachedImage* const oldCachedImage = CachedImage::get (comp))
  408. oldCachedImage->stop(); // (must stop this before detaching it from the component)
  409. comp.setCachedComponentImage (nullptr);
  410. context.nativeContext = nullptr;
  411. }
  412. };
  413. //==============================================================================
  414. OpenGLContext::OpenGLContext()
  415. : nativeContext (nullptr), renderer (nullptr), contextToShareWith (nullptr),
  416. renderComponents (true), useMultisampling (false)
  417. {
  418. }
  419. OpenGLContext::~OpenGLContext()
  420. {
  421. detach();
  422. }
  423. void OpenGLContext::setRenderer (OpenGLRenderer* rendererToUse) noexcept
  424. {
  425. // This method must not be called when the context has already been attached!
  426. // Call it before attaching your context, or use detach() first, before calling this!
  427. jassert (nativeContext == nullptr);
  428. renderer = rendererToUse;
  429. }
  430. void OpenGLContext::setComponentPaintingEnabled (bool shouldPaintComponent) noexcept
  431. {
  432. // This method must not be called when the context has already been attached!
  433. // Call it before attaching your context, or use detach() first, before calling this!
  434. jassert (nativeContext == nullptr);
  435. renderComponents = shouldPaintComponent;
  436. }
  437. void OpenGLContext::setPixelFormat (const OpenGLPixelFormat& preferredPixelFormat) noexcept
  438. {
  439. // This method must not be called when the context has already been attached!
  440. // Call it before attaching your context, or use detach() first, before calling this!
  441. jassert (nativeContext == nullptr);
  442. pixelFormat = preferredPixelFormat;
  443. }
  444. void OpenGLContext::setNativeSharedContext (void* nativeContextToShareWith) noexcept
  445. {
  446. // This method must not be called when the context has already been attached!
  447. // Call it before attaching your context, or use detach() first, before calling this!
  448. jassert (nativeContext == nullptr);
  449. contextToShareWith = nativeContextToShareWith;
  450. }
  451. void OpenGLContext::setMultisamplingEnabled (bool b) noexcept
  452. {
  453. // This method must not be called when the context has already been attached!
  454. // Call it before attaching your context, or use detach() first, before calling this!
  455. jassert (nativeContext == nullptr);
  456. useMultisampling = b;
  457. }
  458. void OpenGLContext::attachTo (Component& component)
  459. {
  460. component.repaint();
  461. if (getTargetComponent() != &component)
  462. {
  463. detach();
  464. attachment = new Attachment (*this, component);
  465. }
  466. }
  467. void OpenGLContext::detach()
  468. {
  469. attachment = nullptr;
  470. nativeContext = nullptr;
  471. }
  472. bool OpenGLContext::isAttached() const noexcept
  473. {
  474. return nativeContext != nullptr;
  475. }
  476. Component* OpenGLContext::getTargetComponent() const noexcept
  477. {
  478. return attachment != nullptr ? attachment->getComponent() : nullptr;
  479. }
  480. static ThreadLocalValue<OpenGLContext*> currentThreadActiveContext;
  481. OpenGLContext* OpenGLContext::getCurrentContext()
  482. {
  483. return currentThreadActiveContext.get();
  484. }
  485. bool OpenGLContext::makeActive() const noexcept
  486. {
  487. OpenGLContext*& current = currentThreadActiveContext.get();
  488. if (nativeContext != nullptr && nativeContext->makeActive())
  489. {
  490. current = const_cast <OpenGLContext*> (this);
  491. return true;
  492. }
  493. current = nullptr;
  494. return false;
  495. }
  496. bool OpenGLContext::isActive() const noexcept
  497. {
  498. return nativeContext != nullptr && nativeContext->isActive();
  499. }
  500. void OpenGLContext::deactivateCurrentContext()
  501. {
  502. NativeContext::deactivateCurrentContext();
  503. currentThreadActiveContext.get() = nullptr;
  504. }
  505. void OpenGLContext::triggerRepaint()
  506. {
  507. if (CachedImage* const cachedImage = getCachedImage())
  508. cachedImage->triggerRepaint();
  509. }
  510. void OpenGLContext::swapBuffers()
  511. {
  512. if (nativeContext != nullptr)
  513. nativeContext->swapBuffers();
  514. }
  515. unsigned int OpenGLContext::getFrameBufferID() const noexcept
  516. {
  517. return nativeContext != nullptr ? nativeContext->getFrameBufferID() : 0;
  518. }
  519. bool OpenGLContext::setSwapInterval (int numFramesPerSwap)
  520. {
  521. return nativeContext != nullptr && nativeContext->setSwapInterval (numFramesPerSwap);
  522. }
  523. int OpenGLContext::getSwapInterval() const
  524. {
  525. return nativeContext != nullptr ? nativeContext->getSwapInterval() : 0;
  526. }
  527. void* OpenGLContext::getRawContext() const noexcept
  528. {
  529. return nativeContext != nullptr ? nativeContext->getRawContext() : nullptr;
  530. }
  531. OpenGLContext::CachedImage* OpenGLContext::getCachedImage() const noexcept
  532. {
  533. if (Component* const comp = getTargetComponent())
  534. return CachedImage::get (*comp);
  535. return nullptr;
  536. }
  537. bool OpenGLContext::areShadersAvailable() const
  538. {
  539. CachedImage* const c = getCachedImage();
  540. return c != nullptr && c->shadersAvailable;
  541. }
  542. ReferenceCountedObject* OpenGLContext::getAssociatedObject (const char* name) const
  543. {
  544. jassert (name != nullptr);
  545. CachedImage* const c = getCachedImage();
  546. // This method must only be called from an openGL rendering callback.
  547. jassert (c != nullptr && nativeContext != nullptr);
  548. jassert (getCurrentContext() != nullptr);
  549. const int index = c->associatedObjectNames.indexOf (name);
  550. return index >= 0 ? c->associatedObjects.getUnchecked (index) : nullptr;
  551. }
  552. void OpenGLContext::setAssociatedObject (const char* name, ReferenceCountedObject* newObject)
  553. {
  554. jassert (name != nullptr);
  555. CachedImage* const c = getCachedImage();
  556. // This method must only be called from an openGL rendering callback.
  557. jassert (c != nullptr && nativeContext != nullptr);
  558. jassert (getCurrentContext() != nullptr);
  559. const int index = c->associatedObjectNames.indexOf (name);
  560. if (index >= 0)
  561. {
  562. c->associatedObjects.set (index, newObject);
  563. }
  564. else
  565. {
  566. c->associatedObjectNames.add (name);
  567. c->associatedObjects.add (newObject);
  568. }
  569. }
  570. void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea,
  571. const Rectangle<int>& anchorPosAndTextureSize,
  572. const int contextWidth, const int contextHeight,
  573. bool flippedVertically)
  574. {
  575. if (contextWidth <= 0 || contextHeight <= 0)
  576. return;
  577. JUCE_CHECK_OPENGL_ERROR
  578. glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  579. glEnable (GL_BLEND);
  580. #if JUCE_USE_OPENGL_SHADERS
  581. if (areShadersAvailable())
  582. {
  583. struct OverlayShaderProgram : public ReferenceCountedObject
  584. {
  585. OverlayShaderProgram (OpenGLContext& context)
  586. : program (context), builder (program), params (program)
  587. {}
  588. static const OverlayShaderProgram& select (OpenGLContext& context)
  589. {
  590. static const char programValueID[] = "juceGLComponentOverlayShader";
  591. OverlayShaderProgram* program = static_cast <OverlayShaderProgram*> (context.getAssociatedObject (programValueID));
  592. if (program == nullptr)
  593. {
  594. program = new OverlayShaderProgram (context);
  595. context.setAssociatedObject (programValueID, program);
  596. }
  597. program->program.use();
  598. return *program;
  599. }
  600. struct ProgramBuilder
  601. {
  602. ProgramBuilder (OpenGLShaderProgram& prog)
  603. {
  604. prog.addShader ("attribute " JUCE_HIGHP " vec2 position;"
  605. "uniform " JUCE_HIGHP " vec2 screenSize;"
  606. "varying " JUCE_HIGHP " vec2 pixelPos;"
  607. "void main()"
  608. "{"
  609. "pixelPos = position;"
  610. JUCE_HIGHP " vec2 scaled = position / (0.5 * screenSize.xy);"
  611. "gl_Position = vec4 (scaled.x - 1.0, 1.0 - scaled.y, 0, 1.0);"
  612. "}",
  613. GL_VERTEX_SHADER);
  614. prog.addShader ("uniform sampler2D imageTexture;"
  615. "uniform " JUCE_HIGHP " float textureBounds[4];"
  616. "uniform " JUCE_HIGHP " vec2 vOffsetAndScale;"
  617. "varying " JUCE_HIGHP " vec2 pixelPos;"
  618. "void main()"
  619. "{"
  620. JUCE_HIGHP " vec2 texturePos = (pixelPos - vec2 (textureBounds[0], textureBounds[1]))"
  621. "/ vec2 (textureBounds[2], textureBounds[3]);"
  622. "gl_FragColor = texture2D (imageTexture, vec2 (texturePos.x, vOffsetAndScale.x + vOffsetAndScale.y * texturePos.y));"
  623. "}",
  624. GL_FRAGMENT_SHADER);
  625. prog.link();
  626. }
  627. };
  628. struct Params
  629. {
  630. Params (OpenGLShaderProgram& prog)
  631. : positionAttribute (prog, "position"),
  632. screenSize (prog, "screenSize"),
  633. imageTexture (prog, "imageTexture"),
  634. textureBounds (prog, "textureBounds"),
  635. vOffsetAndScale (prog, "vOffsetAndScale")
  636. {}
  637. void set (const float targetWidth, const float targetHeight, const Rectangle<float>& bounds, bool flippedVertically) const
  638. {
  639. const GLfloat m[] = { bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight() };
  640. textureBounds.set (m, 4);
  641. imageTexture.set (0);
  642. screenSize.set (targetWidth, targetHeight);
  643. vOffsetAndScale.set (flippedVertically ? 0.0f : 1.0f,
  644. flippedVertically ? 1.0f : -1.0f);
  645. }
  646. OpenGLShaderProgram::Attribute positionAttribute;
  647. OpenGLShaderProgram::Uniform screenSize, imageTexture, textureBounds, vOffsetAndScale;
  648. };
  649. OpenGLShaderProgram program;
  650. ProgramBuilder builder;
  651. Params params;
  652. };
  653. const GLshort left = (GLshort) targetClipArea.getX();
  654. const GLshort top = (GLshort) targetClipArea.getY();
  655. const GLshort right = (GLshort) targetClipArea.getRight();
  656. const GLshort bottom = (GLshort) targetClipArea.getBottom();
  657. const GLshort vertices[] = { left, bottom, right, bottom, left, top, right, top };
  658. const OverlayShaderProgram& program = OverlayShaderProgram::select (*this);
  659. program.params.set ((float) contextWidth, (float) contextHeight, anchorPosAndTextureSize.toFloat(), flippedVertically);
  660. extensions.glVertexAttribPointer (program.params.positionAttribute.attributeID, 2, GL_SHORT, GL_FALSE, 4, vertices);
  661. extensions.glEnableVertexAttribArray (program.params.positionAttribute.attributeID);
  662. JUCE_CHECK_OPENGL_ERROR
  663. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  664. extensions.glUseProgram (0);
  665. extensions.glDisableVertexAttribArray (program.params.positionAttribute.attributeID);
  666. }
  667. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  668. else
  669. #endif
  670. #endif
  671. #if JUCE_USE_OPENGL_FIXED_FUNCTION
  672. {
  673. glEnable (GL_SCISSOR_TEST);
  674. glScissor (targetClipArea.getX(), contextHeight - targetClipArea.getBottom(),
  675. targetClipArea.getWidth(), targetClipArea.getHeight());
  676. JUCE_CHECK_OPENGL_ERROR
  677. glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
  678. glDisableClientState (GL_COLOR_ARRAY);
  679. glDisableClientState (GL_NORMAL_ARRAY);
  680. glEnableClientState (GL_VERTEX_ARRAY);
  681. glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  682. OpenGLHelpers::prepareFor2D (contextWidth, contextHeight);
  683. JUCE_CHECK_OPENGL_ERROR
  684. const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f };
  685. glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
  686. const GLshort left = (GLshort) anchorPosAndTextureSize.getX();
  687. const GLshort right = (GLshort) anchorPosAndTextureSize.getRight();
  688. const GLshort top = (GLshort) (contextHeight - anchorPosAndTextureSize.getY());
  689. const GLshort bottom = (GLshort) (contextHeight - anchorPosAndTextureSize.getBottom());
  690. const GLshort vertices[] = { left, bottom, right, bottom, left, top, right, top };
  691. glVertexPointer (2, GL_SHORT, 0, vertices);
  692. glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
  693. glDisable (GL_SCISSOR_TEST);
  694. }
  695. #endif
  696. JUCE_CHECK_OPENGL_ERROR
  697. }