*******************************************************************************/
#include <algorithm>
-#include <cstdlib> // exit
+#include <cstdlib> // exit, srand
+#include <ctime> // time
#include <list>
#include <string>
+#include <AL/alc.h>
#include <SDL/SDL.h>
#include "fastevents.h"
-#include <AL/alut.h>
-#include "Dispatcher.hh"
+
#include "Engine.hh"
#include "Event.hh"
#include "Log.hh"
-#include "Random.hh"
+#include "Math.hh"
#include "Settings.hh"
#include "Timer.hh"
-#include "Video.hh"
namespace Mf {
class Engine::Impl
{
public:
- 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)
+
+ Impl() :
+ mError(Error::NONE),
+ mTimestep(0.01),
+ mFramerate(0.02),
+ mShowFps(false)
{
-#if defined(_WIN32) || defined (_WIN64) || defined(__WIN32__)
+#if defined(_WIN32) || defined(__WIN32__)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
#else
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTTHREAD) != 0)
#endif
{
- logError("sdl is complaining: %s", SDL_GetError());
- throw Exception(Exception::SDL_ERROR);
+ const char* error = SDL_GetError();
+ mError.init(Error::SDL_INIT, error);
+ return; // fatal
}
+ else
+ {
+ char name[128];
+ SDL_VideoDriverName(name, sizeof(name));
+ logInfo << "initialized SDL; using video driver `"
+ << name << "'" << std::endl;
+ }
+
if (FE_Init() != 0)
{
- logError("fast events error: %s", FE_GetError());
- throw Exception(Exception::SDL_ERROR);
+ const char* error = FE_GetError();
+ mError.init(Error::FASTEVENTS_INIT, error);
+ return; // fatal
}
- alutInit(&argc, argv);
- Settings& settings = Settings::getInstance();
- settings.loadFromFile(configFile);
- settings.parseArgs(argc, argv);
+ mAlDevice = alcOpenDevice(0);
+ mAlContext = alcCreateContext(mAlDevice, 0);
+ if (!mAlDevice || !mAlContext)
+ {
+ const char* error = alcGetString(mAlDevice,alcGetError(mAlDevice));
+ mError.init(Error::OPENAL_INIT, error);
+ }
+ else
+ {
+ alcMakeContextCurrent(mAlContext);
+ logInfo << "opened sound device `"
+ << alcGetString(mAlDevice, ALC_DEFAULT_DEVICE_SPECIFIER)
+ << "'" << std::endl;
+ }
+ }
- long randomSeed;
- if (settings.get("rngseed", randomSeed)) setSeed(randomSeed);
- else setSeed();
+ bool initWithSettings(const Settings& settings)
+ {
+ unsigned randomSeed;
+ if (settings.get("rngseed", randomSeed)) srand(randomSeed);
+ else srand(time(0));
- Scalar timeStep = 80.0;
- settings.get("timestep", timeStep);
- timestep = 1.0 / timeStep;
+ Scalar timestep = 80.0;
+ settings.get("timestep", timestep);
+ mTimestep = 1.0 / timestep;
- Scalar maxFps = 40.0;
- settings.get("maxfps", maxFps);
- drawRate = 1.0 / maxFps;
+ Scalar framerate = 40.0;
+ settings.get("framerate", framerate);
+ mFramerate = 1.0 / framerate;
+ capFps();
- settings.get("printfps", printFps);
+ mShowFps = false;
+ settings.get("showfps", mShowFps);
- video = Video::alloc(name, iconFile);
- video->makeActive();
+ return true;
}
~Impl()
{
// the video object must be destroyed before we can shutdown SDL
- video.reset();
+ mVideo.reset();
+
+ alcMakeContextCurrent(0);
+ alcDestroyContext(mAlContext);
+ alcCloseDevice(mAlDevice);
- alutExit();
FE_Quit();
SDL_Quit();
}
void run()
{
- Scalar ticksNow = Timer::getTicks();
+ Scalar totalTime = 0.0;
+ Scalar ticks = Timer::getTicks();
- Scalar nextStep = ticksNow;
- Scalar nextDraw = ticksNow;
- Scalar nextFpsUpdate = ticksNow + 1.0;
+ Scalar nextUpdate = ticks;
+ Scalar nextDraw = ticks;
+ Scalar nextSecond = ticks + SCALAR(1.0);
- Scalar totalTime = 0.0;
- Scalar deltaTime = 0.0;
- Scalar accumulator = timestep;
+ mFps = 0;
+ int frames = 0;
- fps = 0;
- int frameAccum = 0;
+ const int MAX_FRAMESKIP = 15;
+ const Scalar inverseTimestep = SCALAR(1.0) / mTimestep;
do
{
- Scalar newTicks = Timer::getTicks();
- deltaTime = newTicks - ticksNow;
- ticksNow = newTicks;
-
- if (deltaTime >= 0.25) deltaTime = 0.25;
- accumulator += deltaTime;
+ Timer::fireIfExpired();
+ dispatchEvents();
- Timer::fireIfExpired(ticksNow);
-
- while (accumulator >= timestep)
+ int i = 0;
+ while (nextUpdate < Timer::getTicks() && i < MAX_FRAMESKIP)
{
- dispatchEvents();
- update(totalTime, timestep);
-
- totalTime += timestep;
- accumulator -= timestep;
+ totalTime += mTimestep;
+ update(totalTime, mTimestep);
- nextStep += timestep;
- }
- if (ticksNow >= nextStep)
- {
- nextStep = ticksNow + timestep;
+ nextUpdate += mTimestep;
+ ++i;
}
- if (ticksNow >= nextDraw)
+ if (nextDraw < (ticks = Timer::getTicks()))
{
- frameAccum++;
-
- if (ticksNow >= nextFpsUpdate) // determine the actual fps
- {
- fps = frameAccum;
- frameAccum = 0;
+ ++frames;
+ draw((ticks + mTimestep - nextUpdate) * inverseTimestep);
+ mVideo->swap();
- nextFpsUpdate += 1.0;
- if (ticksNow >= nextFpsUpdate)
- {
- nextFpsUpdate = ticksNow + 1.0;
- }
+ nextDraw += mFramerate;
- if (printFps)
- {
- logInfo("%d fps", fps);
- }
- }
+ if (mShowFps && nextSecond < ticks)
+ {
+ mFps = frames;
+ frames = 0;
- draw(accumulator / timestep);
- video->swap();
+ logInfo << mFps << " fps" << std::endl;
- nextDraw += drawRate;
- if (ticksNow >= nextDraw)
- {
- // we missed some scheduled draws, so reset the schedule
- nextDraw = ticksNow + drawRate;
+ nextSecond += SCALAR(1.0);
}
}
// be a good citizen and give back what you don't need
- Timer::sleep(std::min(std::min(nextStep, nextDraw),
- Timer::getNextFire()), true);
+ Timer::sleep(0.0);
}
- while (!stack.empty());
+ while (!mStack.empty());
+
+ mDispatch.dispatch("engine.stopping");
}
void dispatchEvents()
(SDL_GetModState() & KMOD_CTRL) )
{
// emergency escape
- exit(0);
+ logWarning("escape forced");
+ exit(1);
}
break;
case SDL_VIDEORESIZE:
- video->resize(event.resize.w, event.resize.h);
+ mVideo->resize(event.resize.w, event.resize.h);
break;
}
void update(Scalar t, Scalar dt)
{
- for (stackIt = stack.begin(); stackIt != stack.end(); ++stackIt)
+ for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt)
{
- (*stackIt)->update(t, dt);
+ (*mStackIt)->update(t, dt);
}
}
{
// 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)
+ for (it = mStack.rbegin(); it != mStack.rend(); ++it)
{
(*it)->draw(alpha);
}
void handleEvent(const Event& event)
{
- for (stackIt = stack.begin(); stackIt != stack.end(); ++stackIt)
+ for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt)
{
- if ((*stackIt)->handleEvent(event)) break;
+ if ((*mStackIt)->handleEvent(event)) break;
}
}
void push(LayerP layer)
{
ASSERT(layer && "cannot push null layer");
- stack.push_front(layer);
- logInfo(" push: %d", stack.size());
- layer->pushed(interface);
+ mStack.push_front(layer);
+ logInfo << "stack: " << mStack.size()
+ << " [pushed " << layer.get() << "]" << std::endl;
+ layer->pushedOntoEngine();
}
LayerP pop()
{
bool fixIt = false;
- if (stack.begin() == stackIt) fixIt = true;
+ if (mStack.begin() == mStackIt) fixIt = true;
- LayerP popped = stack.front();
- stack.pop_front();
- logInfo(" pop: %d", stack.size());
- popped->popped(interface);
+ LayerP layer = mStack.front();
+ mStack.pop_front();
+ logInfo << "stack: " << mStack.size()
+ << " [popped " << layer.get() << "]" << std::endl;
+ layer->poppedFromEngine();
- if (fixIt) stackIt = --stack.begin();
+ if (fixIt) mStackIt = --mStack.begin();
- return popped;
+ return layer;
}
LayerP pop(Layer* layer)
{
bool fixIt = false;
- std::list<LayerP> popped;
+ std::list<LayerP> layers;
std::list<LayerP>::iterator it;
- for (it = stack.begin(); it != stack.end(); ++it)
+ for (it = mStack.begin(); it != mStack.end(); ++it)
{
- popped.push_back(*it);
+ layers.push_back(*it);
- if (it == stackIt) fixIt = true;
+ if (it == mStackIt) fixIt = true;
if ((*it).get() == layer)
{
++it;
- stack.erase(stack.begin(), it);
+ mStack.erase(mStack.begin(), it);
- for (it = popped.begin(); it != popped.end(); ++it)
+ for (it = layers.begin(); it != layers.end(); ++it)
{
- (*it)->popped(interface);
+ (*it)->poppedFromEngine();
+ logInfo << "stack: " << mStack.size()
+ << " [popped " << (*it).get() << "]" << std::endl;
}
- if (fixIt) stackIt = --stack.begin();
+ if (fixIt) mStackIt = --mStack.begin();
- return popped.back();
+ return layers.back();
}
}
void clear()
{
- stack.clear();
- stackIt = stack.begin();
- logInfo("clear: %d", stack.size());
+ mStack.clear();
+ mStackIt = mStack.begin();
+ logInfo("stack: 0 [cleared]");
+ }
+
+
+ void capFps()
+ {
+ //if (mFramerate < mTimestep)
+ //{
+ //logWarning << "capping maximum fps to timestep ("
+ //<< mTimestep << ")" << std::endl;
+ //mFramerate = mTimestep;
+ //}
}
- Engine& interface;
+ Error mError;
- VideoP video;
+ VideoP mVideo;
+ Dispatch mDispatch;
- std::list<LayerP> stack;
- std::list<LayerP>::iterator stackIt;
+ ALCdevice* mAlDevice;
+ ALCcontext* mAlContext;
- Scalar timestep;
- Scalar drawRate;
+ std::list<LayerP> mStack;
+ std::list<LayerP>::iterator mStackIt;
- long fps;
- bool printFps;
+ Scalar mTimestep;
+ Scalar mFramerate;
+
+ int mFps;
+ bool mShowFps;
};
-static Engine* instance = 0;
+Engine::Engine() :
+ // pass through
+ mImpl(new Engine::Impl) {}
+
-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))
+bool Engine::initWithSettings(const Settings& settings)
{
- instance = this;
+ // pass through
+ return mImpl->initWithSettings(settings);
}
+const Error& Engine::getError() const
+{
+ // pass through
+ return mImpl->mError;
+}
-Engine& Engine::getInstance()
+void Engine::clearError()
{
- ASSERT(instance && "dereferencing null pointer");
- return *instance;
- //static Engine engine;
- //return engine;
+ // pass through
+ mImpl->mError.init(Error::NONE);
}
-void Engine::run()
+void Engine::setVideo(VideoP video)
{
- return impl_->run();
+ // pass through
+ mImpl->mVideo = video;
}
-void Engine::setTimestep(Scalar ts)
+VideoP Engine::getVideo() const
{
- impl_->timestep = ts;
+ return mImpl->mVideo;
}
-Scalar Engine::getTimestep() const
+
+int Engine::getFps() const
{
- return impl_->timestep;
+ return mImpl->mFps;
}
-void Engine::setMaxFrameRate(long maxFps)
+
+void Engine::push(LayerP layer)
{
- impl_->drawRate = 1.0 / Scalar(maxFps);
+ // pass through
+ mImpl->push(layer);
}
-long Engine::getMaxFrameRate() const
+LayerP Engine::pop()
{
- return long(1.0 / impl_->drawRate);
+ // pass through
+ return mImpl->pop();
}
+LayerP Engine::pop(Layer* layer)
+{
+ // pass through
+ return mImpl->pop(layer);
+}
-Video& Engine::getVideo() const
+void Engine::clear()
{
- return *impl_->video;
+ // pass through
+ mImpl->clear();
}
-long Engine::getFrameRate() const
+int Engine::getSize() const
{
- return impl_->fps;
+ return mImpl->mStack.size();
}
-void Engine::push(LayerP layer)
+void Engine::run()
{
// pass through
- impl_->push(layer);
+ return mImpl->run();
}
-LayerP Engine::pop()
+
+Dispatch::Handler Engine::addHandler(const std::string& event,
+ const Dispatch::Function& callback)
{
- // pass through
- return impl_->pop();
+ return mImpl->mDispatch.addHandler(event, callback);
}
-LayerP Engine::pop(Layer* layer)
+Dispatch::Handler Engine::addHandler(const std::string& event,
+ const Dispatch::Function& callback, Dispatch::Handler handler)
{
- // pass through
- return impl_->pop(layer);
+ return mImpl->mDispatch.addHandler(event, callback, handler);
}
-void Engine::clear()
+void Engine::dispatch(const std::string& event,
+ const Dispatch::Message* message)
{
- // pass through
- impl_->clear();
+ mImpl->mDispatch.dispatch(event, message);
}
+Engine engine;
+
+
} // namespace Mf
/** vim: set ts=4 sw=4 tw=80: *************************************************/