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.

438 lines
12KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. OpenGLPixelFormat::OpenGLPixelFormat (const int bitsPerRGBComponent,
  21. const int alphaBits_,
  22. const int depthBufferBits_,
  23. const int stencilBufferBits_)
  24. : redBits (bitsPerRGBComponent),
  25. greenBits (bitsPerRGBComponent),
  26. blueBits (bitsPerRGBComponent),
  27. alphaBits (alphaBits_),
  28. depthBufferBits (depthBufferBits_),
  29. stencilBufferBits (stencilBufferBits_),
  30. accumulationBufferRedBits (0),
  31. accumulationBufferGreenBits (0),
  32. accumulationBufferBlueBits (0),
  33. accumulationBufferAlphaBits (0),
  34. fullSceneAntiAliasingNumSamples (0)
  35. {
  36. }
  37. OpenGLPixelFormat::OpenGLPixelFormat (const OpenGLPixelFormat& other)
  38. : redBits (other.redBits),
  39. greenBits (other.greenBits),
  40. blueBits (other.blueBits),
  41. alphaBits (other.alphaBits),
  42. depthBufferBits (other.depthBufferBits),
  43. stencilBufferBits (other.stencilBufferBits),
  44. accumulationBufferRedBits (other.accumulationBufferRedBits),
  45. accumulationBufferGreenBits (other.accumulationBufferGreenBits),
  46. accumulationBufferBlueBits (other.accumulationBufferBlueBits),
  47. accumulationBufferAlphaBits (other.accumulationBufferAlphaBits),
  48. fullSceneAntiAliasingNumSamples (other.fullSceneAntiAliasingNumSamples)
  49. {
  50. }
  51. OpenGLPixelFormat& OpenGLPixelFormat::operator= (const OpenGLPixelFormat& other)
  52. {
  53. redBits = other.redBits;
  54. greenBits = other.greenBits;
  55. blueBits = other.blueBits;
  56. alphaBits = other.alphaBits;
  57. depthBufferBits = other.depthBufferBits;
  58. stencilBufferBits = other.stencilBufferBits;
  59. accumulationBufferRedBits = other.accumulationBufferRedBits;
  60. accumulationBufferGreenBits = other.accumulationBufferGreenBits;
  61. accumulationBufferBlueBits = other.accumulationBufferBlueBits;
  62. accumulationBufferAlphaBits = other.accumulationBufferAlphaBits;
  63. fullSceneAntiAliasingNumSamples = other.fullSceneAntiAliasingNumSamples;
  64. return *this;
  65. }
  66. bool OpenGLPixelFormat::operator== (const OpenGLPixelFormat& other) const
  67. {
  68. return redBits == other.redBits
  69. && greenBits == other.greenBits
  70. && blueBits == other.blueBits
  71. && alphaBits == other.alphaBits
  72. && depthBufferBits == other.depthBufferBits
  73. && stencilBufferBits == other.stencilBufferBits
  74. && accumulationBufferRedBits == other.accumulationBufferRedBits
  75. && accumulationBufferGreenBits == other.accumulationBufferGreenBits
  76. && accumulationBufferBlueBits == other.accumulationBufferBlueBits
  77. && accumulationBufferAlphaBits == other.accumulationBufferAlphaBits
  78. && fullSceneAntiAliasingNumSamples == other.fullSceneAntiAliasingNumSamples;
  79. }
  80. //==============================================================================
  81. static Array<OpenGLContext*> knownContexts;
  82. OpenGLContext::OpenGLContext() noexcept
  83. {
  84. knownContexts.add (this);
  85. }
  86. OpenGLContext::~OpenGLContext()
  87. {
  88. knownContexts.removeValue (this);
  89. }
  90. OpenGLContext* OpenGLContext::getCurrentContext()
  91. {
  92. for (int i = knownContexts.size(); --i >= 0;)
  93. {
  94. OpenGLContext* const oglc = knownContexts.getUnchecked(i);
  95. if (oglc->isActive())
  96. return oglc;
  97. }
  98. return nullptr;
  99. }
  100. //==============================================================================
  101. class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher
  102. {
  103. public:
  104. OpenGLComponentWatcher (OpenGLComponent* const owner_)
  105. : ComponentMovementWatcher (owner_),
  106. owner (owner_)
  107. {
  108. }
  109. //==============================================================================
  110. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  111. {
  112. owner->updateContextPosition();
  113. }
  114. void componentPeerChanged()
  115. {
  116. owner->recreateContextAsync();
  117. }
  118. void componentVisibilityChanged()
  119. {
  120. if (! owner->isShowing())
  121. owner->stopBackgroundThread();
  122. }
  123. private:
  124. OpenGLComponent* const owner;
  125. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher);
  126. };
  127. //==============================================================================
  128. class OpenGLComponent::OpenGLComponentRenderThread : public Thread
  129. {
  130. public:
  131. OpenGLComponentRenderThread (OpenGLComponent& owner_)
  132. : Thread ("OpenGL Render"),
  133. owner (owner_)
  134. {
  135. }
  136. void run()
  137. {
  138. #if JUCE_LINUX
  139. {
  140. MessageManagerLock mml (this);
  141. if (! mml.lockWasGained())
  142. return;
  143. owner.updateContext();
  144. owner.updateContextPosition();
  145. }
  146. #endif
  147. while (! threadShouldExit())
  148. {
  149. const uint32 startOfRendering = Time::getMillisecondCounter();
  150. if (! owner.renderAndSwapBuffers())
  151. break;
  152. const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering);
  153. Thread::sleep (jmax (1, 20 - elapsed));
  154. }
  155. #if JUCE_LINUX
  156. owner.deleteContext();
  157. #endif
  158. }
  159. private:
  160. OpenGLComponent& owner;
  161. JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread);
  162. };
  163. void OpenGLComponent::startRenderThread()
  164. {
  165. if (renderThread == nullptr)
  166. renderThread = new OpenGLComponentRenderThread (*this);
  167. renderThread->startThread (6);
  168. }
  169. void OpenGLComponent::stopRenderThread()
  170. {
  171. if (renderThread != nullptr)
  172. {
  173. renderThread->stopThread (5000);
  174. renderThread = nullptr;
  175. }
  176. #if ! JUCE_LINUX
  177. deleteContext();
  178. #endif
  179. }
  180. //==============================================================================
  181. OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread)
  182. : type (type_),
  183. contextToShareListsWith (nullptr),
  184. needToUpdateViewport (true),
  185. needToDeleteContext (false),
  186. threadStarted (false),
  187. useThread (useBackgroundThread)
  188. {
  189. setOpaque (true);
  190. componentWatcher = new OpenGLComponentWatcher (this);
  191. }
  192. OpenGLComponent::~OpenGLComponent()
  193. {
  194. stopBackgroundThread();
  195. componentWatcher = nullptr;
  196. }
  197. OpenGLPixelFormat OpenGLComponent::getPixelFormat() const
  198. {
  199. OpenGLPixelFormat pf;
  200. const ScopedLock sl (contextLock);
  201. if (context != nullptr)
  202. pf = context->getPixelFormat();
  203. return pf;
  204. }
  205. void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse)
  206. {
  207. if (! (preferredPixelFormat == formatToUse))
  208. {
  209. const ScopedLock sl (contextLock);
  210. preferredPixelFormat = formatToUse;
  211. recreateContextAsync();
  212. }
  213. }
  214. void OpenGLComponent::shareWith (OpenGLContext* c)
  215. {
  216. if (contextToShareListsWith != c)
  217. {
  218. const ScopedLock sl (contextLock);
  219. contextToShareListsWith = c;
  220. recreateContextAsync();
  221. }
  222. }
  223. void OpenGLComponent::recreateContextAsync()
  224. {
  225. const ScopedLock sl (contextLock);
  226. needToDeleteContext = true;
  227. repaint();
  228. }
  229. bool OpenGLComponent::makeCurrentRenderingTarget()
  230. {
  231. return context != nullptr && context->makeActive();
  232. }
  233. void OpenGLComponent::releaseAsRenderingTarget()
  234. {
  235. if (context != nullptr)
  236. context->makeInactive();
  237. }
  238. void OpenGLComponent::swapBuffers()
  239. {
  240. if (context != nullptr)
  241. context->swapBuffers();
  242. }
  243. void OpenGLComponent::updateContext()
  244. {
  245. if (needToDeleteContext)
  246. deleteContext();
  247. if (context == nullptr)
  248. {
  249. const ScopedLock sl (contextLock);
  250. if (context == nullptr)
  251. {
  252. context = createContext();
  253. if (context != nullptr)
  254. {
  255. #if JUCE_LINUX
  256. if (! useThread)
  257. #endif
  258. updateContextPosition();
  259. if (context->makeActive())
  260. {
  261. newOpenGLContextCreated();
  262. context->makeInactive();
  263. }
  264. }
  265. }
  266. }
  267. }
  268. void OpenGLComponent::deleteContext()
  269. {
  270. const ScopedLock sl (contextLock);
  271. if (context != nullptr)
  272. {
  273. if (context->makeActive())
  274. {
  275. releaseOpenGLContext();
  276. context->makeInactive();
  277. }
  278. context = nullptr;
  279. }
  280. needToDeleteContext = false;
  281. }
  282. void OpenGLComponent::updateContextPosition()
  283. {
  284. needToUpdateViewport = true;
  285. if (getWidth() > 0 && getHeight() > 0)
  286. {
  287. Component* const topComp = getTopLevelComponent();
  288. if (topComp->getPeer() != nullptr)
  289. {
  290. const ScopedLock sl (contextLock);
  291. if (context != nullptr)
  292. context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
  293. }
  294. }
  295. }
  296. void OpenGLComponent::stopBackgroundThread()
  297. {
  298. if (threadStarted)
  299. {
  300. stopRenderThread();
  301. threadStarted = false;
  302. }
  303. }
  304. void OpenGLComponent::paint (Graphics&)
  305. {
  306. ComponentPeer* const peer = getPeer();
  307. if (useThread)
  308. {
  309. if (peer != nullptr && isShowing())
  310. {
  311. #if ! JUCE_LINUX
  312. updateContext();
  313. #endif
  314. if (! threadStarted)
  315. {
  316. threadStarted = true;
  317. startRenderThread();
  318. }
  319. }
  320. }
  321. else
  322. {
  323. updateContext();
  324. if (! renderAndSwapBuffers())
  325. return;
  326. }
  327. if (peer != nullptr)
  328. {
  329. const Point<int> topLeft (getScreenPosition() - peer->getScreenPosition());
  330. peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight());
  331. }
  332. }
  333. bool OpenGLComponent::renderAndSwapBuffers()
  334. {
  335. const ScopedLock sl (contextLock);
  336. #if JUCE_LINUX
  337. updateContext();
  338. #endif
  339. if (context != nullptr)
  340. {
  341. if (! makeCurrentRenderingTarget())
  342. return false;
  343. if (needToUpdateViewport)
  344. {
  345. needToUpdateViewport = false;
  346. glViewport (0, 0, getWidth(), getHeight());
  347. }
  348. renderOpenGL();
  349. swapBuffers();
  350. }
  351. return true;
  352. }
  353. void OpenGLComponent::internalRepaint (int x, int y, int w, int h)
  354. {
  355. Component::internalRepaint (x, y, w, h);
  356. if (context != nullptr)
  357. context->repaint();
  358. }
  359. END_JUCE_NAMESPACE