/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * This code comes from http://www.ogre3d.org/tikiwiki/High+resolution+screenshots which is Public Domain. * Co-authors: * Oli Scheuss * Damian 'Mozork' Frick * */ /** @file ScreenshotManager.cc @brief Implementation of the ScreenshotManager class. @ingroup Designtools */ #include "ScreenshotManager.h" #include #include #include #include #include // #include TODO: Needed? #include "core/ConfigValueIncludes.h" #include "core/GraphicsManager.h" #include "core/PathConfig.h" #include "core/Resource.h" #include "core/command/ConsoleCommand.h" #include "util/ScopedSingletonManager.h" #include "util/StringUtils.h" #include "CameraManager.h" #include "graphics/Camera.h" namespace orxonox { SetConsoleCommand("printScreenHD", &ScreenshotManager::makeScreenshot_s); ManageScopedSingleton(ScreenshotManager, ScopeID::Graphics, false); /** @brief Constructor. */ ScreenshotManager::ScreenshotManager() { RegisterRootObject(ScreenshotManager); this->setConfigValues(); // Flag for overlay rendering this->disableOverlays_ = true; // Update the values this->update(); } ScreenshotManager::~ScreenshotManager() { } /** @brief Sets some config values. */ void ScreenshotManager::setConfigValues(void) { // Set file extension for the Screenshot files. SetConfigValue(fileExtension_, ".png"); // The grid size. SetConfigValue(gridSize_, 3); } /** @brief Update internal parameters. */ void ScreenshotManager::update(void) { Ogre::RenderWindow* pRenderWindow = GraphicsManager::getInstance().getRenderWindow(); // If the window size has changed if(this->windowWidth_ != pRenderWindow->getWidth() || this->windowHeight_ != pRenderWindow->getHeight()) { // Update current window size this->windowWidth_ = pRenderWindow->getWidth(); this->windowHeight_ = pRenderWindow->getHeight(); // Create temporary texture this->tempTexture_ = Ogre::TextureManager::getSingleton().createManual("ScreenShotTex", Resource::getDefaultResourceGroup(), Ogre::TEX_TYPE_2D, this->windowWidth_, this->windowHeight_, 0, Ogre::PF_B8G8R8, Ogre::TU_RENDERTARGET); // Get the current render target of the temporary texture this->renderTarget_ = this->tempTexture_->getBuffer()->getRenderTarget(); // HardwarePixelBufferSharedPtr to the buffer of the temporary texture this->buffer_ = this->tempTexture_->getBuffer(); // Create PixelBox this->data_ = new uint8_t[(this->windowWidth_ * this->gridSize_) * (this->windowHeight_ * this->gridSize_) * 3]; this->finalPicturePB_ = Ogre::PixelBox(this->windowWidth_ * this->gridSize_, this->windowHeight_ * this->gridSize_, 1, Ogre::PF_B8G8R8, this->data_); } } /** @brief Make a screenshot. The screenshot is saved in the log folder. */ void ScreenshotManager::makeScreenshot() { // Get the screenshot. Ogre::Image* finalImage = getScreenshot(); if(finalImage != NULL) { // Save it. finalImage->save(PathConfig::getInstance().getLogPathString() + "screenshot_" + getTimestamp() + "." + this->fileExtension_); delete finalImage; COUT(3) << "Finished taking " << this->gridSize_*this->windowWidth_ << "x" << this->gridSize_*this->windowHeight_ << " pixel HD screenshot. Storing in log/." << endl; } else { COUT(1) << "There needs to be an active camera to make screenshots." << endl; return; } } /** @brief Creates a screenshot and returns it. @return Returns a pointer to an Ogre::Image with the screenshot. */ Ogre::Image* ScreenshotManager::getScreenshot() { if(CameraManager::getInstance().getActiveCamera() == NULL ) return NULL; return this->getScreenshot(CameraManager::getInstance().getActiveCamera()->getOgreCamera()); } /** @brief Creates a screenshot with the given camera and returns it. @param camera A pointer to the camera the screenshot should be taken with. @return Returns a pointer to an Ogre::Image with the screenshot. */ Ogre::Image* ScreenshotManager::getScreenshot(Ogre::Camera* camera) { if(camera == NULL) return NULL; // Update the internal parameters. this->update(); // Add the camera as viewport. this->renderTarget_->removeAllViewports(); this->renderTarget_->addViewport(camera); // Set the viewport settings Ogre::Viewport *vp = renderTarget_->getViewport(0); vp->setClearEveryFrame(true); vp->setOverlaysEnabled(false); // Remind current overlay flag bool enableOverlayFlag = GraphicsManager::getInstance().getViewport()->getOverlaysEnabled(); // We disable overlay rendering if it is set in config file and the viewport setting is enabled if(this->disableOverlays_ && enableOverlayFlag) GraphicsManager::getInstance().getViewport()->setOverlaysEnabled(false); Ogre::Image* finalImage = new Ogre::Image(); if(this->gridSize_ <= 1) { // Simple case where the contents of the screen are taken directly // Also used when an invalid value is passed within gridSize (zero or negative grid size) this->renderTarget_->update(); // Render finalImage = &finalImage->loadDynamicImage(static_cast(finalPicturePB_.data), finalPicturePB_.getWidth(), finalPicturePB_.getHeight(),Ogre::PF_B8G8R8); } else { // Define the original frustum extents variables Ogre::Real originalFrustumLeft, originalFrustumRight, originalFrustumTop, originalFrustumBottom; // Set the original Frustum extents camera->getFrustumExtents(originalFrustumLeft, originalFrustumRight, originalFrustumTop, originalFrustumBottom); // Compute the Stepsize for the grid Ogre::Real frustumGridStepHorizontal = (originalFrustumRight * 2) / this->gridSize_; Ogre::Real frustumGridStepVertical = (originalFrustumTop * 2) / this->gridSize_; // Process each grid Ogre::Real frustumLeft, frustumRight, frustumTop, frustumBottom; for (unsigned int nbScreenshots = 0; nbScreenshots < this->gridSize_ * this->gridSize_; nbScreenshots++) { int y = nbScreenshots / this->gridSize_; int x = nbScreenshots - y * this->gridSize_; // Shoggoth frustum extents setting // Compute the new frustum extents frustumLeft = originalFrustumLeft + frustumGridStepHorizontal * x; frustumRight = frustumLeft + frustumGridStepHorizontal; frustumTop = originalFrustumTop - frustumGridStepVertical * y; frustumBottom = frustumTop - frustumGridStepVertical; // Set the frustum extents value to the camera camera->setFrustumExtents(frustumLeft, frustumRight, frustumTop, frustumBottom); // Ignore time duration between frames Ogre::Root::getSingletonPtr()->clearEventTimes(); this->renderTarget_->update(); // Render // Define the current box Ogre::Box subBox = Ogre::Box(x* this->windowWidth_,y * this->windowHeight_,x * this->windowWidth_ + this->windowWidth_, y * this->windowHeight_ + this->windowHeight_); // Copy the content from the temp buffer into the final picture PixelBox // Place the tempBuffer content at the right position this->buffer_->blitToMemory(this->finalPicturePB_.getSubVolume(subBox)); COUT(4) << "Created screenshot number " << nbScreenshots << " for multi grid HD screenshot." << endl; } // Set frustum extents to previous settings camera->resetFrustumExtents(); // Insert the PixelBox data into the Image Object finalImage->loadDynamicImage(static_cast(this->finalPicturePB_.data), this->finalPicturePB_.getWidth(), this->finalPicturePB_.getHeight(), 1, Ogre::PF_B8G8R8, false); } // Do we have to re-enable our overlays? if(enableOverlayFlag) GraphicsManager::getInstance().getViewport()->setOverlaysEnabled(true); // Reset time since last frame to pause the scene Ogre::Root::getSingletonPtr()->clearEventTimes(); return finalImage; } /** @brief Set the size of the grid. @param size The size of the grid. */ void ScreenshotManager::setGridSize(unsigned int size) { if(size == this->gridSize_) return; this->gridSize_ = size; // New PixelBox for the changed size. this->data_ = new uint8_t[(this->windowWidth_ * this->gridSize_) * (this->windowHeight_ * this->gridSize_) * 3]; this->finalPicturePB_ = Ogre::PixelBox(this->windowWidth_ * this->gridSize_, this->windowHeight_ * this->gridSize_, 1, Ogre::PF_B8G8R8, this->data_); } }