Patch 2793067: fix trunk with OGRE_THREAD_SUPPORT=1 on non-Windows platforms (don...
[ogre3d.git] / OgreMain / src / OgreRenderTarget.cpp
blob4a272495814175cdf6d838576ec61907f7a0dfcf
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
7 Copyright (c) 2000-2006 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
29 #include "OgreStableHeaders.h"
30 #include "OgreRenderTarget.h"
31 #include "OgreStringConverter.h"
33 #include "OgreViewport.h"
34 #include "OgreException.h"
35 #include "OgreLogManager.h"
36 #include "OgreRenderTargetListener.h"
37 #include "OgreRoot.h"
38 #include "OgreRenderSystem.h"
40 namespace Ogre {
42 RenderTarget::RenderTarget()
43 :mPriority(OGRE_DEFAULT_RT_GROUP),
44 mActive(true),
45 mAutoUpdate(true),
46 mHwGamma(false),
47 mFSAA(0)
49 mTimer = Root::getSingleton().getTimer();
50 resetStatistics();
53 RenderTarget::~RenderTarget()
55 // Delete viewports
56 for (ViewportList::iterator i = mViewportList.begin();
57 i != mViewportList.end(); ++i)
59 fireViewportRemoved(i->second);
60 OGRE_DELETE (*i).second;
64 // Write closing message
65 LogManager::getSingleton().stream(LML_TRIVIAL)
66 << "Render Target '" << mName << "' "
67 << "Average FPS: " << mStats.avgFPS << " "
68 << "Best FPS: " << mStats.bestFPS << " "
69 << "Worst FPS: " << mStats.worstFPS;
73 const String& RenderTarget::getName(void) const
75 return mName;
79 void RenderTarget::getMetrics(unsigned int& width, unsigned int& height, unsigned int& colourDepth)
81 width = mWidth;
82 height = mHeight;
83 colourDepth = mColourDepth;
86 unsigned int RenderTarget::getWidth(void) const
88 return mWidth;
90 unsigned int RenderTarget::getHeight(void) const
92 return mHeight;
94 unsigned int RenderTarget::getColourDepth(void) const
96 return mColourDepth;
99 void RenderTarget::updateImpl(void)
102 // notify listeners (pre)
103 firePreUpdate();
105 mStats.triangleCount = 0;
106 mStats.batchCount = 0;
107 // Go through viewports in Z-order
108 // Tell each to refresh
109 ViewportList::iterator it = mViewportList.begin();
110 while (it != mViewportList.end())
112 fireViewportPreUpdate((*it).second);
113 (*it).second->update();
114 mStats.triangleCount += (*it).second->_getNumRenderedFaces();
115 mStats.batchCount += (*it).second->_getNumRenderedBatches();
116 fireViewportPostUpdate((*it).second);
117 ++it;
120 // notify listeners (post)
121 firePostUpdate();
123 // Update statistics (always on top)
124 updateStats();
129 Viewport* RenderTarget::addViewport(Camera* cam, int ZOrder, float left, float top ,
130 float width , float height)
132 // Check no existing viewport with this Z-order
133 ViewportList::iterator it = mViewportList.find(ZOrder);
135 if (it != mViewportList.end())
137 StringUtil::StrStreamType str;
138 str << "Can't create another viewport for "
139 << mName << " with Z-Order " << ZOrder
140 << " because a viewport exists with this Z-Order already.";
141 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, str.str(), "RenderTarget::addViewport");
143 // Add viewport to list
144 // Order based on Z-Order
145 Viewport* vp = OGRE_NEW Viewport(cam, this, left, top, width, height, ZOrder);
147 mViewportList.insert(ViewportList::value_type(ZOrder, vp));
149 fireViewportAdded(vp);
151 return vp;
153 //-----------------------------------------------------------------------
154 void RenderTarget::removeViewport(int ZOrder)
156 ViewportList::iterator it = mViewportList.find(ZOrder);
158 if (it != mViewportList.end())
160 fireViewportRemoved((*it).second);
161 OGRE_DELETE (*it).second;
162 mViewportList.erase(ZOrder);
166 void RenderTarget::removeAllViewports(void)
170 for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
172 fireViewportRemoved(it->second);
173 OGRE_DELETE (*it).second;
176 mViewportList.clear();
180 void RenderTarget::getStatistics(float& lastFPS, float& avgFPS,
181 float& bestFPS, float& worstFPS) const
184 // Note - the will have been updated by the last render
185 lastFPS = mStats.lastFPS;
186 avgFPS = mStats.avgFPS;
187 bestFPS = mStats.bestFPS;
188 worstFPS = mStats.worstFPS;
193 const RenderTarget::FrameStats& RenderTarget::getStatistics(void) const
195 return mStats;
198 float RenderTarget::getLastFPS() const
200 return mStats.lastFPS;
202 float RenderTarget::getAverageFPS() const
204 return mStats.avgFPS;
206 float RenderTarget::getBestFPS() const
208 return mStats.bestFPS;
210 float RenderTarget::getWorstFPS() const
212 return mStats.worstFPS;
215 size_t RenderTarget::getTriangleCount(void) const
217 return mStats.triangleCount;
220 size_t RenderTarget::getBatchCount(void) const
222 return mStats.batchCount;
225 float RenderTarget::getBestFrameTime() const
227 return mStats.bestFrameTime;
230 float RenderTarget::getWorstFrameTime() const
232 return mStats.worstFrameTime;
235 void RenderTarget::resetStatistics(void)
237 mStats.avgFPS = 0.0;
238 mStats.bestFPS = 0.0;
239 mStats.lastFPS = 0.0;
240 mStats.worstFPS = 999.0;
241 mStats.triangleCount = 0;
242 mStats.batchCount = 0;
243 mStats.bestFrameTime = 999999;
244 mStats.worstFrameTime = 0;
246 mLastTime = mTimer->getMilliseconds();
247 mLastSecond = mLastTime;
248 mFrameCount = 0;
251 void RenderTarget::updateStats(void)
253 ++mFrameCount;
254 unsigned long thisTime = mTimer->getMilliseconds();
256 // check frame time
257 unsigned long frameTime = thisTime - mLastTime ;
258 mLastTime = thisTime ;
260 mStats.bestFrameTime = std::min(mStats.bestFrameTime, frameTime);
261 mStats.worstFrameTime = std::max(mStats.worstFrameTime, frameTime);
263 // check if new second (update only once per second)
264 if (thisTime - mLastSecond > 1000)
266 // new second - not 100% precise
267 mStats.lastFPS = (float)mFrameCount / (float)(thisTime - mLastSecond) * 1000.0;
269 if (mStats.avgFPS == 0)
270 mStats.avgFPS = mStats.lastFPS;
271 else
272 mStats.avgFPS = (mStats.avgFPS + mStats.lastFPS) / 2; // not strictly correct, but good enough
274 mStats.bestFPS = std::max(mStats.bestFPS, mStats.lastFPS);
275 mStats.worstFPS = std::min(mStats.worstFPS, mStats.lastFPS);
277 mLastSecond = thisTime ;
278 mFrameCount = 0;
284 void RenderTarget::getCustomAttribute(const String& name, void* pData)
286 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Attribute not found.", "RenderTarget::getCustomAttribute");
288 //-----------------------------------------------------------------------
289 void RenderTarget::addListener(RenderTargetListener* listener)
291 mListeners.push_back(listener);
293 //-----------------------------------------------------------------------
294 void RenderTarget::removeListener(RenderTargetListener* listener)
296 RenderTargetListenerList::iterator i;
297 for (i = mListeners.begin(); i != mListeners.end(); ++i)
299 if (*i == listener)
301 mListeners.erase(i);
302 break;
307 //-----------------------------------------------------------------------
308 void RenderTarget::removeAllListeners(void)
310 mListeners.clear();
312 //-----------------------------------------------------------------------
313 void RenderTarget::firePreUpdate(void)
315 RenderTargetEvent evt;
316 evt.source = this;
318 RenderTargetListenerList::iterator i, iend;
319 i = mListeners.begin();
320 iend = mListeners.end();
321 for(; i != iend; ++i)
323 (*i)->preRenderTargetUpdate(evt);
328 //-----------------------------------------------------------------------
329 void RenderTarget::firePostUpdate(void)
331 RenderTargetEvent evt;
332 evt.source = this;
334 RenderTargetListenerList::iterator i, iend;
335 i = mListeners.begin();
336 iend = mListeners.end();
337 for(; i != iend; ++i)
339 (*i)->postRenderTargetUpdate(evt);
342 //-----------------------------------------------------------------------
343 unsigned short RenderTarget::getNumViewports(void) const
345 return (unsigned short)mViewportList.size();
348 //-----------------------------------------------------------------------
349 Viewport* RenderTarget::getViewport(unsigned short index)
351 assert (index < mViewportList.size() && "Index out of bounds");
353 ViewportList::iterator i = mViewportList.begin();
354 while (index--)
355 ++i;
356 return i->second;
358 //-----------------------------------------------------------------------
359 bool RenderTarget::isActive() const
361 return mActive;
363 //-----------------------------------------------------------------------
364 void RenderTarget::setActive( bool state )
366 mActive = state;
368 //-----------------------------------------------------------------------
369 void RenderTarget::fireViewportPreUpdate(Viewport* vp)
371 RenderTargetViewportEvent evt;
372 evt.source = vp;
374 RenderTargetListenerList::iterator i, iend;
375 i = mListeners.begin();
376 iend = mListeners.end();
377 for(; i != iend; ++i)
379 (*i)->preViewportUpdate(evt);
382 //-----------------------------------------------------------------------
383 void RenderTarget::fireViewportPostUpdate(Viewport* vp)
385 RenderTargetViewportEvent evt;
386 evt.source = vp;
388 RenderTargetListenerList::iterator i, iend;
389 i = mListeners.begin();
390 iend = mListeners.end();
391 for(; i != iend; ++i)
393 (*i)->postViewportUpdate(evt);
396 //-----------------------------------------------------------------------
397 void RenderTarget::fireViewportAdded(Viewport* vp)
399 RenderTargetViewportEvent evt;
400 evt.source = vp;
402 RenderTargetListenerList::iterator i, iend;
403 i = mListeners.begin();
404 iend = mListeners.end();
405 for(; i != iend; ++i)
407 (*i)->viewportAdded(evt);
410 //-----------------------------------------------------------------------
411 void RenderTarget::fireViewportRemoved(Viewport* vp)
413 RenderTargetViewportEvent evt;
414 evt.source = vp;
416 // Make a temp copy of the listeners
417 // some will want to remove themselves as listeners when they get this
418 RenderTargetListenerList tempList = mListeners;
420 RenderTargetListenerList::iterator i, iend;
421 i = tempList.begin();
422 iend = tempList.end();
423 for(; i != iend; ++i)
425 (*i)->viewportRemoved(evt);
428 //-----------------------------------------------------------------------
429 String RenderTarget::writeContentsToTimestampedFile(const String& filenamePrefix, const String& filenameSuffix)
431 struct tm *pTime;
432 time_t ctTime; time(&ctTime);
433 pTime = localtime( &ctTime );
434 Ogre::StringStream oss;
435 oss << std::setw(2) << std::setfill('0') << (pTime->tm_mon + 1)
436 << std::setw(2) << std::setfill('0') << pTime->tm_mday
437 << std::setw(2) << std::setfill('0') << (pTime->tm_year + 1900)
438 << "_" << std::setw(2) << std::setfill('0') << pTime->tm_hour
439 << std::setw(2) << std::setfill('0') << pTime->tm_min
440 << std::setw(2) << std::setfill('0') << pTime->tm_sec
441 << std::setw(3) << std::setfill('0') << (mTimer->getMilliseconds() % 1000);
442 String filename = filenamePrefix + oss.str() + filenameSuffix;
443 writeContentsToFile(filename);
444 return filename;
447 //-----------------------------------------------------------------------
448 void RenderTarget::writeContentsToFile(const String& filename)
450 PixelFormat pf = suggestPixelFormat();
452 uchar *data = OGRE_ALLOC_T(uchar, mWidth * mHeight * PixelUtil::getNumElemBytes(pf), MEMCATEGORY_RENDERSYS);
453 PixelBox pb(mWidth, mHeight, 1, pf, data);
455 copyContentsToMemory(pb);
457 Image().loadDynamicImage(data, mWidth, mHeight, 1, pf, false, 1, 0).save(filename);
459 OGRE_FREE(data, MEMCATEGORY_RENDERSYS);
461 //-----------------------------------------------------------------------
462 void RenderTarget::_notifyCameraRemoved(const Camera* cam)
464 ViewportList::iterator i, iend;
465 iend = mViewportList.end();
466 for (i = mViewportList.begin(); i != iend; ++i)
468 Viewport* v = i->second;
469 if (v->getCamera() == cam)
471 // disable camera link
472 v->setCamera(0);
476 //-----------------------------------------------------------------------
477 void RenderTarget::setAutoUpdated(bool autoup)
479 mAutoUpdate = autoup;
481 //-----------------------------------------------------------------------
482 bool RenderTarget::isAutoUpdated(void) const
484 return mAutoUpdate;
486 //-----------------------------------------------------------------------
487 bool RenderTarget::isPrimary(void) const
489 // RenderWindow will override and return true for the primary window
490 return false;
492 //-----------------------------------------------------------------------
493 RenderTarget::Impl *RenderTarget::_getImpl()
495 return 0;
497 //-----------------------------------------------------------------------
498 void RenderTarget::update(bool swap)
500 // call implementation
501 updateImpl();
504 if (swap)
506 // Swap buffers
507 swapBuffers(Root::getSingleton().getRenderSystem()->getWaitForVerticalBlank());