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