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
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"
38 #include "OgreRenderSystem.h"
42 RenderTarget::RenderTarget()
43 :mPriority(OGRE_DEFAULT_RT_GROUP
),
49 mTimer
= Root::getSingleton().getTimer();
53 RenderTarget::~RenderTarget()
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
79 void RenderTarget::getMetrics(unsigned int& width
, unsigned int& height
, unsigned int& colourDepth
)
83 colourDepth
= mColourDepth
;
86 unsigned int RenderTarget::getWidth(void) const
90 unsigned int RenderTarget::getHeight(void) const
94 unsigned int RenderTarget::getColourDepth(void) const
99 void RenderTarget::updateImpl(void)
102 // notify listeners (pre)
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
);
120 // notify listeners (post)
123 // Update statistics (always on top)
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
);
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
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)
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
;
251 void RenderTarget::updateStats(void)
254 unsigned long thisTime
= mTimer
->getMilliseconds();
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
;
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
;
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
)
307 //-----------------------------------------------------------------------
308 void RenderTarget::removeAllListeners(void)
312 //-----------------------------------------------------------------------
313 void RenderTarget::firePreUpdate(void)
315 RenderTargetEvent evt
;
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
;
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();
358 //-----------------------------------------------------------------------
359 bool RenderTarget::isActive() const
363 //-----------------------------------------------------------------------
364 void RenderTarget::setActive( bool state
)
368 //-----------------------------------------------------------------------
369 void RenderTarget::fireViewportPreUpdate(Viewport
* vp
)
371 RenderTargetViewportEvent evt
;
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
;
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
;
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
;
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
)
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
);
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
476 //-----------------------------------------------------------------------
477 void RenderTarget::setAutoUpdated(bool autoup
)
479 mAutoUpdate
= autoup
;
481 //-----------------------------------------------------------------------
482 bool RenderTarget::isAutoUpdated(void) const
486 //-----------------------------------------------------------------------
487 bool RenderTarget::isPrimary(void) const
489 // RenderWindow will override and return true for the primary window
492 //-----------------------------------------------------------------------
493 RenderTarget::Impl
*RenderTarget::_getImpl()
497 //-----------------------------------------------------------------------
498 void RenderTarget::update(bool swap
)
500 // call implementation
507 swapBuffers(Root::getSingleton().getRenderSystem()->getWaitForVerticalBlank());