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.

850 lines
27KB

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