[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 | { |
---|
[8232] | 151 | COUT(1) << "You must be in a level to generate a skybox." << endl; |
---|
| 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. |
---|
| 175 | Ogre::ResourceGroupManager::getSingleton().addResourceLocation(PathConfig::getInstance().getLogPathString(), "FileSystem", Resource::DEFAULT_GROUP); |
---|
| 176 | |
---|
| 177 | COUT(4) << "Setting up SkyboxGenerator..." << endl; |
---|
| 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 | |
---|
| 196 | COUT(4) << "Created face number " << this->faceCounter_ << "." << endl; |
---|
| 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. |
---|
| 210 | Ogre::ResourceGroupManager::getSingleton().removeResourceLocation(PathConfig::getInstance().getLogPathString(), Resource::DEFAULT_GROUP); |
---|
| 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 | |
---|
| 227 | COUT(3) << "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(); |
---|
| 313 | image->load(name, Resource::DEFAULT_GROUP); |
---|
| 314 | image->resize(this->size_, this->size_); |
---|
| 315 | image->save(PathConfig::getInstance().getLogPathString()+name); |
---|
| 316 | delete image; |
---|
| 317 | } |
---|
[6616] | 318 | } |
---|