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