- Timestamp:
- Jul 25, 2009, 10:16:37 PM (15 years ago)
- Location:
- code/branches/resource/src/core
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/resource/src/core/Game.cc
r3349 r3352 122 122 bChangingState_ = false; 123 123 124 #ifdef ORXONOX_PLATFORM_WINDOWS 125 minimumSleepTime_ = 1000/*us*/; 126 #else 127 minimumSleepTime_ = 0/*us*/; 128 #endif 129 124 130 // Create an empty root state 125 declareGameState<GameState>("GameState", "emptyRootGameState", true, false); 126 127 // reset statistics 128 this->statisticsStartTime_ = 0; 129 this->statisticsTickTimes_.clear(); 130 this->periodTickTime_ = 0; 131 this->periodTime_ = 0; 132 this->avgFPS_ = 0.0f; 133 this->avgTickTime_ = 0.0f; 131 this->declareGameState<GameState>("GameState", "emptyRootGameState", true, false); 134 132 135 133 // Set up a basic clock to keep time … … 195 193 COUT(0) << "Warning: Starting game without requesting GameState. This automatically terminates the program." << std::endl; 196 194 195 // reset statistics 196 this->statisticsStartTime_ = 0; 197 this->statisticsTickTimes_.clear(); 198 this->periodTickTime_ = 0; 199 this->periodTime_ = 0; 200 this->avgFPS_ = 0.0f; 201 this->avgTickTime_ = 0.0f; 202 this->excessSleepTime_ = 0; 203 197 204 // START GAME 198 205 // first delta time should be about 0 seconds … … 203 210 while (!this->bAbort_ && (!this->activeStates_.empty() || this->requestedStateNodes_.size() > 0)) 204 211 { 205 uint64_t currentTime = this->gameClock_->getRealMicroseconds(); 206 207 uint64_t nextTickTime = statisticsTickTimes_.back().tickTime + static_cast<uint64_t>(1000000.0f / configuration_->fpsLimit_); 208 if (currentTime < nextTickTime) 209 { 210 usleep(nextTickTime - currentTime); 211 continue; 212 } 212 // Generate the dt 213 213 this->gameClock_->capture(); 214 214 215 // S TATISTICS216 StatisticsTickInfo tickInfo = { currentTime, 0};215 // Statistics init 216 StatisticsTickInfo tickInfo = {gameClock_->getMicroseconds(), 0}; 217 217 statisticsTickTimes_.push_back(tickInfo); 218 218 this->periodTime_ += this->gameClock_->getDeltaTimeMicroseconds(); 219 219 220 // UPDATE STATE STACK 221 while (this->requestedStateNodes_.size() > 0) 222 { 223 shared_ptr<GameStateTreeNode> requestedStateNode = this->requestedStateNodes_.front(); 224 assert(this->activeStateNode_); 225 if (!this->activeStateNode_->parent_.expired() && requestedStateNode == this->activeStateNode_->parent_.lock()) 226 this->unloadState(this->activeStateNode_->state_); 227 else // has to be child 228 { 229 try 230 { 231 this->loadState(requestedStateNode->state_); 232 } 233 catch (const std::exception& ex) 234 { 235 COUT(1) << "Error: Loading GameState '" << requestedStateNode->state_->getName() << "' failed: " << ex.what() << std::endl; 236 // All scheduled operations have now been rendered inert --> flush them and issue a warning 237 if (this->requestedStateNodes_.size() > 1) 238 COUT(1) << "All " << this->requestedStateNodes_.size() - 1 << " scheduled transitions have been ignored." << std::endl; 239 this->requestedStateNodes_.clear(); 240 break; 241 } 242 } 243 this->activeStateNode_ = requestedStateNode; 244 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin()); 245 } 246 247 // UPDATE, Core preUpdate (doesn't throw) 220 // Update the GameState stack if required 221 this->updateGameStateStack(); 222 223 // Core preUpdate (doesn't throw) 248 224 if (!this->core_->preUpdate(*this->gameClock_)) 249 225 { … … 252 228 } 253 229 254 // UPDATE, GameStates bottom to top in the stack 255 // Note: The first element is the empty root state, which doesn't need ticking 256 for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin() + 1; 257 it != this->activeStates_.end(); ++it) 258 { 259 std::string exceptionMessage; 260 try 261 { 262 // Add tick time for most of the states 263 uint64_t timeBeforeTick; 264 if ((*it)->ignoreTickTime()) 265 timeBeforeTick = this->gameClock_->getRealMicroseconds(); 266 (*it)->update(*this->gameClock_); 267 if ((*it)->ignoreTickTime()) 268 this->subtractTickTime(static_cast<int32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick)); 269 } 270 catch (const std::exception& ex) 271 { exceptionMessage = ex.what(); } 272 catch (...) 273 { exceptionMessage = "Unknown exception"; } 274 if (!exceptionMessage.empty()) 275 { 276 COUT(1) << "An exception occurred while updating '" << (*it)->getName() << "': " << exceptionMessage << std::endl; 277 COUT(1) << "This should really never happen!" << std::endl; 278 COUT(1) << "Unloading all GameStates depending on the one that crashed." << std::endl; 279 if ((*it)->getParent() != NULL) 280 this->requestState((*it)->getParent()->getName()); 281 else 282 this->stop(); 283 break; 284 } 285 286 } 287 288 // UPDATE, Core postUpdate (doesn't throw) 230 // Update the GameStates bottom up in the stack 231 this->updateGameStates(); 232 233 // Core postUpdate (doesn't throw) 289 234 if (!this->core_->postUpdate(*this->gameClock_)) 290 235 { … … 293 238 } 294 239 295 // STATISTICS 296 if (this->periodTime_ > this->configuration_->statisticsRefreshCycle_) 297 { 298 std::list<StatisticsTickInfo>::iterator it = this->statisticsTickTimes_.begin(); 299 assert(it != this->statisticsTickTimes_.end()); 300 int64_t lastTime = currentTime - this->configuration_->statisticsAvgLength_; 301 if (static_cast<int64_t>(it->tickTime) < lastTime) 302 { 303 do 304 { 305 assert(this->periodTickTime_ >= it->tickLength); 306 this->periodTickTime_ -= it->tickLength; 307 ++it; 308 assert(it != this->statisticsTickTimes_.end()); 309 } while (static_cast<int64_t>(it->tickTime) < lastTime); 310 this->statisticsTickTimes_.erase(this->statisticsTickTimes_.begin(), it); 311 } 312 313 uint32_t framesPerPeriod = this->statisticsTickTimes_.size(); 314 this->avgFPS_ = static_cast<float>(framesPerPeriod) / (currentTime - this->statisticsTickTimes_.front().tickTime) * 1000000.0f; 315 this->avgTickTime_ = static_cast<float>(this->periodTickTime_) / framesPerPeriod / 1000.0f; 316 317 this->periodTime_ -= this->configuration_->statisticsRefreshCycle_; 318 } 240 // Evaluate statistics 241 this->updateStatistics(); 242 243 // Limit framerate 244 this->updateFPSLimiter(); 319 245 } 320 246 … … 324 250 this->activeStateNode_ = this->rootStateNode_; 325 251 this->requestedStateNodes_.clear(); 252 } 253 254 void Game::updateGameStateStack() 255 { 256 while (this->requestedStateNodes_.size() > 0) 257 { 258 shared_ptr<GameStateTreeNode> requestedStateNode = this->requestedStateNodes_.front(); 259 assert(this->activeStateNode_); 260 if (!this->activeStateNode_->parent_.expired() && requestedStateNode == this->activeStateNode_->parent_.lock()) 261 this->unloadState(this->activeStateNode_->state_); 262 else // has to be child 263 { 264 try 265 { 266 this->loadState(requestedStateNode->state_); 267 } 268 catch (const std::exception& ex) 269 { 270 COUT(1) << "Error: Loading GameState '" << requestedStateNode->state_->getName() << "' failed: " << ex.what() << std::endl; 271 // All scheduled operations have now been rendered inert --> flush them and issue a warning 272 if (this->requestedStateNodes_.size() > 1) 273 COUT(1) << "All " << this->requestedStateNodes_.size() - 1 << " scheduled transitions have been ignored." << std::endl; 274 this->requestedStateNodes_.clear(); 275 break; 276 } 277 } 278 this->activeStateNode_ = requestedStateNode; 279 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin()); 280 } 281 } 282 283 void Game::updateGameStates() 284 { 285 // Note: The first element is the empty root state, which doesn't need ticking 286 for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin() + 1; 287 it != this->activeStates_.end(); ++it) 288 { 289 std::string exceptionMessage; 290 try 291 { 292 // Add tick time for most of the states 293 uint64_t timeBeforeTick; 294 if ((*it)->ignoreTickTime()) 295 timeBeforeTick = this->gameClock_->getRealMicroseconds(); 296 (*it)->update(*this->gameClock_); 297 if ((*it)->ignoreTickTime()) 298 this->subtractTickTime(static_cast<int32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick)); 299 } 300 catch (const std::exception& ex) 301 { exceptionMessage = ex.what(); } 302 catch (...) 303 { exceptionMessage = "Unknown exception"; } 304 if (!exceptionMessage.empty()) 305 { 306 COUT(1) << "An exception occurred while updating '" << (*it)->getName() << "': " << exceptionMessage << std::endl; 307 COUT(1) << "This should really never happen!" << std::endl; 308 COUT(1) << "Unloading all GameStates depending on the one that crashed." << std::endl; 309 if ((*it)->getParent() != NULL) 310 this->requestState((*it)->getParent()->getName()); 311 else 312 this->stop(); 313 break; 314 } 315 } 316 } 317 318 void Game::updateStatistics() 319 { 320 // Add the tick time of this frame (rendering time has already been subtracted) 321 uint64_t currentTime = gameClock_->getMicroseconds(); 322 uint64_t currentRealTime = gameClock_->getRealMicroseconds(); 323 this->statisticsTickTimes_.back().tickLength += currentRealTime - currentTime; 324 this->periodTickTime_ += currentRealTime - currentTime; 325 if (this->periodTime_ > this->configuration_->statisticsRefreshCycle_) 326 { 327 std::list<StatisticsTickInfo>::iterator it = this->statisticsTickTimes_.begin(); 328 assert(it != this->statisticsTickTimes_.end()); 329 int64_t lastTime = currentTime - this->configuration_->statisticsAvgLength_; 330 if (static_cast<int64_t>(it->tickTime) < lastTime) 331 { 332 do 333 { 334 assert(this->periodTickTime_ >= it->tickLength); 335 this->periodTickTime_ -= it->tickLength; 336 ++it; 337 assert(it != this->statisticsTickTimes_.end()); 338 } while (static_cast<int64_t>(it->tickTime) < lastTime); 339 this->statisticsTickTimes_.erase(this->statisticsTickTimes_.begin(), it); 340 } 341 342 uint32_t framesPerPeriod = this->statisticsTickTimes_.size(); 343 this->avgFPS_ = static_cast<float>(framesPerPeriod) / (currentTime - this->statisticsTickTimes_.front().tickTime) * 1000000.0f; 344 this->avgTickTime_ = static_cast<float>(this->periodTickTime_) / framesPerPeriod / 1000.0f; 345 346 this->periodTime_ -= this->configuration_->statisticsRefreshCycle_; 347 } 348 } 349 350 void Game::updateFPSLimiter() 351 { 352 // Why configuration_->fpsLimit_ - 1? No idea, but otherwise the fps rate is always (from 10 to 200!) one frame too high 353 uint32_t nextTime = gameClock_->getMicroseconds() - excessSleepTime_ + static_cast<uint32_t>(1000000.0f / (configuration_->fpsLimit_ - 1)); 354 uint64_t currentRealTime = gameClock_->getRealMicroseconds(); 355 while (currentRealTime < nextTime - minimumSleepTime_) 356 { 357 usleep(nextTime - currentRealTime); 358 currentRealTime = gameClock_->getRealMicroseconds(); 359 } 360 // Integrate excess to avoid steady state error 361 excessSleepTime_ = currentRealTime - nextTime; 362 // Anti windup 363 if (excessSleepTime_ > 50000) // 20ms is about the maximum time Windows would sleep for too long 364 excessSleepTime_ = 50000; 326 365 } 327 366 -
code/branches/resource/src/core/Game.h
r3349 r3352 133 133 void unloadState(GameState* state); 134 134 135 // Main loop structuring 136 void updateGameStateStack(); 137 void updateGameStates(); 138 void updateStatistics(); 139 void updateFPSLimiter(); 140 135 141 std::map<std::string, GameState*> gameStates_; 136 142 std::vector<GameState*> activeStates_; … … 153 159 float avgFPS_; 154 160 float avgTickTime_; 161 int excessSleepTime_; 162 unsigned int minimumSleepTime_; 155 163 156 164 static std::map<std::string, GameStateInfo> gameStateDeclarations_s;
Note: See TracChangeset
for help on using the changeset viewer.