X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FEngine.cc;h=785cb4b41ed67ee342cf8df535f9e6726e5d3a35;hp=e97c8b5d1b7edbae52a5b48ebc1072574e697ebe;hb=f0aed8dbdbdd61ac9d0728058ba5eb9693b4b94c;hpb=33842c860fe18ca8cf087905992885687434320c diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index e97c8b5..785cb4b 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -26,20 +26,24 @@ *******************************************************************************/ -#include // exit +#include +#include // exit, srand +#include // time +#include #include +#include #include #include "fastevents.h" -#include -#include "Dispatcher.hh" + #include "Engine.hh" +#include "Event.hh" +#include "Exception.hh" #include "Log.hh" -#include "Random.hh" +#include "Math.hh" #include "Settings.hh" #include "Timer.hh" -#include "Video.hh" namespace Mf { @@ -48,56 +52,79 @@ namespace Mf { 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(Engine& engine) : + mInterface(engine), + mTimestep(0.01), + mPrintFps(false) { -#if defined(_WIN32) || defined (_WIN64) || defined(__WIN32__) + // first, initialize the libraries + +#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(); + throw Exception(ErrorCode::SDL_INIT, error); } + else + { + char vdName[128]; + SDL_VideoDriverName(vdName, sizeof(vdName)); + logDebug("initialized SDL; using video driver `%s'", vdName); + } + if (FE_Init() != 0) { - logError("fast events error: %s", FE_GetError()); - throw Exception(Exception::SDL_ERROR); + const char* error = FE_GetError(); + throw Exception(ErrorCode::FASTEVENTS_INIT, error); } - alutInit(&argc, argv); - Settings& settings = Settings::getInstance(); - settings.parseArgs(argc, argv); - settings.loadFromFile(configFile); + mAlDevice = alcOpenDevice(0); + mAlContext = alcCreateContext(mAlDevice, 0); + if (!mAlDevice || !mAlContext) + { + const char* error = alcGetString(mAlDevice,alcGetError(mAlDevice)); + logError("error while creating audio context: %s", error); + } + else + { + alcMakeContextCurrent(mAlContext); + logDebug("opened sound device `%s'", + alcGetString(mAlDevice, ALC_DEFAULT_DEVICE_SPECIFIER)); + } + + // now load the settings the engine needs - long randomSeed; - if (settings.get("engine.rngseed", randomSeed)) setSeed(randomSeed); - else setSeed(); + Settings& settings = Settings::getInstance(); - double ts = 0.01; - settings.get("engine.timestep", ts); - timestep = Scalar(ts); + unsigned randomSeed; + if (settings.get("rngseed", randomSeed)) srand(randomSeed); + else srand(time(0)); - long maxFps = 40; - settings.getNumber("video.maxfps", maxFps); - drawRate = 1.0 / Scalar(maxFps); + Scalar timestep = 80.0; + settings.get("timestep", timestep); + mTimestep = 1.0 / timestep; - printFps = false; - settings.get("video.printfps", printFps); + Scalar maxFps = 40.0; + settings.get("maxfps", maxFps); + mMaxFps = 1.0 / maxFps; + capFps(); - video = Video::alloc(name, iconFile); - video->makeActive(); + settings.get("printfps", mPrintFps); } ~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(); } @@ -110,7 +137,7 @@ public: * the exit code used to stop the loop. */ - int run() + void run() { Scalar ticksNow = Timer::getTicks(); @@ -120,36 +147,36 @@ public: Scalar totalTime = 0.0; Scalar deltaTime = 0.0; - Scalar accumulator = timestep; + Scalar accumulator = mTimestep; - fps = 0; + mFps = 0; int frameAccum = 0; - running = true; do { Scalar newTicks = Timer::getTicks(); deltaTime = newTicks - ticksNow; ticksNow = newTicks; + // don't slow the animation until 4Hz, which is unplayable anyway if (deltaTime >= 0.25) deltaTime = 0.25; accumulator += deltaTime; Timer::fireIfExpired(ticksNow); + dispatchEvents(); - while (accumulator >= timestep) + while (accumulator >= mTimestep) { - dispatchEvents(); - interface->update(totalTime, timestep); + update(totalTime, mTimestep); - totalTime += timestep; - accumulator -= timestep; + totalTime += mTimestep; + accumulator -= mTimestep; - nextStep += timestep; + nextStep += mTimestep; } if (ticksNow >= nextStep) { - nextStep = ticksNow + timestep; + nextStep = ticksNow + mTimestep; } if (ticksNow >= nextDraw) @@ -158,7 +185,7 @@ public: if (ticksNow >= nextFpsUpdate) // determine the actual fps { - fps = frameAccum; + mFps = frameAccum; frameAccum = 0; nextFpsUpdate += 1.0; @@ -167,33 +194,30 @@ public: nextFpsUpdate = ticksNow + 1.0; } - if (printFps) + if (mPrintFps) { - logInfo("framerate: %d fps", fps); + logInfo("%d fps", mFps); } } - interface->draw(accumulator / timestep); - video->swap(); + draw(accumulator / mTimestep); + mVideo->swap(); - nextDraw += drawRate; + nextDraw += mMaxFps; if (ticksNow >= nextDraw) { // we missed some scheduled draws, so reset the schedule - nextDraw = ticksNow + drawRate; + nextDraw = ticksNow + mMaxFps; } } // be a good citizen and give back what you don't need Timer::sleep(std::min(std::min(nextStep, nextDraw), - Timer::getNextFire()), true); + Timer::getNextFire()), Timer::ACTUAL); } - while (running); - - return exitCode; + while (!mStack.empty()); } - void dispatchEvents() { SDL_Event event; @@ -206,89 +230,248 @@ public: if (event.key.keysym.sym == SDLK_ESCAPE && (SDL_GetModState() & KMOD_CTRL) ) { - exit(0); + // emergency escape + 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; } - interface->handleEvent(event); + handleEvent(event); + } + } + + + void update(Scalar t, Scalar dt) + { + for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt) + { + (*mStackIt)->update(mInterface, t, dt); + } + } + + void draw(Scalar alpha) + { + // FIXME - this will crash if the layer being drawn pops itself + std::list::reverse_iterator it; + for (it = mStack.rbegin(); it != mStack.rend(); ++it) + { + (*it)->draw(mInterface, alpha); + } + } + + void handleEvent(const Event& event) + { + for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt) + { + if ((*mStackIt)->handleEvent(mInterface, event)) break; + } + } + + + void push(LayerP layer) + { + ASSERT(layer && "cannot push null layer"); + mStack.push_front(layer); + logDebug("stack: %d [pushed %X]", mStack.size(), layer.get()); + layer->pushed(mInterface); + } + + LayerP pop() + { + bool fixIt = false; + if (mStack.begin() == mStackIt) fixIt = true; + + LayerP layer = mStack.front(); + mStack.pop_front(); + logDebug("stack: %d [popped %X]", mStack.size(), layer.get()); + layer->popped(mInterface); + + if (fixIt) mStackIt = --mStack.begin(); + + return layer; + } + + LayerP pop(Layer* layer) + { + bool fixIt = false; + + std::list layers; + + std::list::iterator it; + for (it = mStack.begin(); it != mStack.end(); ++it) + { + layers.push_back(*it); + + if (it == mStackIt) fixIt = true; + + if ((*it).get() == layer) + { + ++it; + mStack.erase(mStack.begin(), it); + + for (it = layers.begin(); it != layers.end(); ++it) + { + (*it)->popped(mInterface); + logDebug("stack: %d [popped %X]", mStack.size(), (*it).get()); + } + + if (fixIt) mStackIt = --mStack.begin(); + + return layers.back(); + } + } + + return LayerP(); + } + + void clear() + { + mStack.clear(); + mStackIt = mStack.begin(); + logDebug("stack: 0 [cleared]"); + } + + + void capFps() + { + if (mMaxFps < mTimestep) + { + logWarning("capping maximum fps to timestep (%f)", mTimestep); + mMaxFps = mTimestep; } } - Engine* interface; + Engine& mInterface; + VideoP mVideo; + Dispatch mDispatch; - VideoP video; + ALCdevice* mAlDevice; + ALCcontext* mAlContext; - bool running; - int exitCode; + std::list mStack; + std::list::iterator mStackIt; - Scalar timestep; - Scalar drawRate; + Scalar mTimestep; + Scalar mMaxFps; - long fps; - bool printFps; + int mFps; + bool mPrintFps; }; -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)) {} +Engine::Engine() : + // pass through + mImpl(new Engine::Impl(*this)) {} + +Engine& Engine::getInstance() +{ + static Engine engine; + return engine; +} + + +void Engine::setVideo(VideoP video) +{ + // pass through + mImpl->mVideo = video; +} + +VideoP Engine::getVideo() const +{ + return mImpl->mVideo; +} + + +void Engine::setTimestep(int ts) +{ + mImpl->mTimestep = 1.0 / Scalar(ts); + mImpl->capFps(); +} + +int Engine::getTimestep() const +{ + return int(1.0 / mImpl->mTimestep); +} -Engine::~Engine() {} +void Engine::setMaxFps(int maxFps) +{ + mImpl->mMaxFps = 1.0 / Scalar(maxFps); + mImpl->capFps(); +} -int Engine::run() +int Engine::getMaxFps() const { - return impl_->run(); + return int(1.0 / mImpl->mMaxFps); } -void Engine::stop(int exitCode) + +int Engine::getFps() const { - impl_->running = false; - impl_->exitCode = exitCode; + return mImpl->mFps; } -void Engine::setTimestep(Scalar ts) +void Engine::push(LayerP layer) +{ + // pass through + mImpl->push(layer); +} + +LayerP Engine::pop() { - impl_->timestep = ts; + // pass through + return mImpl->pop(); } -Scalar Engine::getTimestep() +LayerP Engine::pop(Layer* layer) { - return impl_->timestep; + // pass through + return mImpl->pop(layer); } -void Engine::setMaxFrameRate(long maxFps) +void Engine::clear() { - impl_->drawRate = 1.0 / Scalar(maxFps); + // pass through + mImpl->clear(); } -long Engine::getMaxFrameRate() +int Engine::getSize() const { - return long(1.0 / impl_->drawRate); + return mImpl->mStack.size(); } -Video& Engine::getVideo() +void Engine::run() { - return *impl_->video; + // pass through + return mImpl->run(); } -long Engine::getFrameRate() + +Dispatch::Handler Engine::addHandler(const std::string& event, + const Dispatch::Function& callback) { - return impl_->fps; + return mImpl->mDispatch.addHandler(event, callback); } +Dispatch::Handler Engine::addHandler(const std::string& event, + const Dispatch::Function& callback, Dispatch::Handler handler) +{ + return mImpl->mDispatch.addHandler(event, callback, handler); +} -void Engine::update(Scalar t, Scalar dt) {} -void Engine::draw(Scalar alpha) {} -void Engine::handleEvent(const Event& event) {} +void Engine::dispatch(const std::string& event, + const Dispatch::Message* message) +{ + mImpl->mDispatch.dispatch(event, message); +} } // namespace Mf