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: |
---|
25 | * Damian 'Mozork' Frick |
---|
26 | * |
---|
27 | */ |
---|
28 | |
---|
29 | /** |
---|
30 | @file SkyboxGenerator.cc |
---|
31 | @brief Implementation of the SkyboxGenerator class. |
---|
32 | */ |
---|
33 | |
---|
34 | #include "SkyboxGenerator.h" |
---|
35 | |
---|
36 | #include <string> |
---|
37 | #include <OgreRenderWindow.h> |
---|
38 | #include <OgreCamera.h> |
---|
39 | |
---|
40 | #include "util/ScopedSingletonManager.h" |
---|
41 | #include "core/CoreIncludes.h" |
---|
42 | #include "core/ConfigValueIncludes.h" |
---|
43 | #include "core/GraphicsManager.h" |
---|
44 | #include "core/PathConfig.h" |
---|
45 | #include "core/Resource.h" |
---|
46 | #include "core/command/ConsoleCommand.h" |
---|
47 | #include "core/command/CommandExecutor.h" |
---|
48 | |
---|
49 | #include "controllers/HumanController.h" |
---|
50 | #include "graphics/Camera.h" |
---|
51 | #include "worldentities/ControllableEntity.h" |
---|
52 | |
---|
53 | #include "ScreenshotManager.h" |
---|
54 | |
---|
55 | // #include <X11/Xlib.h> TODO: Needed? |
---|
56 | |
---|
57 | namespace orxonox |
---|
58 | { |
---|
59 | |
---|
60 | SetConsoleCommand("SkyboxGenerator", "createSkybox", &SkyboxGenerator::createSkybox).addShortcut(); |
---|
61 | |
---|
62 | ManageScopedSingleton(SkyboxGenerator, ScopeID::Graphics, false); |
---|
63 | |
---|
64 | /** |
---|
65 | @brief |
---|
66 | Constructor. Registers and initializes the singleton. |
---|
67 | */ |
---|
68 | SkyboxGenerator::SkyboxGenerator() |
---|
69 | { |
---|
70 | RegisterRootObject(SkyboxGenerator); |
---|
71 | |
---|
72 | this->setConfigValues(); |
---|
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)); |
---|
95 | } |
---|
96 | |
---|
97 | /** |
---|
98 | @brief |
---|
99 | Destructor. |
---|
100 | */ |
---|
101 | SkyboxGenerator::~SkyboxGenerator() |
---|
102 | { |
---|
103 | |
---|
104 | } |
---|
105 | |
---|
106 | /** |
---|
107 | @brief |
---|
108 | Sets some config values. |
---|
109 | */ |
---|
110 | void SkyboxGenerator::setConfigValues( ) |
---|
111 | { |
---|
112 | SetConfigValue(skyboxPrefix_, "SkyboxFile_"); |
---|
113 | SetConfigValue(imageExtension_, ".png"); |
---|
114 | SetConfigValue(size_, 1024); |
---|
115 | } |
---|
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 | } |
---|
128 | |
---|
129 | /** |
---|
130 | @brief |
---|
131 | This is where the skybox generation happens. |
---|
132 | Generating a skybox takes several (up to 10) ticks. |
---|
133 | */ |
---|
134 | void SkyboxGenerator::tick(float dt) |
---|
135 | { |
---|
136 | // Whether a skybox is currently being generated. |
---|
137 | if(this->bGenerateSkybox_) |
---|
138 | { |
---|
139 | // Wait one tick. |
---|
140 | if(this->bWait_) |
---|
141 | { |
---|
142 | this->bWait_ = false; |
---|
143 | return; |
---|
144 | } |
---|
145 | |
---|
146 | ControllableEntity* entity = NULL; |
---|
147 | if(HumanController::getLocalControllerSingleton() != NULL && HumanController::getLocalControllerSingleton()->getControllableEntity() != NULL) |
---|
148 | entity = HumanController::getLocalControllerSingleton()->getControllableEntity(); |
---|
149 | else |
---|
150 | { |
---|
151 | orxout(user_error) << "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::getDefaultResourceGroup()); |
---|
176 | |
---|
177 | orxout(internal_status) << "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) |
---|
192 | entity->yaw(Degree((float)rotate.first)); |
---|
193 | if(rotate.second != 0) |
---|
194 | entity->pitch(Degree((float)rotate.second)); |
---|
195 | |
---|
196 | orxout(internal_info) << "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::getDefaultResourceGroup()); |
---|
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. |
---|
225 | CommandExecutor::execute("pause"); |
---|
226 | |
---|
227 | orxout(user_info) << "Skybox with face size " << this->size_ << "x" << this->size_ << " pixels created. Storing in log/." << endl; |
---|
228 | } |
---|
229 | } |
---|
230 | } |
---|
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); |
---|
280 | |
---|
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) |
---|
291 | { |
---|
292 | // Restore window size. |
---|
293 | renderWindow->setFullscreen(this->windowFullScreen_, this->windowWidth_, this->windowHeight_); |
---|
294 | // Restore grid size. |
---|
295 | ScreenshotManager::getInstance().setGridSize(this->gridSize_); |
---|
296 | } |
---|
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::getDefaultResourceGroup()); |
---|
314 | image->resize(this->size_, this->size_); |
---|
315 | image->save(PathConfig::getInstance().getLogPathString()+name); |
---|
316 | delete image; |
---|
317 | ScreenshotManager::getInstance().cleanup(); // Free memory in ScreenshotManager. |
---|
318 | } |
---|
319 | } |
---|