*******************************************************************************/
+#include <algorithm>
#include <cstdlib> // exit
+#include <list>
#include <string>
#include <SDL/SDL.h>
#include "Dispatcher.hh"
#include "Engine.hh"
+#include "Event.hh"
#include "Log.hh"
#include "Random.hh"
#include "Settings.hh"
class Engine::Impl
{
public:
- Impl(int argc, char* argv[], const std::string& configFile,
- const std::string& name, const std::string& iconFile,
- Engine* outer) :
- interface(outer),
+ Impl(int argc, char* argv[], const std::string& name,
+ const std::string& iconFile, const std::string& configFile,
+ Engine& engine) :
+ interface(engine),
timestep(0.01),
printFps(false)
{
* the exit code used to stop the loop.
*/
- int run()
+ void run()
{
Scalar ticksNow = Timer::getTicks();
fps = 0;
int frameAccum = 0;
- running = true;
do
{
Scalar newTicks = Timer::getTicks();
while (accumulator >= timestep)
{
dispatchEvents();
- interface->update(totalTime, timestep);
+ update(totalTime, timestep);
totalTime += timestep;
accumulator -= timestep;
}
}
- interface->draw(accumulator / timestep);
+ draw(accumulator / timestep);
video->swap();
nextDraw += drawRate;
Timer::sleep(std::min(std::min(nextStep, nextDraw),
Timer::getNextFire()), true);
}
- while (running);
-
- return exitCode;
+ while (!stack.empty());
}
-
void dispatchEvents()
{
SDL_Event event;
if (event.key.keysym.sym == SDLK_ESCAPE &&
(SDL_GetModState() & KMOD_CTRL) )
{
- exit(0);
+ // emergency escape
+ exit(0);
}
break;
break;
}
- interface->handleEvent(event);
+ handleEvent(event);
}
}
- Engine* interface;
+ void update(Scalar t, Scalar dt)
+ {
+ for (stackIt = stack.begin(); stackIt != stack.end(); ++stackIt)
+ {
+ (*stackIt)->update(t, dt);
+ }
+ }
- VideoP video;
+ void draw(Scalar alpha)
+ {
+ // FIXME - this will crash if the layer being drawn pops itself
+ std::list<LayerP>::reverse_iterator it;
+ for (it = stack.rbegin(); it != stack.rend(); ++it)
+ {
+ (*it)->draw(alpha);
+ }
+ }
- bool running;
- int exitCode;
+ void handleEvent(const Event& event)
+ {
+ for (stackIt = stack.begin(); stackIt != stack.end(); ++stackIt)
+ {
+ if ((*stackIt)->handleEvent(event)) break;
+ }
+ }
- Scalar timestep;
- Scalar drawRate;
- long fps;
- bool printFps;
-};
+ void pushLayer(LayerP layer)
+ {
+ ASSERT(layer && "cannot push null layer");
+ stack.push_front(layer);
+ layer->pushed(interface);
+ }
+
+ void popLayer()
+ {
+ bool fixIt = false;
+ if (stack.begin() == stackIt) fixIt = true;
+ LayerP popped = stack.front();
+ stack.pop_front();
+ popped->popped(interface);
-Engine::Engine(int argc, char* argv[], const std::string& configFile,
- const std::string& name, const std::string& iconFile) :
- impl_(new Engine::Impl(argc, argv, configFile, name, iconFile, this)) {}
+ if (fixIt) stackIt = --stack.begin();
+ }
+
+ void popLayer(Layer* layer)
+ {
+ bool fixIt = false;
-Engine::~Engine() {}
+ std::list<LayerP>::iterator it;
+ for (it = stack.begin(); it != stack.end(); ++it)
+ {
+ if (it == stackIt) fixIt = true;
+ if ((*it).get() == layer)
+ {
+ ++it;
+ do
+ {
+ LayerP popped = stack.front();
+ stack.pop_front();
+ popped->popped(interface);
+ }
+ while (stack.begin() != it);
+
+ if (fixIt) stackIt = --stack.begin();
+ return;
+ }
+ }
+ }
-int Engine::run()
+ void clearLayers()
+ {
+ stack.clear();
+ stackIt = stack.begin();
+ }
+
+
+ Engine& interface;
+
+ VideoP video;
+
+ std::list<LayerP> stack;
+ std::list<LayerP>::iterator stackIt;
+
+ Scalar timestep;
+ Scalar drawRate;
+
+ long fps;
+ bool printFps;
+};
+
+
+static Engine* instance = 0;
+
+Engine::Engine(int argc, char* argv[], const std::string& name,
+ const std::string& iconFile, const std::string& configFile) :
+ impl_(new Engine::Impl(argc, argv, name, iconFile, configFile, *this))
{
- return impl_->run();
+ instance = this;
}
-void Engine::stop(int exitCode)
+
+Engine& Engine::getInstance()
{
- impl_->running = false;
- impl_->exitCode = exitCode;
+ ASSERT(instance && "dereferencing null pointer");
+ return *instance;
}
+void Engine::run()
+{
+ return impl_->run();
+}
+
void Engine::setTimestep(Scalar ts)
{
impl_->timestep = ts;
}
-Scalar Engine::getTimestep()
+Scalar Engine::getTimestep() const
{
return impl_->timestep;
}
impl_->drawRate = 1.0 / Scalar(maxFps);
}
-long Engine::getMaxFrameRate()
+long Engine::getMaxFrameRate() const
{
return long(1.0 / impl_->drawRate);
}
-Video& Engine::getVideo()
+Video& Engine::getVideo() const
{
return *impl_->video;
}
-long Engine::getFrameRate()
+long Engine::getFrameRate() const
{
return impl_->fps;
}
-void Engine::update(Scalar t, Scalar dt) {}
-void Engine::draw(Scalar alpha) {}
-void Engine::handleEvent(const Event& event) {}
+void Engine::pushLayer(LayerP layer)
+{
+ // pass through
+ impl_->pushLayer(layer);
+}
+
+void Engine::popLayer()
+{
+ // pass through
+ impl_->popLayer();
+}
+
+void Engine::popLayer(Layer* layer)
+{
+ // pass through
+ impl_->popLayer(layer);
+}
+
+void Engine::clearLayers()
+{
+ // pass through
+ impl_->clearLayers();
+}
} // namespace Mf