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.

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