00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <engine/GameState.h>
00022 #include <engine/GameStateI.h>
00023 #include <engine/GameStateStimulusI.h>
00024 #include <common/Keyboard.h>
00025 #include <common/Defines.h>
00026 #include <common/Logger.h>
00027 #include <common/LoggerI.h>
00028 #include <limits.h>
00029 #include <SDL/SDL.h>
00030
00031 GameStatePerfCounter::GameStatePerfCounter(const char *name) :
00032 name_(name), total_(0), used_(false)
00033 {
00034 }
00035
00036 GameStatePerfCounter::~GameStatePerfCounter()
00037 {
00038 }
00039
00040 void GameStatePerfCounter::start()
00041 {
00042 used_ = true;
00043 start_ = SDL_GetTicks();
00044 }
00045
00046 void GameStatePerfCounter::end()
00047 {
00048 used_ = true;
00049 unsigned int end = SDL_GetTicks();
00050 total_ += end - start_;
00051 }
00052
00053 unsigned int GameStatePerfCounter::getTotal()
00054 {
00055 unsigned int lastTotal = total_;
00056 total_ = 0;
00057 used_ = false;
00058 return lastTotal;
00059 }
00060
00061 GameState::GameState(const char *name) :
00062 name_(name),
00063 fakeMiddleButton_(true),
00064 currentMouseState_(0),
00065 pendingStimulus_(UINT_MAX),
00066 currentState_(UINT_MAX),
00067 currentEntry_(0),
00068 currentStateI_(0),
00069 currentMouseX_(0), currentMouseY_(0),
00070 mouseDoubleX_(0), mouseDoubleY_(0),
00071 stateLogging_(false),
00072 stateTimeLogging_(0.0f), frameCount_(0)
00073 {
00074 clearTimers();
00075 }
00076
00077 GameState::~GameState()
00078 {
00079
00080 }
00081
00082 void GameState::clear()
00083 {
00084 stateList_.clear();
00085 }
00086
00087 void GameState::setFakeMiddleButton(bool fake)
00088 {
00089 fakeMiddleButton_ = fake;
00090 }
00091
00092 void GameState::mouseWheel(short z)
00093 {
00094 bool skipRest = false;
00095 if (currentEntry_)
00096 {
00097 GameStateEntry *thisEntry = currentEntry_;
00098 unsigned thisState = currentState_;
00099
00100 StateIList *currentList = ¤tEntry_->subMouseWheelList;
00101 if (!currentList->empty())
00102 {
00103 StateIList::iterator subItor;
00104 for (subItor = currentList->begin();
00105 subItor != currentList->end();
00106 subItor++)
00107 {
00108 (*subItor)->mouseWheel(thisState,
00109 currentMouseX_, currentMouseY_,
00110 (int) z, skipRest);
00111 if (checkStimulate()) return;
00112 if (skipRest) break;
00113 }
00114 }
00115 }
00116 }
00117
00118 void GameState::mouseMove(int x, int y)
00119 {
00120 currentMouseX_ = x;
00121 currentMouseY_ = y;
00122 if (currentEntry_)
00123 {
00124 GameStateEntry *thisEntry = currentEntry_;
00125 unsigned thisState = currentState_;
00126
00127 if (MouseButtonMiddle & currentMouseState_)
00128 {
00129 int diffX = x - mouseMDragX_; mouseMDragX_ = x;
00130 int diffY = mouseMDragY_ - y; mouseMDragY_ = y;
00131
00132 mouseMoveCall(thisState, MouseButtonMiddle,
00133 currentEntry_->subMouseDragMiddleList,
00134 x, y, diffX, diffY);
00135 }
00136
00137 if (fakeMiddleButton_ && (MouseButtonLeft & currentMouseState_ &&
00138 MouseButtonRight & currentMouseState_))
00139 {
00140 int diffX = x - mouseMDragX_; mouseMDragX_ = x;
00141 int diffY = mouseMDragY_ - y; mouseMDragY_ = y;
00142
00143 mouseMoveCall(thisState, MouseButtonMiddle,
00144 currentEntry_->subMouseDragMiddleList,
00145 x, y, diffX, diffY);
00146 }
00147 else
00148 {
00149 if (MouseButtonLeft & currentMouseState_)
00150 {
00151 int diffX = x - mouseLDragX_; mouseLDragX_ = x;
00152 int diffY = mouseLDragY_ - y; mouseLDragY_ = y;
00153
00154 mouseMoveCall(thisState, MouseButtonLeft,
00155 currentEntry_->subMouseDragLeftList,
00156 x, y, diffX, diffY);
00157 }
00158 if (MouseButtonRight & currentMouseState_)
00159 {
00160 int diffX = x - mouseRDragX_; mouseRDragX_ = x;
00161 int diffY = mouseRDragY_ - y; mouseRDragY_ = y;
00162
00163 mouseMoveCall(thisState, MouseButtonRight,
00164 currentEntry_->subMouseDragRightList,
00165 x, y, diffX, diffY);
00166 }
00167 }
00168 }
00169 }
00170
00171 void GameState::mouseMoveCall(const unsigned state, MouseButton button,
00172 StateIList ¤tList,
00173 int mx, int my,
00174 int dx, int dy)
00175 {
00176 if (!currentList.empty())
00177 {
00178 bool skipRest = false;
00179 StateIList::iterator subItor;
00180 for (subItor = currentList.begin();
00181 subItor != currentList.end();
00182 subItor++)
00183 {
00184 (*subItor)->mouseDrag(state, button, mx, my, dx, dy, skipRest);
00185 if (checkStimulate()) return;
00186 if (skipRest) break;
00187 }
00188 }
00189 }
00190
00191 void GameState::mouseDown(MouseButton button, int x, int y)
00192 {
00193 mouseUpDown(button, true, x, y);
00194
00195 if (doubleClickClock_.getTimeDifference() < 0.25 &&
00196 abs(mouseDoubleX_ - x) <= 4 &&
00197 abs(mouseDoubleY_ - y) <= 4)
00198 {
00199 switch (button)
00200 {
00201 case MouseButtonLeft:
00202 mouseUpDown(MouseButtonLeftDoubleClick, true, x, y);
00203 break;
00204 case MouseButtonMiddle:
00205 mouseUpDown(MouseButtonMiddleDoubleClick, true, x, y);
00206 break;
00207 case MouseButtonRight:
00208 mouseUpDown(MouseButtonRightDoubleClick, true, x, y);
00209 break;
00210 }
00211 }
00212 mouseDoubleX_ = x;
00213 mouseDoubleY_ = y;
00214 }
00215
00216 void GameState::mouseUp(MouseButton button, int x, int y)
00217 {
00218 mouseUpDown(button, false, x, y);
00219 }
00220
00221 void GameState::mouseUpDown(MouseButton button, bool down, int x, int y)
00222 {
00223 bool skipRest = false;
00224 if (currentEntry_)
00225 {
00226 GameStateEntry *thisEntry = currentEntry_;
00227 unsigned thisState = currentState_;
00228
00229 StateIList *currentList = 0;
00230 if (down)
00231 {
00232 if (button <= MouseButtonLeftDoubleClick)
00233 {
00234 currentMouseState_ |= (unsigned) button;
00235 }
00236 switch(button)
00237 {
00238 case MouseButtonRight:
00239 mouseRDragX_ = x; mouseRDragY_ = y;
00240 currentList = ¤tEntry_->subMouseDownRightList;
00241 break;
00242 case MouseButtonMiddle:
00243 mouseMDragX_ = x; mouseMDragY_ = y;
00244 currentList = ¤tEntry_->subMouseDownMiddleList;
00245 break;
00246 default:
00247 mouseLDragX_ = x; mouseLDragY_ = y;
00248 currentList = ¤tEntry_->subMouseDownLeftList;
00249 break;
00250 }
00251
00252 if (fakeMiddleButton_ &&
00253 (MouseButtonLeft & currentMouseState_ &&
00254 MouseButtonRight & currentMouseState_))
00255 {
00256 mouseMDragX_ = x;
00257 mouseMDragY_ = y;
00258 }
00259 }
00260 else
00261 {
00262 if (fakeMiddleButton_ &&
00263 (MouseButtonLeft & currentMouseState_ &&
00264 MouseButtonRight & currentMouseState_))
00265 {
00266 currentList = ¤tEntry_->subMouseUpMiddleList;
00267 }
00268 else
00269 {
00270 switch(button)
00271 {
00272 case MouseButtonRight:
00273 currentList = ¤tEntry_->subMouseUpRightList;
00274 break;
00275 case MouseButtonMiddle:
00276 currentList = ¤tEntry_->subMouseUpMiddleList;
00277 break;
00278 default:
00279 currentList = ¤tEntry_->subMouseUpLeftList;
00280 break;
00281 }
00282 }
00283
00284 if (button <= MouseButtonLeftDoubleClick)
00285 {
00286 currentMouseState_ ^= (unsigned) button;
00287 }
00288 }
00289
00290 if (!currentList->empty())
00291 {
00292 StateIList::iterator subItor;
00293 for (subItor = currentList->begin();
00294 subItor != currentList->end();
00295 subItor++)
00296 {
00297 if (down)
00298 {
00299 (*subItor)->mouseDown(thisState, button, x, y, skipRest);
00300 }
00301 else
00302 {
00303 (*subItor)->mouseUp(thisState, button, x, y, skipRest);
00304 }
00305 if (checkStimulate()) return;
00306 if (skipRest) break;
00307 }
00308 }
00309 }
00310 }
00311
00312 void GameState::simulate(float simTime)
00313 {
00314 if (checkStimulate()) return;
00315 if (currentEntry_)
00316 {
00317 GameStateEntry *thisEntry = currentEntry_;
00318 unsigned thisState = currentState_;
00319
00320 if (frameCount_ > int(stateTimeLogging_)) clearTimers(true);
00321
00322 timerClock_.getTicksDifference();
00323 int timerCount = 0;
00324
00325 std::list<GameStateSubEntry>::iterator itor;
00326 for (itor = thisEntry->loopList.begin();
00327 itor != thisEntry->loopList.end();
00328 itor++)
00329 {
00330 StateIList::iterator subItor;
00331 for (subItor = itor->subLoopList.begin();
00332 subItor != itor->subLoopList.end();
00333 subItor++, timerCount++)
00334 {
00335 GameStateI *stateI = (*subItor);
00336 currentStateI_ = stateI;
00337 stateI->simulate(thisState, simTime);
00338 if (checkStimulate()) return;
00339
00340 timers_[timerCount % 50].simulateTime +=
00341 timerClock_.getTicksDifference();
00342 timers_[timerCount % 50].gameStateI = stateI;
00343 }
00344
00345
00346
00347
00348 itor->current->simulate(thisState, simTime);
00349 if (checkStimulate()) return;
00350 }
00351
00352 if (!thisEntry->subKeyList.empty())
00353 {
00354 unsigned int historySize;
00355 unsigned int bufferSize;
00356
00357 char *buffer =
00358 Keyboard::instance()->getkeyboardbuffer(bufferSize);
00359 KeyboardHistory::HistoryElement *history =
00360 Keyboard::instance()->getkeyboardhistory(historySize);
00361 unsigned int keyState =
00362 Keyboard::instance()->getKeyboardState();
00363
00364 bool skipRest = false;
00365 StateIList::iterator subItor;
00366 for (subItor = thisEntry->subKeyList.begin();
00367 subItor != thisEntry->subKeyList.end();
00368 subItor++)
00369 {
00370 (*subItor)->keyboardCheck(thisState, simTime, buffer, keyState,
00371 history, historySize, skipRest);
00372 if (checkStimulate()) return;
00373 if (skipRest) break;
00374 }
00375 }
00376
00377 if (!thisEntry->condStimList.empty())
00378 {
00379 StiulusIList::iterator itor;
00380 for (itor = thisEntry->condStimList.begin();
00381 itor != thisEntry->condStimList.end();
00382 itor++)
00383 {
00384 SimulusIPair &p = *itor;
00385 if (p.first->acceptStateChange(thisState, p.second, simTime))
00386 {
00387 if (stateLogging_)
00388 {
00389 Logger::log(S3D::formatStringBuffer("%s::acceptStateChange(%i, %i)",
00390 name_.c_str(), thisState, p.second));
00391 }
00392 setState(itor->second);
00393 return;
00394 }
00395 if (checkStimulate()) return;
00396 }
00397 }
00398 }
00399 }
00400
00401 void GameState::draw()
00402 {
00403 if (currentEntry_)
00404 {
00405 GameStateEntry *thisEntry = currentEntry_;
00406 unsigned thisState = currentState_;
00407
00408 frameCount_ ++;
00409
00410 timerClock_.getTicksDifference();
00411 int timerCount = 0;
00412
00413 std::list<GameStateSubEntry>::iterator itor;
00414 for (itor = thisEntry->loopList.begin();
00415 itor != thisEntry->loopList.end();
00416 itor++)
00417 {
00418 itor->current->draw(thisState);
00419
00420 StateIList::iterator subItor;
00421 for (subItor = itor->subLoopList.begin();
00422 subItor != itor->subLoopList.end();
00423 subItor++, timerCount++)
00424 {
00425 GameStateI *stateI = (*subItor);
00426 currentStateI_ = stateI;
00427 stateI->draw(thisState);
00428 if (checkStimulate()) return;
00429
00430 timers_[timerCount % 50].drawTime +=
00431 timerClock_.getTicksDifference();
00432 timers_[timerCount % 50].gameStateI = stateI;
00433 }
00434 }
00435 }
00436 }
00437
00438 void GameState::setState(const unsigned state)
00439 {
00440 if (stateLogging_)
00441 {
00442 Logger::log(S3D::formatStringBuffer("%s::setState(%i)", name_.c_str(), state));
00443 }
00444
00445 clearTimers();
00446
00447 currentState_ = state;
00448 currentEntry_ = 0;
00449 pendingStimulus_ = UINT_MAX;
00450 std::map<unsigned, GameStateEntry>::iterator itor = stateList_.find(state);
00451 if (itor != stateList_.end())
00452 {
00453 currentEntry_ = &itor->second;
00454
00455 GameStateEntry *thisEntry = currentEntry_;
00456 unsigned thisState = currentState_;
00457
00458 if (!thisEntry->enterStateList.empty())
00459 {
00460 StateIList::iterator subItor;
00461 for (subItor = thisEntry->enterStateList.begin();
00462 subItor != thisEntry->enterStateList.end();
00463 subItor++)
00464 {
00465 GameStateI *s = (*subItor);
00466 s->enterState(thisState);
00467 }
00468 }
00469
00470 if (checkStimulate()) return;
00471 }
00472 else
00473 {
00474 S3D::dialogExit("Scorched3D", S3D::formatStringBuffer(
00475 "%s: Failed to find state %i",
00476 name_.c_str(),
00477 state));
00478 }
00479
00480 if (stateLogging_)
00481 {
00482 Logger::log(S3D::formatStringBuffer("%s::setStateFinished(%i)", name_.c_str(), state));
00483 }
00484 }
00485
00486 bool GameState::checkStimulate()
00487 {
00488 if (pendingStimulus_ != UINT_MAX)
00489 {
00490 std::map<unsigned, unsigned>::iterator itor =
00491 currentEntry_->stimList.find(pendingStimulus_);
00492 if (itor != currentEntry_->stimList.end())
00493 {
00494 pendingStimulus_ = UINT_MAX;
00495 setState(itor->second);
00496 return true;
00497 }
00498 else
00499 {
00500 S3D::dialogExit("Scorched3D", S3D::formatStringBuffer(
00501 "%s: Failed to find stimulus %i in state %i",
00502 name_.c_str(),
00503 pendingStimulus_, currentState_));
00504 }
00505 }
00506
00507 return false;
00508 }
00509
00510 void GameState::stimulate(const unsigned stimulus)
00511 {
00512 if (stateLogging_)
00513 {
00514 Logger::log(S3D::formatStringBuffer("%s::stimulate(%i)", name_.c_str(), stimulus));
00515 }
00516
00517 pendingStimulus_ = stimulus;
00518 }
00519
00520 GameState::GameStateEntry* GameState::getEntry(const unsigned state)
00521 {
00522 GameStateEntry *foundEntry = 0;
00523 std::map<unsigned, GameStateEntry>::iterator itor = stateList_.find(state);
00524 if (itor == stateList_.end())
00525 {
00526 GameStateEntry newEntry;
00527 stateList_[state] = newEntry;
00528
00529 foundEntry = &stateList_[state];
00530
00531 if (currentState_ == state)
00532 {
00533 currentEntry_ = &stateList_[state];
00534 }
00535 }
00536 else
00537 {
00538 foundEntry = &itor->second;
00539 }
00540
00541 return foundEntry;
00542 }
00543
00544 GameState::GameStateSubEntry* GameState::getSubEntry(const unsigned state,
00545 GameStateI *entry)
00546 {
00547 GameStateEntry *foundEntry = getEntry(state);
00548
00549 GameStateSubEntry *foundSubEntry = 0;
00550 std::list<GameStateSubEntry>::iterator subItor;
00551 for (subItor = foundEntry->loopList.begin();
00552 subItor != foundEntry->loopList.end();
00553 subItor++)
00554 {
00555 if (subItor->current == entry)
00556 {
00557 foundSubEntry = &(*subItor);
00558 }
00559 }
00560
00561 if (!foundSubEntry)
00562 {
00563 GameStateSubEntry newEntry;
00564 newEntry.current = entry;
00565
00566 foundEntry->loopList.push_back(newEntry);
00567 foundSubEntry = &foundEntry->loopList.back();
00568 }
00569
00570 return foundSubEntry;
00571 }
00572
00573 void GameState::addStateLoop(const unsigned state, GameStateI *entry,
00574 GameStateI *subEntry)
00575 {
00576 getSubEntry(state, entry)->subLoopList.push_back(subEntry);
00577 }
00578
00579 void GameState::addStateEntry(const unsigned state, GameStateI *subEntry)
00580 {
00581 getEntry(state)->enterStateList.push_back(subEntry);
00582 }
00583
00584 void GameState::addStateKeyEntry(const unsigned state, GameStateI *subEntry)
00585 {
00586 getEntry(state)->subKeyList.push_back(subEntry);
00587 }
00588
00589 void GameState::addStateMouseDownEntry(const unsigned state,
00590 const unsigned buttons,
00591 GameStateI *subEntry)
00592 {
00593 if (buttons & MouseButtonLeft)
00594 {
00595 getEntry(state)->subMouseDownLeftList.push_back(subEntry);
00596 }
00597 if (buttons & MouseButtonRight)
00598 {
00599 getEntry(state)->subMouseDownRightList.push_back(subEntry);
00600 }
00601 if (buttons & MouseButtonMiddle)
00602 {
00603 getEntry(state)->subMouseDownMiddleList.push_back(subEntry);
00604 }
00605 }
00606
00607 void GameState::addStateMouseUpEntry(const unsigned state,
00608 const unsigned buttons,
00609 GameStateI *subEntry)
00610 {
00611 if (buttons & MouseButtonLeft)
00612 {
00613 getEntry(state)->subMouseUpLeftList.push_back(subEntry);
00614 }
00615 if (buttons & MouseButtonRight)
00616 {
00617 getEntry(state)->subMouseUpRightList.push_back(subEntry);
00618 }
00619 if (buttons & MouseButtonMiddle)
00620 {
00621 getEntry(state)->subMouseUpMiddleList.push_back(subEntry);
00622 }
00623 }
00624
00625 void GameState::addStateMouseDragEntry(const unsigned state,
00626 const unsigned buttons,
00627 GameStateI *subEntry)
00628 {
00629 if (buttons & MouseButtonLeft)
00630 {
00631 getEntry(state)->subMouseDragLeftList.push_back(subEntry);
00632 }
00633 if (buttons & MouseButtonRight)
00634 {
00635 getEntry(state)->subMouseDragRightList.push_back(subEntry);
00636 }
00637 if (buttons & MouseButtonMiddle)
00638 {
00639 getEntry(state)->subMouseDragMiddleList.push_back(subEntry);
00640 }
00641 }
00642
00643 void GameState::addStateMouseWheelEntry(const unsigned state,
00644 GameStateI *subEntry)
00645 {
00646 getEntry(state)->subMouseWheelList.push_back(subEntry);
00647 }
00648
00649 void GameState::addStateStimulus(const unsigned state,
00650 const unsigned stim,
00651 const unsigned nexts)
00652 {
00653 GameState::GameStateEntry *entry = getEntry(state);
00654 std::map<unsigned, unsigned>::iterator itor = entry->stimList.find(stim);
00655 if (itor == entry->stimList.end())
00656 {
00657 entry->stimList[stim] = nexts;
00658 }
00659 else
00660 {
00661 DIALOG_ASSERT(0);
00662 }
00663 }
00664
00665 void GameState::addStateStimulus(const unsigned state,
00666 GameStateStimulusI *check,
00667 const unsigned nexts)
00668 {
00669 GameState::GameStateEntry *entry = getEntry(state);
00670 SimulusIPair pair(check, nexts);
00671 entry->condStimList.push_back(pair);
00672 }
00673
00674 void GameState::clearTimers(bool printTimers)
00675 {
00676 unsigned int sinceLastTime = overallTimerClock_.getTicksDifference();
00677 if (printTimers && stateTimeLogging_ > 0.0f)
00678 {
00679 unsigned int simulateTotal = 0, drawTotal = 0;
00680 for (int i=0; i<50; i++)
00681 {
00682 if (timers_[i].gameStateI)
00683 {
00684 simulateTotal += timers_[i].simulateTime;
00685 drawTotal += timers_[i].drawTime;
00686 }
00687 }
00688 int timeLeft = int(sinceLastTime) - int(drawTotal + simulateTotal);
00689 if (sinceLastTime == 0) sinceLastTime = 1;
00690
00691 unsigned int drawTotalPer = (100 * drawTotal) / sinceLastTime;
00692 unsigned int simulateTotalPer = (100 * simulateTotal) / sinceLastTime;
00693 unsigned int timeLeftPer = (100 * timeLeft) / sinceLastTime;
00694
00695 Logger::log(
00696 "----------------------------------------");
00697 Logger::log(S3D::formatStringBuffer("%30s Draw : %4u (%3u%%), Simulate : %4u (%3u%%)\nOther : %4i (%3u%%)\n\n",
00698 name_.c_str(),
00699 drawTotal, drawTotalPer,
00700 simulateTotal, simulateTotalPer,
00701 timeLeft, timeLeftPer));
00702 for (int i=0; i<50; i++)
00703 {
00704 if (timers_[i].gameStateI)
00705 {
00706 unsigned int percentageSimulate =
00707 (100 * timers_[i].simulateTime) / sinceLastTime;
00708 unsigned int percentageDraw =
00709 (100 * timers_[i].drawTime) / sinceLastTime;
00710 if (percentageSimulate > 0 || percentageDraw > 0)
00711 {
00712 Logger::log(S3D::formatStringBuffer("%2i:%25s - Draw : %4u (%3u%%), Simulate : %4u (%3u%%)",
00713 i,
00714 timers_[i].gameStateI->getGameStateIName(),
00715 timers_[i].drawTime, percentageDraw,
00716 timers_[i].simulateTime, percentageSimulate));
00717 }
00718
00719 std::vector<GameStatePerfCounter *>::iterator itor;
00720 for (itor = timers_[i].gameStateI->getPerfCounters().begin();
00721 itor != timers_[i].gameStateI->getPerfCounters().end();
00722 itor++)
00723 {
00724 GameStatePerfCounter *counter = *itor;
00725 bool used = counter->getUsed();
00726 int total = counter->getTotal();
00727 if (used && total > 0 &&
00728 (percentageSimulate > 0 || percentageDraw > 0))
00729 {
00730 Logger::log(S3D::formatStringBuffer("%35s +- %4u",
00731 counter->getName(),
00732 total));
00733 }
00734 }
00735 }
00736 }
00737 }
00738
00739 memset(&timers_, 0, sizeof(timers_));
00740 frameCount_ = 0;
00741 }
00742
00743 int GameState::getPerfCounter(const char *name)
00744 {
00745 DIALOG_ASSERT(currentStateI_);
00746 return currentStateI_->getPerfCounter(name);
00747 }
00748
00749 void GameState::startPerfCount(int counter)
00750 {
00751 DIALOG_ASSERT(currentStateI_);
00752 currentStateI_->startPerfCount(counter);
00753 }
00754
00755 void GameState::endPerfCount(int counter)
00756 {
00757 DIALOG_ASSERT(currentStateI_);
00758 currentStateI_->endPerfCount(counter);
00759 }