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.

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