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/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreStableHeaders.h"
29 #include "OgreRenderTarget.h"
30 #include "OgreStringConverter.h"
31 
32 #include "OgreViewport.h"
33 #include "OgreException.h"
34 #include "OgreLogManager.h"
35 #include "OgreRenderTargetListener.h"
36 #include "OgreRoot.h"
37 #include "OgreRenderSystem.h"
38 #include "OgreDepthBuffer.h"
39 #include "OgreProfiler.h"
40 
41 namespace Ogre {
42 
RenderTarget()43     RenderTarget::RenderTarget()
44 		: mPriority(OGRE_DEFAULT_RT_GROUP)
45 		, mDepthBufferPoolId(DepthBuffer::POOL_DEFAULT)
46 		, mDepthBuffer(0)
47 		, mActive(true)
48 		, mAutoUpdate(true)
49 		, mHwGamma(false)
50 		, mFSAA(0)
51     {
52         mTimer = Root::getSingleton().getTimer();
53         resetStatistics();
54     }
55 
~RenderTarget()56     RenderTarget::~RenderTarget()
57     {
58         // Delete viewports
59         for (ViewportList::iterator i = mViewportList.begin();
60             i != mViewportList.end(); ++i)
61         {
62             fireViewportRemoved(i->second);
63             OGRE_DELETE (*i).second;
64         }
65 
66 		//DepthBuffer keeps track of us, avoid a dangling pointer
67 		detachDepthBuffer();
68 
69 
70         // Write closing message
71 		LogManager::getSingleton().stream(LML_TRIVIAL)
72 			<< "Render Target '" << mName << "' "
73 			<< "Average FPS: " << mStats.avgFPS << " "
74 			<< "Best FPS: " << mStats.bestFPS << " "
75 			<< "Worst FPS: " << mStats.worstFPS;
76 
77     }
78 
getName(void) const79     const String& RenderTarget::getName(void) const
80     {
81         return mName;
82     }
83 
84 
getMetrics(unsigned int & width,unsigned int & height,unsigned int & colourDepth)85     void RenderTarget::getMetrics(unsigned int& width, unsigned int& height, unsigned int& colourDepth)
86     {
87         width = mWidth;
88         height = mHeight;
89         colourDepth = mColourDepth;
90     }
91 
getWidth(void) const92     unsigned int RenderTarget::getWidth(void) const
93     {
94         return mWidth;
95     }
getHeight(void) const96     unsigned int RenderTarget::getHeight(void) const
97     {
98         return mHeight;
99     }
getColourDepth(void) const100     unsigned int RenderTarget::getColourDepth(void) const
101     {
102         return mColourDepth;
103     }
104 	//-----------------------------------------------------------------------
setDepthBufferPool(uint16 poolId)105 	void RenderTarget::setDepthBufferPool( uint16 poolId )
106 	{
107 		if( mDepthBufferPoolId != poolId )
108 		{
109 			mDepthBufferPoolId = poolId;
110 			detachDepthBuffer();
111 		}
112 	}
113 	//-----------------------------------------------------------------------
getDepthBufferPool() const114 	uint16 RenderTarget::getDepthBufferPool() const
115 	{
116 		return mDepthBufferPoolId;
117 	}
118 	//-----------------------------------------------------------------------
getDepthBuffer() const119 	DepthBuffer* RenderTarget::getDepthBuffer() const
120 	{
121 		return mDepthBuffer;
122 	}
123 	//-----------------------------------------------------------------------
attachDepthBuffer(DepthBuffer * depthBuffer)124 	bool RenderTarget::attachDepthBuffer( DepthBuffer *depthBuffer )
125 	{
126 		bool retVal = false;
127 
128 		if( (retVal = depthBuffer->isCompatible( this )) )
129 		{
130 			detachDepthBuffer();
131 			mDepthBuffer = depthBuffer;
132 			mDepthBuffer->_notifyRenderTargetAttached( this );
133 		}
134 
135 		return retVal;
136 	}
137 	//-----------------------------------------------------------------------
detachDepthBuffer()138 	void RenderTarget::detachDepthBuffer()
139 	{
140 		if( mDepthBuffer )
141 		{
142 			mDepthBuffer->_notifyRenderTargetDetached( this );
143 			mDepthBuffer = 0;
144 		}
145 	}
146 	//-----------------------------------------------------------------------
_detachDepthBuffer()147 	void RenderTarget::_detachDepthBuffer()
148 	{
149 		mDepthBuffer = 0;
150 	}
151 
updateImpl(void)152     void RenderTarget::updateImpl(void)
153     {
154 		_beginUpdate();
155 		_updateAutoUpdatedViewports(true);
156 		_endUpdate();
157     }
158 
_beginUpdate()159 	void RenderTarget::_beginUpdate()
160 	{
161 		// notify listeners (pre)
162         firePreUpdate();
163 
164         mStats.triangleCount = 0;
165         mStats.batchCount = 0;
166 	}
167 
_updateAutoUpdatedViewports(bool updateStatistics)168 	void RenderTarget::_updateAutoUpdatedViewports(bool updateStatistics)
169 	{
170 		// Go through viewports in Z-order
171         // Tell each to refresh
172 		ViewportList::iterator it = mViewportList.begin();
173         while (it != mViewportList.end())
174         {
175 			Viewport* viewport = (*it).second;
176 			if(viewport->isAutoUpdated())
177 			{
178 				_updateViewport(viewport,updateStatistics);
179 			}
180 			++it;
181 		}
182 	}
183 
_endUpdate()184 	void RenderTarget::_endUpdate()
185 	{
186 		 // notify listeners (post)
187         firePostUpdate();
188 
189         // Update statistics (always on top)
190         updateStats();
191 	}
192 
_updateViewport(Viewport * viewport,bool updateStatistics)193 	void RenderTarget::_updateViewport(Viewport* viewport, bool updateStatistics)
194 	{
195 		assert(viewport->getTarget() == this &&
196 				"RenderTarget::_updateViewport the requested viewport is "
197 				"not bound to the rendertarget!");
198 
199 		fireViewportPreUpdate(viewport);
200 		viewport->update();
201 		if(updateStatistics)
202 		{
203 			mStats.triangleCount += viewport->_getNumRenderedFaces();
204 			mStats.batchCount += viewport->_getNumRenderedBatches();
205 		}
206 		fireViewportPostUpdate(viewport);
207 	}
208 
_updateViewport(int zorder,bool updateStatistics)209 	void RenderTarget::_updateViewport(int zorder, bool updateStatistics)
210 	{
211 		ViewportList::iterator it = mViewportList.find(zorder);
212         if (it != mViewportList.end())
213         {
214 			_updateViewport((*it).second,updateStatistics);
215 		}
216 		else
217 		{
218 			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,"No viewport with given zorder : "
219 				+ StringConverter::toString(zorder), "RenderTarget::_updateViewport");
220 		}
221 	}
222 
addViewport(Camera * cam,int ZOrder,float left,float top,float width,float height)223     Viewport* RenderTarget::addViewport(Camera* cam, int ZOrder, float left, float top ,
224         float width , float height)
225     {
226         // Check no existing viewport with this Z-order
227         ViewportList::iterator it = mViewportList.find(ZOrder);
228 
229         if (it != mViewportList.end())
230         {
231 			StringUtil::StrStreamType str;
232 			str << "Can't create another viewport for "
233 				<< mName << " with Z-order " << ZOrder
234 				<< " because a viewport exists with this Z-order already.";
235 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, str.str(), "RenderTarget::addViewport");
236         }
237         // Add viewport to list
238         // Order based on Z-order
239         Viewport* vp = OGRE_NEW Viewport(cam, this, left, top, width, height, ZOrder);
240 
241         mViewportList.insert(ViewportList::value_type(ZOrder, vp));
242 
243 		fireViewportAdded(vp);
244 
245         return vp;
246     }
247 	//-----------------------------------------------------------------------
removeViewport(int ZOrder)248     void RenderTarget::removeViewport(int ZOrder)
249     {
250         ViewportList::iterator it = mViewportList.find(ZOrder);
251 
252         if (it != mViewportList.end())
253         {
254 			fireViewportRemoved((*it).second);
255             OGRE_DELETE (*it).second;
256             mViewportList.erase(ZOrder);
257         }
258     }
259 
removeAllViewports(void)260     void RenderTarget::removeAllViewports(void)
261     {
262 
263 
264         for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
265         {
266             fireViewportRemoved(it->second);
267             OGRE_DELETE (*it).second;
268         }
269 
270         mViewportList.clear();
271 
272     }
273 
getStatistics(float & lastFPS,float & avgFPS,float & bestFPS,float & worstFPS) const274     void RenderTarget::getStatistics(float& lastFPS, float& avgFPS,
275         float& bestFPS, float& worstFPS) const
276     {
277 
278         // Note - the will have been updated by the last render
279         lastFPS = mStats.lastFPS;
280         avgFPS = mStats.avgFPS;
281         bestFPS = mStats.bestFPS;
282         worstFPS = mStats.worstFPS;
283 
284 
285     }
286 
getStatistics(void) const287     const RenderTarget::FrameStats& RenderTarget::getStatistics(void) const
288     {
289         return mStats;
290     }
291 
getLastFPS() const292     float RenderTarget::getLastFPS() const
293     {
294         return mStats.lastFPS;
295     }
getAverageFPS() const296     float RenderTarget::getAverageFPS() const
297     {
298         return mStats.avgFPS;
299     }
getBestFPS() const300     float RenderTarget::getBestFPS() const
301     {
302         return mStats.bestFPS;
303     }
getWorstFPS() const304     float RenderTarget::getWorstFPS() const
305     {
306         return mStats.worstFPS;
307     }
308 
getTriangleCount(void) const309     size_t RenderTarget::getTriangleCount(void) const
310     {
311         return mStats.triangleCount;
312     }
313 
getBatchCount(void) const314     size_t RenderTarget::getBatchCount(void) const
315     {
316         return mStats.batchCount;
317     }
318 
getBestFrameTime() const319     float RenderTarget::getBestFrameTime() const
320     {
321         return (float)mStats.bestFrameTime;
322     }
323 
getWorstFrameTime() const324     float RenderTarget::getWorstFrameTime() const
325     {
326         return (float)mStats.worstFrameTime;
327     }
328 
resetStatistics(void)329     void RenderTarget::resetStatistics(void)
330     {
331         mStats.avgFPS = 0.0;
332         mStats.bestFPS = 0.0;
333         mStats.lastFPS = 0.0;
334         mStats.worstFPS = 999.0;
335         mStats.triangleCount = 0;
336         mStats.batchCount = 0;
337         mStats.bestFrameTime = 999999;
338         mStats.worstFrameTime = 0;
339 
340         mLastTime = mTimer->getMilliseconds();
341         mLastSecond = mLastTime;
342         mFrameCount = 0;
343     }
344 
updateStats(void)345     void RenderTarget::updateStats(void)
346     {
347         ++mFrameCount;
348         unsigned long thisTime = mTimer->getMilliseconds();
349 
350         // check frame time
351         unsigned long frameTime = thisTime - mLastTime ;
352         mLastTime = thisTime ;
353 
354         mStats.bestFrameTime = std::min(mStats.bestFrameTime, frameTime);
355         mStats.worstFrameTime = std::max(mStats.worstFrameTime, frameTime);
356 
357         // check if new second (update only once per second)
358         if (thisTime - mLastSecond > 1000)
359         {
360             // new second - not 100% precise
361             mStats.lastFPS = (float)mFrameCount / (float)(thisTime - mLastSecond) * 1000.0f;
362 
363             if (mStats.avgFPS == 0)
364                 mStats.avgFPS = mStats.lastFPS;
365             else
366                 mStats.avgFPS = (mStats.avgFPS + mStats.lastFPS) / 2; // not strictly correct, but good enough
367 
368             mStats.bestFPS = std::max(mStats.bestFPS, mStats.lastFPS);
369             mStats.worstFPS = std::min(mStats.worstFPS, mStats.lastFPS);
370 
371             mLastSecond = thisTime ;
372             mFrameCount  = 0;
373 
374         }
375 
376     }
377 
getCustomAttribute(const String & name,void * pData)378     void RenderTarget::getCustomAttribute(const String& name, void* pData)
379     {
380         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Attribute not found. " + name, " RenderTarget::getCustomAttribute");
381     }
382     //-----------------------------------------------------------------------
addListener(RenderTargetListener * listener)383     void RenderTarget::addListener(RenderTargetListener* listener)
384     {
385         mListeners.push_back(listener);
386     }
387     //-----------------------------------------------------------------------
removeListener(RenderTargetListener * listener)388     void RenderTarget::removeListener(RenderTargetListener* listener)
389     {
390         RenderTargetListenerList::iterator i;
391         for (i = mListeners.begin(); i != mListeners.end(); ++i)
392         {
393             if (*i == listener)
394             {
395                 mListeners.erase(i);
396                 break;
397             }
398         }
399 
400     }
401     //-----------------------------------------------------------------------
removeAllListeners(void)402     void RenderTarget::removeAllListeners(void)
403     {
404         mListeners.clear();
405     }
406     //-----------------------------------------------------------------------
firePreUpdate(void)407     void RenderTarget::firePreUpdate(void)
408     {
409         RenderTargetEvent evt;
410         evt.source = this;
411 
412         RenderTargetListenerList::iterator i, iend;
413         i = mListeners.begin();
414         iend = mListeners.end();
415         for(; i != iend; ++i)
416         {
417             (*i)->preRenderTargetUpdate(evt);
418         }
419 
420 
421     }
422     //-----------------------------------------------------------------------
firePostUpdate(void)423     void RenderTarget::firePostUpdate(void)
424     {
425         RenderTargetEvent evt;
426         evt.source = this;
427 
428         RenderTargetListenerList::iterator i, iend;
429         i = mListeners.begin();
430         iend = mListeners.end();
431         for(; i != iend; ++i)
432         {
433             (*i)->postRenderTargetUpdate(evt);
434         }
435     }
436     //-----------------------------------------------------------------------
getNumViewports(void) const437     unsigned short RenderTarget::getNumViewports(void) const
438     {
439         return (unsigned short)mViewportList.size();
440 
441     }
442     //-----------------------------------------------------------------------
getViewport(unsigned short index)443     Viewport* RenderTarget::getViewport(unsigned short index)
444     {
445         assert (index < mViewportList.size() && "Index out of bounds");
446 
447         ViewportList::iterator i = mViewportList.begin();
448         while (index--)
449             ++i;
450         return i->second;
451     }
452 	//-----------------------------------------------------------------------
getViewportByZOrder(int ZOrder)453     Viewport* RenderTarget::getViewportByZOrder(int ZOrder)
454     {
455 		ViewportList::iterator i = mViewportList.find(ZOrder);
456 		if(i == mViewportList.end())
457 		{
458 			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,"No viewport with given Z-order: "
459 				+ StringConverter::toString(ZOrder), "RenderTarget::getViewportByZOrder");
460 		}
461         return i->second;
462     }
463 	//-----------------------------------------------------------------------
hasViewportWithZOrder(int ZOrder)464     bool RenderTarget::hasViewportWithZOrder(int ZOrder)
465     {
466 		ViewportList::iterator i = mViewportList.find(ZOrder);
467 		return i != mViewportList.end();
468     }
469     //-----------------------------------------------------------------------
isActive() const470     bool RenderTarget::isActive() const
471     {
472         return mActive;
473     }
474     //-----------------------------------------------------------------------
setActive(bool state)475     void RenderTarget::setActive( bool state )
476     {
477         mActive = state;
478     }
479     //-----------------------------------------------------------------------
fireViewportPreUpdate(Viewport * vp)480     void RenderTarget::fireViewportPreUpdate(Viewport* vp)
481     {
482         RenderTargetViewportEvent evt;
483         evt.source = vp;
484 
485         RenderTargetListenerList::iterator i, iend;
486         i = mListeners.begin();
487         iend = mListeners.end();
488         for(; i != iend; ++i)
489         {
490             (*i)->preViewportUpdate(evt);
491         }
492     }
493     //-----------------------------------------------------------------------
fireViewportPostUpdate(Viewport * vp)494     void RenderTarget::fireViewportPostUpdate(Viewport* vp)
495     {
496         RenderTargetViewportEvent evt;
497         evt.source = vp;
498 
499         RenderTargetListenerList::iterator i, iend;
500         i = mListeners.begin();
501         iend = mListeners.end();
502         for(; i != iend; ++i)
503         {
504             (*i)->postViewportUpdate(evt);
505         }
506     }
507 	//-----------------------------------------------------------------------
fireViewportAdded(Viewport * vp)508 	void RenderTarget::fireViewportAdded(Viewport* vp)
509 	{
510 		RenderTargetViewportEvent evt;
511 		evt.source = vp;
512 
513 		RenderTargetListenerList::iterator i, iend;
514 		i = mListeners.begin();
515 		iend = mListeners.end();
516 		for(; i != iend; ++i)
517 		{
518 			(*i)->viewportAdded(evt);
519 		}
520 	}
521 	//-----------------------------------------------------------------------
fireViewportRemoved(Viewport * vp)522 	void RenderTarget::fireViewportRemoved(Viewport* vp)
523 	{
524 		RenderTargetViewportEvent evt;
525 		evt.source = vp;
526 
527 		// Make a temp copy of the listeners
528 		// some will want to remove themselves as listeners when they get this
529 		RenderTargetListenerList tempList = mListeners;
530 
531 		RenderTargetListenerList::iterator i, iend;
532 		i = tempList.begin();
533 		iend = tempList.end();
534 		for(; i != iend; ++i)
535 		{
536 			(*i)->viewportRemoved(evt);
537 		}
538 	}
539     //-----------------------------------------------------------------------
writeContentsToTimestampedFile(const String & filenamePrefix,const String & filenameSuffix)540     String RenderTarget::writeContentsToTimestampedFile(const String& filenamePrefix, const String& filenameSuffix)
541     {
542         struct tm *pTime;
543         time_t ctTime; time(&ctTime);
544         pTime = localtime( &ctTime );
545         Ogre::StringStream oss;
546         oss	<< std::setw(2) << std::setfill('0') << (pTime->tm_mon + 1)
547             << std::setw(2) << std::setfill('0') << pTime->tm_mday
548             << std::setw(2) << std::setfill('0') << (pTime->tm_year + 1900)
549             << "_" << std::setw(2) << std::setfill('0') << pTime->tm_hour
550             << std::setw(2) << std::setfill('0') << pTime->tm_min
551             << std::setw(2) << std::setfill('0') << pTime->tm_sec
552             << std::setw(3) << std::setfill('0') << (mTimer->getMilliseconds() % 1000);
553         String filename = filenamePrefix + oss.str() + filenameSuffix;
554         writeContentsToFile(filename);
555         return filename;
556 
557     }
558 	//-----------------------------------------------------------------------
writeContentsToFile(const String & filename)559 	void RenderTarget::writeContentsToFile(const String& filename)
560 	{
561 		PixelFormat pf = suggestPixelFormat();
562 
563 		uchar *data = OGRE_ALLOC_T(uchar, mWidth * mHeight * PixelUtil::getNumElemBytes(pf), MEMCATEGORY_RENDERSYS);
564 		PixelBox pb(mWidth, mHeight, 1, pf, data);
565 
566 		copyContentsToMemory(pb);
567 
568 		Image().loadDynamicImage(data, mWidth, mHeight, 1, pf, false, 1, 0).save(filename);
569 
570 		OGRE_FREE(data, MEMCATEGORY_RENDERSYS);
571 	}
572     //-----------------------------------------------------------------------
_notifyCameraRemoved(const Camera * cam)573     void RenderTarget::_notifyCameraRemoved(const Camera* cam)
574     {
575         ViewportList::iterator i, iend;
576         iend = mViewportList.end();
577         for (i = mViewportList.begin(); i != iend; ++i)
578         {
579             Viewport* v = i->second;
580             if (v->getCamera() == cam)
581             {
582                 // disable camera link
583                 v->setCamera(0);
584             }
585         }
586     }
587     //-----------------------------------------------------------------------
setAutoUpdated(bool autoup)588     void RenderTarget::setAutoUpdated(bool autoup)
589     {
590         mAutoUpdate = autoup;
591     }
592     //-----------------------------------------------------------------------
isAutoUpdated(void) const593     bool RenderTarget::isAutoUpdated(void) const
594     {
595         return mAutoUpdate;
596     }
597     //-----------------------------------------------------------------------
isPrimary(void) const598     bool RenderTarget::isPrimary(void) const
599     {
600         // RenderWindow will override and return true for the primary window
601         return false;
602     }
603     //-----------------------------------------------------------------------
_getImpl()604     RenderTarget::Impl *RenderTarget::_getImpl()
605     {
606         return 0;
607     }
608     //-----------------------------------------------------------------------
update(bool swap)609     void RenderTarget::update(bool swap)
610     {
611         OgreProfileBeginGPUEvent("RenderTarget: " + getName());
612         // call implementation
613         updateImpl();
614 
615 
616 		if (swap)
617 		{
618 			// Swap buffers
619     	    swapBuffers();
620 		}
621         OgreProfileEndGPUEvent("RenderTarget: " + getName());
622     }
623 
624 
625 }
626