| [6616] | 1 | /* | 
|---|
|  | 2 | *   ORXONOX - the hottest 3D action shooter ever to exist | 
|---|
|  | 3 | *                    > www.orxonox.net < | 
|---|
|  | 4 | * | 
|---|
|  | 5 | * | 
|---|
|  | 6 | *   License notice: | 
|---|
|  | 7 | * | 
|---|
|  | 8 | *   This program is free software; you can redistribute it and/or | 
|---|
|  | 9 | *   modify it under the terms of the GNU General Public License | 
|---|
|  | 10 | *   as published by the Free Software Foundation; either version 2 | 
|---|
|  | 11 | *   of the License, or (at your option) any later version. | 
|---|
|  | 12 | * | 
|---|
|  | 13 | *   This program is distributed in the hope that it will be useful, | 
|---|
|  | 14 | *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
|  | 15 | *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
|  | 16 | *   GNU General Public License for more details. | 
|---|
|  | 17 | * | 
|---|
|  | 18 | *   You should have received a copy of the GNU General Public License | 
|---|
|  | 19 | *   along with this program; if not, write to the Free Software | 
|---|
|  | 20 | *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
|---|
|  | 21 | * | 
|---|
|  | 22 | *   Author: | 
|---|
|  | 23 | *      Gion-Andri Cantieni | 
|---|
|  | 24 | *   Co-authors: | 
|---|
| [8232] | 25 | *      Damian 'Mozork' Frick | 
|---|
| [6616] | 26 | * | 
|---|
|  | 27 | */ | 
|---|
|  | 28 |  | 
|---|
| [8232] | 29 | /** | 
|---|
|  | 30 | @file SkyboxGenerator.cc | 
|---|
|  | 31 | @brief Implementation of the SkyboxGenerator class. | 
|---|
|  | 32 | */ | 
|---|
|  | 33 |  | 
|---|
| [6616] | 34 | #include "SkyboxGenerator.h" | 
|---|
|  | 35 |  | 
|---|
|  | 36 | #include <string> | 
|---|
| [6673] | 37 | #include <OgreRenderWindow.h> | 
|---|
| [6771] | 38 | #include <OgreCamera.h> | 
|---|
| [6673] | 39 |  | 
|---|
| [7284] | 40 | #include "util/ScopedSingletonManager.h" | 
|---|
| [6616] | 41 | #include "core/CoreIncludes.h" | 
|---|
|  | 42 | #include "core/ConfigValueIncludes.h" | 
|---|
| [7284] | 43 | #include "core/GraphicsManager.h" | 
|---|
| [8232] | 44 | #include "core/PathConfig.h" | 
|---|
|  | 45 | #include "core/Resource.h" | 
|---|
| [7284] | 46 | #include "core/command/ConsoleCommand.h" | 
|---|
|  | 47 | #include "core/command/CommandExecutor.h" | 
|---|
| [8232] | 48 |  | 
|---|
| [6673] | 49 | #include "controllers/HumanController.h" | 
|---|
| [8232] | 50 | #include "graphics/Camera.h" | 
|---|
| [6673] | 51 | #include "worldentities/ControllableEntity.h" | 
|---|
|  | 52 |  | 
|---|
| [8232] | 53 | #include "ScreenshotManager.h" | 
|---|
| [6673] | 54 |  | 
|---|
| [8297] | 55 | // #include <X11/Xlib.h> TODO: Needed? | 
|---|
|  | 56 |  | 
|---|
| [6616] | 57 | namespace orxonox | 
|---|
|  | 58 | { | 
|---|
|  | 59 |  | 
|---|
| [7284] | 60 | SetConsoleCommand("SkyboxGenerator", "createSkybox", &SkyboxGenerator::createSkybox).addShortcut(); | 
|---|
| [6616] | 61 |  | 
|---|
|  | 62 | ManageScopedSingleton(SkyboxGenerator, ScopeID::Graphics, false); | 
|---|
|  | 63 |  | 
|---|
| [8232] | 64 | /** | 
|---|
|  | 65 | @brief | 
|---|
|  | 66 | Constructor. Registers and initializes the singleton. | 
|---|
|  | 67 | */ | 
|---|
|  | 68 | SkyboxGenerator::SkyboxGenerator() | 
|---|
| [6616] | 69 | { | 
|---|
|  | 70 | RegisterRootObject(SkyboxGenerator); | 
|---|
|  | 71 |  | 
|---|
|  | 72 | this->setConfigValues(); | 
|---|
| [8232] | 73 |  | 
|---|
|  | 74 | this->bGenerateSkybox_ = false; | 
|---|
|  | 75 | this->bCaptionsRemoved_ = false; | 
|---|
|  | 76 | this->bSetup_ = true; | 
|---|
|  | 77 | this->bWait_ = false; | 
|---|
|  | 78 | this->bCreateFace_ = true; | 
|---|
|  | 79 | this->bCleanup_ = true; | 
|---|
|  | 80 | this->faceCounter_ = 0; | 
|---|
|  | 81 |  | 
|---|
|  | 82 | this->names_.push_back("fr"); | 
|---|
|  | 83 | this->names_.push_back("lf"); | 
|---|
|  | 84 | this->names_.push_back("bk"); | 
|---|
|  | 85 | this->names_.push_back("rt"); | 
|---|
|  | 86 | this->names_.push_back("up"); | 
|---|
|  | 87 | this->names_.push_back("dn"); | 
|---|
|  | 88 |  | 
|---|
|  | 89 | this->rotations_.push_back(std::pair<int, int>(90, 0)); | 
|---|
|  | 90 | this->rotations_.push_back(std::pair<int, int>(90, 0)); | 
|---|
|  | 91 | this->rotations_.push_back(std::pair<int, int>(90, 0)); | 
|---|
|  | 92 | this->rotations_.push_back(std::pair<int, int>(90, 90)); | 
|---|
|  | 93 | this->rotations_.push_back(std::pair<int, int>(0, 180)); | 
|---|
|  | 94 | this->rotations_.push_back(std::pair<int, int>(0, 90)); | 
|---|
| [6616] | 95 | } | 
|---|
|  | 96 |  | 
|---|
| [8232] | 97 | /** | 
|---|
|  | 98 | @brief | 
|---|
|  | 99 | Destructor. | 
|---|
|  | 100 | */ | 
|---|
| [6616] | 101 | SkyboxGenerator::~SkyboxGenerator() | 
|---|
|  | 102 | { | 
|---|
|  | 103 |  | 
|---|
|  | 104 | } | 
|---|
|  | 105 |  | 
|---|
| [8232] | 106 | /** | 
|---|
|  | 107 | @brief | 
|---|
|  | 108 | Sets some config values. | 
|---|
|  | 109 | */ | 
|---|
| [7127] | 110 | void SkyboxGenerator::setConfigValues( ) | 
|---|
| [6616] | 111 | { | 
|---|
|  | 112 | SetConfigValue(skyboxPrefix_, "SkyboxFile_"); | 
|---|
| [8232] | 113 | SetConfigValue(imageExtension_, ".png"); | 
|---|
|  | 114 | SetConfigValue(size_, 1024); | 
|---|
| [6616] | 115 | } | 
|---|
| [8232] | 116 |  | 
|---|
|  | 117 | /** | 
|---|
|  | 118 | @brief | 
|---|
|  | 119 | Generate the 6 faces of a skybox. | 
|---|
|  | 120 | */ | 
|---|
|  | 121 | void SkyboxGenerator::createSkybox() | 
|---|
|  | 122 | { | 
|---|
|  | 123 | // Pause | 
|---|
|  | 124 | CommandExecutor::execute("pause"); | 
|---|
|  | 125 | // Start the skybox generation process. | 
|---|
|  | 126 | SkyboxGenerator::getInstance().startSkyboxGeneration(); | 
|---|
|  | 127 | } | 
|---|
| [6673] | 128 |  | 
|---|
| [8232] | 129 | /** | 
|---|
|  | 130 | @brief | 
|---|
|  | 131 | This is where the skybox generation happens. | 
|---|
|  | 132 | Generating a skybox takes several (up to 10) ticks. | 
|---|
|  | 133 | */ | 
|---|
| [6673] | 134 | void SkyboxGenerator::tick(float dt) | 
|---|
|  | 135 | { | 
|---|
| [8232] | 136 | // Whether a skybox is currently being generated. | 
|---|
|  | 137 | if(this->bGenerateSkybox_) | 
|---|
| [6673] | 138 | { | 
|---|
| [8232] | 139 | // Wait one tick. | 
|---|
|  | 140 | if(this->bWait_) | 
|---|
| [6858] | 141 | { | 
|---|
| [8232] | 142 | this->bWait_ = false; | 
|---|
| [6858] | 143 | return; | 
|---|
|  | 144 | } | 
|---|
| [7127] | 145 |  | 
|---|
| [8232] | 146 | ControllableEntity* entity = NULL; | 
|---|
|  | 147 | if(HumanController::getLocalControllerSingleton() != NULL && HumanController::getLocalControllerSingleton()->getControllableEntity() != NULL) | 
|---|
|  | 148 | entity = HumanController::getLocalControllerSingleton()->getControllableEntity(); | 
|---|
|  | 149 | else | 
|---|
| [6673] | 150 | { | 
|---|
| [8858] | 151 | orxout(user_error) << "You must be in a level to generate a skybox." << endl; | 
|---|
| [8232] | 152 | this->bGenerateSkybox_ = false; | 
|---|
|  | 153 | return; | 
|---|
|  | 154 | } | 
|---|
|  | 155 | Ogre::Camera* camera = entity->getCamera()->getOgreCamera(); | 
|---|
|  | 156 | Ogre::RenderWindow* renderWindow = GraphicsManager::getInstance().getRenderWindow(); | 
|---|
|  | 157 |  | 
|---|
|  | 158 | // Setup the SkyboxGenerator to generate a skybox. | 
|---|
|  | 159 | if(this->bSetup_) | 
|---|
|  | 160 | { | 
|---|
|  | 161 | // If there are captions being displayed, don't. | 
|---|
|  | 162 | if(!this->bCaptionsRemoved_) | 
|---|
|  | 163 | { | 
|---|
|  | 164 | CommandExecutor::execute("GametypeStatus displayCaption false"); | 
|---|
|  | 165 | this->bCaptionsRemoved_ = true; | 
|---|
|  | 166 | return; | 
|---|
|  | 167 | } | 
|---|
|  | 168 |  | 
|---|
|  | 169 | // Store the settings for the camera. | 
|---|
|  | 170 | this->fovy_ = camera->getFOVy(); | 
|---|
|  | 171 | this->aspectRatio_ = camera->getAspectRatio(); | 
|---|
|  | 172 | // Setup the render window. | 
|---|
|  | 173 | this->setupRenderWindow(renderWindow); | 
|---|
|  | 174 | // Add the log path to the standard resource group. | 
|---|
| [8351] | 175 | Ogre::ResourceGroupManager::getSingleton().addResourceLocation(PathConfig::getInstance().getLogPathString(), "FileSystem", Resource::getDefaultResourceGroup()); | 
|---|
| [8232] | 176 |  | 
|---|
| [8858] | 177 | orxout(internal_status) << "Setting up SkyboxGenerator..." << endl; | 
|---|
| [8232] | 178 |  | 
|---|
|  | 179 | this->bSetup_ = false; | 
|---|
|  | 180 | this->bWait_ = true; | 
|---|
|  | 181 | } | 
|---|
|  | 182 | // Create one of the faces. (faceCounter_ decides which) | 
|---|
|  | 183 | else if(this->bCreateFace_) | 
|---|
|  | 184 | { | 
|---|
|  | 185 | // Setup the camera. | 
|---|
|  | 186 | this->setupCamera(camera); | 
|---|
|  | 187 | // Take the picture using the ScreenshotManager and save it. | 
|---|
|  | 188 | this->saveImage(ScreenshotManager::getInstance().getScreenshot(camera), this->skyboxPrefix_+this->names_[this->faceCounter_]+this->imageExtension_); | 
|---|
|  | 189 | // Rotate the camera to be ready for taking the next picture. | 
|---|
|  | 190 | std::pair<int, int> rotate = this->rotations_[this->faceCounter_]; | 
|---|
|  | 191 | if(rotate.first != 0) | 
|---|
| [8234] | 192 | entity->yaw(Degree((float)rotate.first)); | 
|---|
| [8232] | 193 | if(rotate.second != 0) | 
|---|
| [8234] | 194 | entity->pitch(Degree((float)rotate.second)); | 
|---|
| [8232] | 195 |  | 
|---|
| [8858] | 196 | orxout(internal_info) << "Created face number " << this->faceCounter_ << "." << endl; | 
|---|
| [8232] | 197 | // Check whether we've generated all 6 faces. | 
|---|
|  | 198 | if(++this->faceCounter_ >= 6) | 
|---|
|  | 199 | this->bCreateFace_ = false; | 
|---|
|  | 200 | } | 
|---|
|  | 201 | // Cleanup after the successful creation of a skybox. | 
|---|
|  | 202 | else if(this->bCleanup_) | 
|---|
|  | 203 | { | 
|---|
|  | 204 | // Reset the camera parameters. | 
|---|
|  | 205 | camera->setAspectRatio(this->aspectRatio_); | 
|---|
|  | 206 | camera->setFOVy(this->fovy_); | 
|---|
|  | 207 | // Restore the render window. | 
|---|
|  | 208 | this->restoreRenderWindow(renderWindow); | 
|---|
|  | 209 | // Remove the log path from the standard resource group. | 
|---|
| [8351] | 210 | Ogre::ResourceGroupManager::getSingleton().removeResourceLocation(PathConfig::getInstance().getLogPathString(), Resource::getDefaultResourceGroup()); | 
|---|
| [8232] | 211 |  | 
|---|
|  | 212 | // Reset the flow parameters for the next skybox generation. | 
|---|
|  | 213 | this->bGenerateSkybox_ = false; | 
|---|
|  | 214 | this->bSetup_ = true; | 
|---|
|  | 215 | this->bWait_ = false; | 
|---|
|  | 216 | this->bCreateFace_ = true; | 
|---|
|  | 217 | this->bCleanup_ = true; | 
|---|
|  | 218 | this->faceCounter_ = 0; | 
|---|
|  | 219 |  | 
|---|
|  | 220 | // Display captions again. | 
|---|
|  | 221 | CommandExecutor::execute("GametypeStatus displayCaption true"); | 
|---|
|  | 222 | this->bCaptionsRemoved_ = false; | 
|---|
|  | 223 |  | 
|---|
|  | 224 | // Unpause. | 
|---|
| [6673] | 225 | CommandExecutor::execute("pause"); | 
|---|
| [8232] | 226 |  | 
|---|
| [8858] | 227 | orxout(user_info) << "Skybox with face size " << this->size_ << "x" << this->size_ << " pixels created. Storing in log/." << endl; | 
|---|
| [6673] | 228 | } | 
|---|
|  | 229 | } | 
|---|
|  | 230 | } | 
|---|
| [8232] | 231 |  | 
|---|
|  | 232 | /** | 
|---|
|  | 233 | @brief | 
|---|
|  | 234 | Set up the input camera to be ready to generate a skybox face. | 
|---|
|  | 235 | @param camera | 
|---|
|  | 236 | The camera to be set up. | 
|---|
|  | 237 | */ | 
|---|
|  | 238 | void SkyboxGenerator::setupCamera(Ogre::Camera* camera) | 
|---|
|  | 239 | { | 
|---|
|  | 240 | camera->setFOVy(Degree(90)); | 
|---|
|  | 241 | camera->setAspectRatio(1.0); | 
|---|
|  | 242 | } | 
|---|
|  | 243 |  | 
|---|
|  | 244 | /** | 
|---|
|  | 245 | @brief | 
|---|
|  | 246 | Setup the input render window to be ready to generate the skybox. | 
|---|
|  | 247 | @param renderWindow | 
|---|
|  | 248 | The render window to be set up. | 
|---|
|  | 249 | */ | 
|---|
|  | 250 | void SkyboxGenerator::setupRenderWindow(Ogre::RenderWindow* renderWindow) | 
|---|
|  | 251 | { | 
|---|
|  | 252 | // Store current window properties. | 
|---|
|  | 253 | this->windowWidth_ = renderWindow->getWidth(); | 
|---|
|  | 254 | this->windowHeight_ = renderWindow->getHeight(); | 
|---|
|  | 255 | this->windowFullScreen_ = renderWindow->isFullScreen(); | 
|---|
|  | 256 | // Store current ScreenshotManager grid size. | 
|---|
|  | 257 | this->gridSize_ = ScreenshotManager::getInstance().getGridSize(); | 
|---|
|  | 258 |  | 
|---|
|  | 259 | unsigned int size = this->size_; | 
|---|
|  | 260 |  | 
|---|
|  | 261 | // 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. | 
|---|
|  | 262 | if(this->windowHeight_ < this->size_ || this->windowWidth_ < this->size_) | 
|---|
|  | 263 | { | 
|---|
|  | 264 | unsigned int min = std::min(this->windowHeight_, this->windowWidth_); | 
|---|
|  | 265 | unsigned int step = 256; | 
|---|
|  | 266 | assert(min >= step); | 
|---|
|  | 267 | size = step; | 
|---|
|  | 268 | while(min >= size+step) | 
|---|
|  | 269 | size += step; | 
|---|
|  | 270 |  | 
|---|
|  | 271 | unsigned int gridSize = 1; | 
|---|
|  | 272 | while(gridSize*size < this->size_) | 
|---|
|  | 273 | gridSize++; | 
|---|
|  | 274 |  | 
|---|
|  | 275 | renderWindow->setFullscreen(false, size, size); | 
|---|
|  | 276 | ScreenshotManager::getInstance().setGridSize(gridSize); | 
|---|
|  | 277 | } | 
|---|
|  | 278 | else | 
|---|
|  | 279 | ScreenshotManager::getInstance().setGridSize(1); | 
|---|
| [7039] | 280 |  | 
|---|
| [8232] | 281 | } | 
|---|
|  | 282 |  | 
|---|
|  | 283 | /** | 
|---|
|  | 284 | @brief | 
|---|
|  | 285 | Restore the render window. | 
|---|
|  | 286 | Reset the window size, reset the grid size of the ScreenshotManager. | 
|---|
|  | 287 | @param renderWindow | 
|---|
|  | 288 | The render window to be restored. | 
|---|
|  | 289 | */ | 
|---|
|  | 290 | void SkyboxGenerator::restoreRenderWindow(Ogre::RenderWindow* renderWindow) | 
|---|
| [7039] | 291 | { | 
|---|
| [8232] | 292 | // Restore window size. | 
|---|
|  | 293 | renderWindow->setFullscreen(this->windowFullScreen_, this->windowWidth_, this->windowHeight_); | 
|---|
|  | 294 | // Restore grid size. | 
|---|
|  | 295 | ScreenshotManager::getInstance().setGridSize(this->gridSize_); | 
|---|
| [7039] | 296 | } | 
|---|
| [8232] | 297 |  | 
|---|
|  | 298 | /** | 
|---|
|  | 299 | @brief | 
|---|
|  | 300 | Resizes and saves the input image under the input name. | 
|---|
|  | 301 | @param image | 
|---|
|  | 302 | A pointer to the image to be saved. The image is deleted afterwards, | 
|---|
|  | 303 | @param name | 
|---|
|  | 304 | The desired filename of the image. | 
|---|
|  | 305 | */ | 
|---|
|  | 306 | void SkyboxGenerator::saveImage(Ogre::Image* image, const std::string& name) const | 
|---|
|  | 307 | { | 
|---|
|  | 308 | image->save(PathConfig::getInstance().getLogPathString()+name); | 
|---|
|  | 309 | delete image; | 
|---|
|  | 310 | // Loading the resizing, then saving again. This seems stupid, but resizing doesn't seem to work otherwise. | 
|---|
|  | 311 | // If someone figures this out, feel free to adjust. | 
|---|
|  | 312 | image = new Ogre::Image(); | 
|---|
| [8351] | 313 | image->load(name, Resource::getDefaultResourceGroup()); | 
|---|
| [8232] | 314 | image->resize(this->size_, this->size_); | 
|---|
|  | 315 | image->save(PathConfig::getInstance().getLogPathString()+name); | 
|---|
|  | 316 | delete image; | 
|---|
| [8413] | 317 | ScreenshotManager::getInstance().cleanup(); // Free memory in ScreenshotManager. | 
|---|
| [8232] | 318 | } | 
|---|
| [6616] | 319 | } | 
|---|