+++ /dev/null
-
-/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
-**] All rights reserved.
-*
-* vi:ts=4 sw=4 tw=75
-*
-* Distributable under the terms and conditions of the 2-clause BSD license;
-* see the file COPYING for a complete text of the license.
-*
-**************************************************************************/
-
-#include <algorithm>
-#include <cstdlib> // exit, srand
-#include <ctime> // time
-#include <string>
-
-#include <SDL/SDL.h>
-#include "fastevents.h"
-
-#include "Error.hh"
-#include "Event.hh"
-#include "Log.hh"
-#include "Math.hh"
-#include "ModalDialog.hh"
-#include "Settings.hh"
-#include "Timer.hh"
-#include "Video.hh"
-#include "View.hh"
-
-
-namespace Mf {
-
-
-class RootView : public View
-{
- void update(Scalar t, Scalar dt)
- {
- if (children().size() == 0) stop();
- }
-};
-
-static RootView gRootView;
-
-
-class View::Impl
-{
-public:
-
- Impl(View* view, Settings& settings, Video& video) :
- mView(*view),
- mSettings(&settings),
- mVideo(&video),
- mParent(&gRootView)
- {
- init();
-
- unsigned randomSeed;
- if (settings.get("rngseed", randomSeed)) srand(randomSeed);
- else srand(time(0));
-
- Scalar timestep = 80.0;
- settings.get("timestep", timestep);
- mTimestep = 1.0 / timestep;
-
- Scalar framerate = 40.0;
- settings.get("framerate", framerate);
- mFramerate = 1.0 / framerate;
-
- mShowFps = false;
- settings.get("showfps", mShowFps);
- }
-
- Impl(View* view) :
- mView(*view),
- mSettings(0),
- mVideo(0),
- mParent(&gRootView)
- {
- init();
- }
-
- void init()
- {
- mTimestep = SCALAR(0.01);
- mFramerate = SCALAR(0.02);
- mShowFps = false;
- }
-
-
- /**
- * The main loop. This just calls dispatchEvents(), update(), and
- * draw() over and over again. The timing of the update and draw are
- * decoupled. The actual frame rate is also calculated here. This
- * function will return the exit code used to stop the loop.
- */
-
- void run()
- {
- ASSERT(mVideo && "running without video set");
-
- Scalar totalTime = 0.0;
- Scalar ticks = Timer::getTicks();
-
- Scalar nextUpdate = ticks;
- Scalar nextDraw = ticks;
- Scalar nextSecond = ticks + SCALAR(1.0);
-
- mFps = 0;
- int frameCount = 0;
-
- const Scalar timestep = mTimestep;
- const Scalar framerate = mFramerate;
-
- const int MAX_FRAMESKIP = 15;
- const Scalar inverseTimestep = SCALAR(1.0) / timestep;
-
- mIsRunning = true;
- for (;;)
- {
- Timer::fireIfExpired(); // 1. fire timers
- dispatchEvents(); // 2. dispatch events
-
- if (!mIsRunning) break;
-
- int i = 0;
- while (nextUpdate < Timer::getTicks() && i < MAX_FRAMESKIP)
- {
- totalTime += timestep; // 3. update state
- mView.update(totalTime, timestep);
-
- nextUpdate += timestep;
- ++i;
-
- if (!mIsRunning) break;
- }
-
- if (nextDraw < (ticks = Timer::getTicks()))
- {
- mView.draw(
- (ticks + timestep - nextUpdate) * inverseTimestep);
- mVideo->swap(); // 4. draw state
-
- nextDraw += framerate;
- ++frameCount;
-
- if (nextSecond < Timer::getTicks())
- {
- mFps = frameCount;
- frameCount = 0;
-
- if (mShowFps) logInfo << mFps << " fps" << std::endl;
-
- nextSecond += SCALAR(1.0);
- }
- }
-
- if (!mIsRunning) break;
-
- ticks = Timer::getTicks(); // 5. yield timeslice
- if (ticks < nextUpdate && ticks < nextDraw) Timer::sleep(0.0);
- }
- }
-
- void stop()
- {
- mIsRunning = false;
- }
-
-
- void dispatchEvents()
- {
- Event event;
-
- while (FE_PollEvent(&event) == 1)
- {
- switch (event.type)
- {
- case SDL_KEYDOWN:
- if (event.key.keysym.sym == SDLK_ESCAPE &&
- (SDL_GetModState() & KMOD_CTRL) )
- {
- // emergency escape
- logWarning("escape forced");
- exit(1);
- }
- break;
-
- case SDL_VIDEORESIZE:
- mVideo->resize(event.resize.w, event.resize.h);
- break;
- }
-
- mView.handleEvent(event);
- }
- }
-
- bool handleEvent(const Event& event)
- {
- std::list<ViewP>::iterator it;
- for (it = mChildren.begin(); it != mChildren.end(); ++it)
- {
- if ((*it)->handleEvent(event)) return true;
- }
-
- return false;
- }
-
- void update(Scalar t, Scalar dt)
- {
- std::list<ViewP>::iterator it;
- for (it = mChildren.begin(); it != mChildren.end(); ++it)
- {
- (*it)->update(t, dt);
- }
- }
-
- void draw(Scalar alpha)
- {
- std::list<ViewP>::iterator it;
- for (it = mChildren.begin(); it != mChildren.end(); ++it)
- {
- (*it)->draw(alpha);
- }
- }
-
-
- void addChild(ViewP child)
- {
- ASSERT(child && "adding null view");
- ASSERT(child.get() != &mView && "adding view to itself");
-
- child->mImpl->mParent->removeChild(child);
- mChildren.push_back(child);
-
- child->mImpl->mParent = &mView;
- child->mImpl->percolateObjects();
-
- child->didAddToView();
- }
-
- void percolateObjects()
- {
- bool recurseAgain = false;
-
- if (mParent->mImpl->mVideo && mParent->mImpl->mVideo != mVideo)
- {
- mVideo = mParent->mImpl->mVideo;
- recurseAgain = true;
- }
-
- if (mParent->mImpl->mSettings &&
- mParent->mImpl->mSettings != mSettings)
- {
- mSettings = mParent->mImpl->mSettings;
- recurseAgain = true;
- }
-
- if (recurseAgain)
- {
- std::list<ViewP>::iterator it;
- for (it = mChildren.begin(); it != mChildren.end(); ++it)
- {
- (*it)->mImpl->percolateObjects();
- }
- }
- }
-
- ViewP removeChild(View* child)
- {
- ASSERT(child && "cannot remove null child");
-
- std::list<ViewP>::iterator it;
- for (it = mChildren.begin(); it != mChildren.end(); ++it)
- {
- if ((*it).get() == child)
- {
- ViewP found = *it;
- found->willRemoveFromView();
- mChildren.erase(it);
-
- found->mImpl->mParent = &gRootView;
-
- return found;
- }
- }
-
- return ViewP();
- }
-
- void clear()
- {
- mChildren.clear();
- }
-
-
- bool mIsRunning;
- View& mView;
-
- Settings* mSettings;
- Video* mVideo;
-
- View* mParent;
- std::list<ViewP> mChildren;
-
- Scalar mTimestep;
- Scalar mFramerate;
-
- int mFps;
- bool mShowFps;
-};
-
-
-View::View(Settings& settings, Video& video) :
- // pass through
- mImpl(new View::Impl(this, settings, video)) {}
-
-View::View() :
- mImpl(new View::Impl(this)) {}
-
-
-void View::update(Scalar t, Scalar dt)
-{
- // pass through
- mImpl->update(t, dt);
-}
-
-void View::draw(Scalar alpha) const
-{
- // pass through
- mImpl->draw(alpha);
-}
-
-bool View::handleEvent(const Event& event)
-{
- // pass through
- return mImpl->handleEvent(event);
-}
-
-
-void View::addChild(ViewP view)
-{
- // pass through
- mImpl->addChild(view);
-}
-
-ViewP View::removeChild(View* view)
-{
- // pass through
- return mImpl->removeChild(view);
-}
-
-ViewP View::removeChild(ViewP view)
-{
- // pass through
- return mImpl->removeChild(view.get());
-}
-
-void View::clear()
-{
- // pass through
- mImpl->clear();
-}
-
-
-View& View::parent() const
-{
- return *(mImpl->mParent);
-}
-
-const std::list<ViewP>& View::children() const
-{
- return mImpl->mChildren;
-}
-
-
-Settings& View::settings() const
-{
- ASSERT(mImpl->mSettings && "accessing null reference");
- // pass through
- return *(mImpl->mSettings);
-}
-
-Video& View::video() const
-{
- ASSERT(mImpl->mVideo && "accessing null reference");
- // pass through
- return *(mImpl->mVideo);
-}
-
-
-void View::run()
-{
- // pass through
- return mImpl->run();
-}
-
-void View::stop()
-{
- // pass through
- return mImpl->stop();
-}
-
-bool View::isRunning() const
-{
- // pass through
- return mImpl->mIsRunning;
-}
-
-
-} // namespace Mf
-