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.

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