2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
32 #include "juce_OpenGLComponent.h"
33 #include "../windows/juce_ComponentPeer.h"
34 #include "../layout/juce_ComponentMovementWatcher.h"
35 #include "../../../threads/juce_Thread.h"
38 //==============================================================================
39 extern void juce_glViewport (const int w
, const int h
);
42 //==============================================================================
43 OpenGLPixelFormat::OpenGLPixelFormat (const int bitsPerRGBComponent
,
45 const int depthBufferBits_
,
46 const int stencilBufferBits_
)
47 : redBits (bitsPerRGBComponent
),
48 greenBits (bitsPerRGBComponent
),
49 blueBits (bitsPerRGBComponent
),
50 alphaBits (alphaBits_
),
51 depthBufferBits (depthBufferBits_
),
52 stencilBufferBits (stencilBufferBits_
),
53 accumulationBufferRedBits (0),
54 accumulationBufferGreenBits (0),
55 accumulationBufferBlueBits (0),
56 accumulationBufferAlphaBits (0),
57 fullSceneAntiAliasingNumSamples (0)
61 OpenGLPixelFormat::OpenGLPixelFormat (const OpenGLPixelFormat
& other
)
62 : redBits (other
.redBits
),
63 greenBits (other
.greenBits
),
64 blueBits (other
.blueBits
),
65 alphaBits (other
.alphaBits
),
66 depthBufferBits (other
.depthBufferBits
),
67 stencilBufferBits (other
.stencilBufferBits
),
68 accumulationBufferRedBits (other
.accumulationBufferRedBits
),
69 accumulationBufferGreenBits (other
.accumulationBufferGreenBits
),
70 accumulationBufferBlueBits (other
.accumulationBufferBlueBits
),
71 accumulationBufferAlphaBits (other
.accumulationBufferAlphaBits
),
72 fullSceneAntiAliasingNumSamples (other
.fullSceneAntiAliasingNumSamples
)
76 OpenGLPixelFormat
& OpenGLPixelFormat::operator= (const OpenGLPixelFormat
& other
)
78 redBits
= other
.redBits
;
79 greenBits
= other
.greenBits
;
80 blueBits
= other
.blueBits
;
81 alphaBits
= other
.alphaBits
;
82 depthBufferBits
= other
.depthBufferBits
;
83 stencilBufferBits
= other
.stencilBufferBits
;
84 accumulationBufferRedBits
= other
.accumulationBufferRedBits
;
85 accumulationBufferGreenBits
= other
.accumulationBufferGreenBits
;
86 accumulationBufferBlueBits
= other
.accumulationBufferBlueBits
;
87 accumulationBufferAlphaBits
= other
.accumulationBufferAlphaBits
;
88 fullSceneAntiAliasingNumSamples
= other
.fullSceneAntiAliasingNumSamples
;
92 bool OpenGLPixelFormat::operator== (const OpenGLPixelFormat
& other
) const
94 return redBits
== other
.redBits
95 && greenBits
== other
.greenBits
96 && blueBits
== other
.blueBits
97 && alphaBits
== other
.alphaBits
98 && depthBufferBits
== other
.depthBufferBits
99 && stencilBufferBits
== other
.stencilBufferBits
100 && accumulationBufferRedBits
== other
.accumulationBufferRedBits
101 && accumulationBufferGreenBits
== other
.accumulationBufferGreenBits
102 && accumulationBufferBlueBits
== other
.accumulationBufferBlueBits
103 && accumulationBufferAlphaBits
== other
.accumulationBufferAlphaBits
104 && fullSceneAntiAliasingNumSamples
== other
.fullSceneAntiAliasingNumSamples
;
107 //==============================================================================
108 static Array
<OpenGLContext
*> knownContexts
;
110 OpenGLContext::OpenGLContext() noexcept
112 knownContexts
.add (this);
115 OpenGLContext::~OpenGLContext()
117 knownContexts
.removeValue (this);
120 OpenGLContext
* OpenGLContext::getCurrentContext()
122 for (int i
= knownContexts
.size(); --i
>= 0;)
124 OpenGLContext
* const oglc
= knownContexts
.getUnchecked(i
);
126 if (oglc
->isActive())
133 //==============================================================================
134 class OpenGLComponent::OpenGLComponentWatcher
: public ComponentMovementWatcher
137 //==============================================================================
138 OpenGLComponentWatcher (OpenGLComponent
* const owner_
)
139 : ComponentMovementWatcher (owner_
),
144 //==============================================================================
145 void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
147 owner
->updateContextPosition();
150 void componentPeerChanged()
152 owner
->recreateContextAsync();
155 void componentVisibilityChanged()
157 if (! owner
->isShowing())
158 owner
->stopBackgroundThread();
161 //==============================================================================
163 OpenGLComponent
* const owner
;
165 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher
);
168 //==============================================================================
169 class OpenGLComponent::OpenGLComponentRenderThread
: public Thread
172 OpenGLComponentRenderThread (OpenGLComponent
& owner_
)
173 : Thread ("OpenGL Render"),
180 while (! threadShouldExit())
182 const uint32 startOfRendering
= Time::getMillisecondCounter();
184 if (! owner
.renderAndSwapBuffers())
187 const int elapsed
= Time::getMillisecondCounter() - startOfRendering
;
188 Thread::sleep (jmax (1, 20 - elapsed
));
192 owner
.deleteContext();
197 OpenGLComponent
& owner
;
199 JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread
);
202 void OpenGLComponent::startRenderThread()
204 if (renderThread
== nullptr)
205 renderThread
= new OpenGLComponentRenderThread (*this);
207 renderThread
->startThread (6);
210 void OpenGLComponent::stopRenderThread()
212 if (renderThread
!= nullptr)
214 renderThread
->stopThread (5000);
215 renderThread
= nullptr;
223 //==============================================================================
224 OpenGLComponent::OpenGLComponent (const OpenGLType type_
, const bool useBackgroundThread
)
226 contextToShareListsWith (nullptr),
227 needToUpdateViewport (true),
228 needToDeleteContext (false),
229 threadStarted (false),
230 useThread (useBackgroundThread
)
233 componentWatcher
= new OpenGLComponentWatcher (this);
236 OpenGLComponent::~OpenGLComponent()
238 stopBackgroundThread();
239 componentWatcher
= nullptr;
242 const OpenGLPixelFormat
OpenGLComponent::getPixelFormat() const
244 OpenGLPixelFormat pf
;
246 const ScopedLock
sl (contextLock
);
247 if (context
!= nullptr)
248 pf
= context
->getPixelFormat();
253 void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat
& formatToUse
)
255 if (! (preferredPixelFormat
== formatToUse
))
257 const ScopedLock
sl (contextLock
);
258 preferredPixelFormat
= formatToUse
;
259 recreateContextAsync();
263 void OpenGLComponent::shareWith (OpenGLContext
* c
)
265 if (contextToShareListsWith
!= c
)
267 const ScopedLock
sl (contextLock
);
268 contextToShareListsWith
= c
;
269 recreateContextAsync();
273 void OpenGLComponent::recreateContextAsync()
275 const ScopedLock
sl (contextLock
);
276 needToDeleteContext
= true;
280 bool OpenGLComponent::makeCurrentContextActive()
282 return context
!= nullptr && context
->makeActive();
285 void OpenGLComponent::makeCurrentContextInactive()
287 if (context
!= nullptr)
288 context
->makeInactive();
291 bool OpenGLComponent::isActiveContext() const noexcept
293 return context
!= nullptr && context
->isActive();
296 void OpenGLComponent::swapBuffers()
298 if (context
!= nullptr)
299 context
->swapBuffers();
302 void OpenGLComponent::updateContext()
304 if (needToDeleteContext
)
307 if (context
== nullptr)
309 const ScopedLock
sl (contextLock
);
311 if (context
== nullptr)
313 context
= createContext();
315 if (context
!= nullptr)
320 updateContextPosition();
322 if (context
->makeActive())
324 newOpenGLContextCreated();
325 context
->makeInactive();
332 void OpenGLComponent::deleteContext()
334 const ScopedLock
sl (contextLock
);
335 if (context
!= nullptr)
337 if (context
->makeActive())
339 releaseOpenGLContext();
340 context
->makeInactive();
346 needToDeleteContext
= false;
349 void OpenGLComponent::updateContextPosition()
351 needToUpdateViewport
= true;
353 if (getWidth() > 0 && getHeight() > 0)
355 Component
* const topComp
= getTopLevelComponent();
357 if (topComp
->getPeer() != nullptr)
359 const ScopedLock
sl (contextLock
);
361 if (context
!= nullptr)
362 context
->updateWindowPosition (topComp
->getLocalArea (this, getLocalBounds()));
367 void OpenGLComponent::stopBackgroundThread()
372 threadStarted
= false;
376 void OpenGLComponent::paint (Graphics
&)
378 ComponentPeer
* const peer
= getPeer();
382 if (peer
!= nullptr && isShowing())
390 threadStarted
= true;
399 if (! renderAndSwapBuffers())
405 const Point
<int> topLeft (getScreenPosition() - peer
->getScreenPosition());
406 peer
->addMaskedRegion (topLeft
.getX(), topLeft
.getY(), getWidth(), getHeight());
410 bool OpenGLComponent::renderAndSwapBuffers()
412 const ScopedLock
sl (contextLock
);
418 if (context
!= nullptr)
420 if (! makeCurrentContextActive())
423 if (needToUpdateViewport
)
425 needToUpdateViewport
= false;
426 juce_glViewport (getWidth(), getHeight());
436 void OpenGLComponent::internalRepaint (int x
, int y
, int w
, int h
)
438 Component::internalRepaint (x
, y
, w
, h
);
440 if (context
!= nullptr)