/* * 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: * Gion-Andri Cantieni * Co-authors: * Damian 'Mozork' Frick * */ /** @file SkyboxGenerator.cc @brief Implementation of the SkyboxGenerator class. */ #include "SkyboxGenerator.h" #include #include #include #include "core/CoreIncludes.h" #include "core/config/ConfigValueIncludes.h" #include "core/GraphicsManager.h" #include "core/PathConfig.h" #include "core/Resource.h" #include "core/command/ConsoleCommandIncludes.h" #include "core/command/CommandExecutor.h" #include "core/singleton/ScopedSingletonManager.h" #include "controllers/HumanController.h" #include "graphics/Camera.h" #include "worldentities/ControllableEntity.h" #include "ScreenshotManager.h" // #include TODO: Needed? namespace orxonox { SetConsoleCommand("SkyboxGenerator", "createSkybox", &SkyboxGenerator::createSkybox).addShortcut(); ManageScopedSingleton(SkyboxGenerator, ScopeID::Graphics, false); RegisterAbstractClass(SkyboxGenerator).inheritsFrom().inheritsFrom(); /** @brief Constructor. Registers and initializes the singleton. */ SkyboxGenerator::SkyboxGenerator() { RegisterObject(SkyboxGenerator); this->setConfigValues(); this->bGenerateSkybox_ = false; this->bCaptionsRemoved_ = false; this->bSetup_ = true; this->bWait_ = false; this->bCreateFace_ = true; this->bCleanup_ = true; this->faceCounter_ = 0; this->names_.push_back("fr"); this->names_.push_back("lf"); this->names_.push_back("bk"); this->names_.push_back("rt"); this->names_.push_back("up"); this->names_.push_back("dn"); this->rotations_.push_back(std::pair(90, 0)); this->rotations_.push_back(std::pair(90, 0)); this->rotations_.push_back(std::pair(90, 0)); this->rotations_.push_back(std::pair(90, 90)); this->rotations_.push_back(std::pair(0, 180)); this->rotations_.push_back(std::pair(0, 90)); } /** @brief Destructor. */ SkyboxGenerator::~SkyboxGenerator() { } /** @brief Sets some config values. */ void SkyboxGenerator::setConfigValues( ) { SetConfigValue(skyboxPrefix_, "SkyboxFile_"); SetConfigValue(imageExtension_, ".png"); SetConfigValue(size_, 1024); } /** @brief Generate the 6 faces of a skybox. */ void SkyboxGenerator::createSkybox() { // Pause CommandExecutor::execute("pause"); // Start the skybox generation process. SkyboxGenerator::getInstance().startSkyboxGeneration(); } /** @brief This is where the skybox generation happens. Generating a skybox takes several (up to 10) ticks. */ void SkyboxGenerator::tick(float dt) { // Whether a skybox is currently being generated. if(this->bGenerateSkybox_) { // Wait one tick. if(this->bWait_) { this->bWait_ = false; return; } ControllableEntity* entity = NULL; if(HumanController::getLocalControllerSingleton() != NULL && HumanController::getLocalControllerSingleton()->getControllableEntity() != NULL) entity = HumanController::getLocalControllerSingleton()->getControllableEntity(); else { orxout(user_error) << "You must be in a level to generate a skybox." << endl; this->bGenerateSkybox_ = false; return; } Ogre::Camera* camera = entity->getCamera()->getOgreCamera(); Ogre::RenderWindow* renderWindow = GraphicsManager::getInstance().getRenderWindow(); // Setup the SkyboxGenerator to generate a skybox. if(this->bSetup_) { // If there are captions being displayed, don't. if(!this->bCaptionsRemoved_) { CommandExecutor::execute("GametypeStatus displayCaption false"); this->bCaptionsRemoved_ = true; return; } // Store the settings for the camera. this->fovy_ = camera->getFOVy(); this->aspectRatio_ = camera->getAspectRatio(); // Setup the render window. this->setupRenderWindow(renderWindow); // Add the log path to the standard resource group. Ogre::ResourceGroupManager::getSingleton().addResourceLocation(PathConfig::getInstance().getLogPathString(), "FileSystem", Resource::getDefaultResourceGroup()); orxout(internal_status) << "Setting up SkyboxGenerator..." << endl; this->bSetup_ = false; this->bWait_ = true; } // Create one of the faces. (faceCounter_ decides which) else if(this->bCreateFace_) { // Setup the camera. this->setupCamera(camera); // Take the picture using the ScreenshotManager and save it. this->saveImage(ScreenshotManager::getInstance().getScreenshot(camera), this->skyboxPrefix_+this->names_[this->faceCounter_]+this->imageExtension_); // Rotate the camera to be ready for taking the next picture. std::pair rotate = this->rotations_[this->faceCounter_]; if(rotate.first != 0) entity->yaw(Degree((float)rotate.first)); if(rotate.second != 0) entity->pitch(Degree((float)rotate.second)); orxout(internal_info) << "Created face number " << this->faceCounter_ << "." << endl; // Check whether we've generated all 6 faces. if(++this->faceCounter_ >= 6) this->bCreateFace_ = false; } // Cleanup after the successful creation of a skybox. else if(this->bCleanup_) { // Reset the camera parameters. camera->setAspectRatio(this->aspectRatio_); camera->setFOVy(this->fovy_); // Restore the render window. this->restoreRenderWindow(renderWindow); // Remove the log path from the standard resource group. Ogre::ResourceGroupManager::getSingleton().removeResourceLocation(PathConfig::getInstance().getLogPathString(), Resource::getDefaultResourceGroup()); // Reset the flow parameters for the next skybox generation. this->bGenerateSkybox_ = false; this->bSetup_ = true; this->bWait_ = false; this->bCreateFace_ = true; this->bCleanup_ = true; this->faceCounter_ = 0; // Display captions again. CommandExecutor::execute("GametypeStatus displayCaption true"); this->bCaptionsRemoved_ = false; // Unpause. CommandExecutor::execute("pause"); orxout(user_info) << "Skybox with face size " << this->size_ << "x" << this->size_ << " pixels created. Storing in log/." << endl; } } } /** @brief Set up the input camera to be ready to generate a skybox face. @param camera The camera to be set up. */ void SkyboxGenerator::setupCamera(Ogre::Camera* camera) { camera->setFOVy(Degree(90)); camera->setAspectRatio(1.0); } /** @brief Setup the input render window to be ready to generate the skybox. @param renderWindow The render window to be set up. */ void SkyboxGenerator::setupRenderWindow(Ogre::RenderWindow* renderWindow) { // Store current window properties. this->windowWidth_ = renderWindow->getWidth(); this->windowHeight_ = renderWindow->getHeight(); this->windowFullScreen_ = renderWindow->isFullScreen(); // Store current ScreenshotManager grid size. this->gridSize_ = ScreenshotManager::getInstance().getGridSize(); unsigned int size = this->size_; // If the desired skybox face size is bigger than what the current render window can accommodate we find a size that is a multiple of 256, that fits into the current render window adjust the grid size of the ScreenshotManager such that the screenshots generated are at least as big as we need. if(this->windowHeight_ < this->size_ || this->windowWidth_ < this->size_) { unsigned int min = std::min(this->windowHeight_, this->windowWidth_); unsigned int step = 256; assert(min >= step); size = step; while(min >= size+step) size += step; unsigned int gridSize = 1; while(gridSize*size < this->size_) gridSize++; renderWindow->setFullscreen(false, size, size); ScreenshotManager::getInstance().setGridSize(gridSize); } else ScreenshotManager::getInstance().setGridSize(1); } /** @brief Restore the render window. Reset the window size, reset the grid size of the ScreenshotManager. @param renderWindow The render window to be restored. */ void SkyboxGenerator::restoreRenderWindow(Ogre::RenderWindow* renderWindow) { // Restore window size. renderWindow->setFullscreen(this->windowFullScreen_, this->windowWidth_, this->windowHeight_); // Restore grid size. ScreenshotManager::getInstance().setGridSize(this->gridSize_); } /** @brief Resizes and saves the input image under the input name. @param image A pointer to the image to be saved. The image is deleted afterwards, @param name The desired filename of the image. */ void SkyboxGenerator::saveImage(Ogre::Image* image, const std::string& name) const { image->save(PathConfig::getInstance().getLogPathString()+name); delete image; // Loading the resizing, then saving again. This seems stupid, but resizing doesn't seem to work otherwise. // If someone figures this out, feel free to adjust. image = new Ogre::Image(); image->load(name, Resource::getDefaultResourceGroup()); image->resize(this->size_, this->size_); image->save(PathConfig::getInstance().getLogPathString()+name); delete image; ScreenshotManager::getInstance().cleanup(); // Free memory in ScreenshotManager. } }