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