X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FEngine.cc;h=5d703da15d745110a4caa63d938c6fc7890bcde3;hp=80a203e6989b368a86cb12c0790568fef0bc7b6c;hb=4f62ce947db282f0bbf4d49b3aafb83d7cf51adc;hpb=5250c138b1a692e4e893a8f424d2856e519fd652 diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index 80a203e..5d703da 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -26,20 +26,23 @@ *******************************************************************************/ -#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 "Log.hh" -#include "Random.hh" +#include "Math.hh" #include "Settings.hh" #include "Timer.hh" -#include "Video.hh" namespace Mf { @@ -48,56 +51,84 @@ 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() : + mError(Error::NONE), + mTimestep(0.01), + mFramerate(0.02), + mShowFps(false) { -#if defined(_WIN32) || defined (_WIN64) || defined(__WIN32__) - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) +#if defined(_WIN32) || defined(__WIN32__) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) #else - if (SDL_Init(SDL_INIT_EVERYTHING | SDL_INIT_EVENTTHREAD) != 0) + 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.parseArgs(argc, argv); - settings.loadFromFile(configFile); + 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("engine.rngseed", randomSeed)) setSeed(randomSeed); - else setSeed(); + bool initWithSettings(const Settings& settings) + { + unsigned randomSeed; + if (settings.get("rngseed", randomSeed)) srand(randomSeed); + else srand(time(0)); - double ts = 0.01; - settings.get("engine.timestep", ts); - timestep = Scalar(ts); + Scalar timestep = 80.0; + settings.get("timestep", timestep); + mTimestep = 1.0 / timestep; - long maxFps = 40; - settings.getNumber("video.maxfps", maxFps); - drawRate = 1.0 / Scalar(maxFps); + Scalar framerate = 40.0; + settings.get("framerate", framerate); + mFramerate = 1.0 / framerate; + capFps(); - printFps = false; - settings.get("video.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(); } @@ -110,87 +141,63 @@ public: * the exit code used to stop the loop. */ - int run() + void run() { - Scalar ticksNow = 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; - running = true; do { - Scalar newTicks = getTicks(); - deltaTime = newTicks - ticksNow; - ticksNow = newTicks; - - if (deltaTime >= 0.25) deltaTime = 0.25; - accumulator += deltaTime; + Timer::fireIfExpired(); + dispatchEvents(); - while (accumulator >= timestep) + int i = 0; + while (nextUpdate < Timer::getTicks() && i < MAX_FRAMESKIP) { - dispatchEvents(); - interface->update(totalTime, timestep); + totalTime += mTimestep; + update(totalTime, mTimestep); - totalTime += timestep; - accumulator -= timestep; - - nextStep += timestep; - } - if (ticksNow >= nextStep) - { - nextStep = ticksNow + timestep; + nextUpdate += mTimestep; + ++i; } - if (ticksNow >= nextDraw) + if (nextDraw < (ticks = Timer::getTicks())) { - frameAccum++; + ++frames; + draw((ticks + mTimestep - nextUpdate) * inverseTimestep); + mVideo->swap(); + + nextDraw += mFramerate; - if (ticksNow >= nextFpsUpdate) // determine the actual fps + if (mShowFps && nextSecond < ticks) { - fps = frameAccum; - frameAccum = 0; + mFps = frames; + frames = 0; - nextFpsUpdate += 1.0; - if (ticksNow >= nextFpsUpdate) - { - nextFpsUpdate = ticksNow + 1.0; - } + logInfo << mFps << " fps" << std::endl; - if (printFps) - { - logInfo("framerate: %d fps", fps); - } - } - - interface->draw(accumulator / timestep); - video->swap(); - - 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 - sleep(std::min(nextStep, nextDraw), true); + Timer::sleep(0.0); } - while (running); + while (!mStack.empty()); - return exitCode; + mDispatch.dispatch("engine.stopping"); } - void dispatchEvents() { SDL_Event event; @@ -203,89 +210,245 @@ 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(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(alpha); + } + } + + void handleEvent(const Event& event) + { + for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt) + { + if ((*mStackIt)->handleEvent(event)) break; + } + } + + + void push(LayerP layer) + { + ASSERT(layer && "cannot push null layer"); + mStack.push_front(layer); + logInfo << "stack: " << mStack.size() + << " [pushed " << layer.get() << "]" << std::endl; + layer->pushedOntoEngine(); + } + + LayerP pop() + { + bool fixIt = false; + if (mStack.begin() == mStackIt) fixIt = true; + + LayerP layer = mStack.front(); + mStack.pop_front(); + logInfo << "stack: " << mStack.size() + << " [popped " << layer.get() << "]" << std::endl; + layer->poppedFromEngine(); + + 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)->poppedFromEngine(); + logInfo << "stack: " << mStack.size() + << " [popped " << (*it).get() << "]" << std::endl; + } + + if (fixIt) mStackIt = --mStack.begin(); + + return layers.back(); + } } + + return LayerP(); } + void clear() + { + 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; - VideoP video; + Error mError; - bool running; - int exitCode; + VideoP mVideo; + Dispatch mDispatch; - Scalar timestep; - Scalar drawRate; + ALCdevice* mAlDevice; + ALCcontext* mAlContext; - long fps; - bool printFps; + std::list mStack; + std::list::iterator mStackIt; + + Scalar mTimestep; + Scalar mFramerate; + + int mFps; + bool mShowFps; }; -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) {} -Engine::~Engine() {} +bool Engine::initWithSettings(const Settings& settings) +{ + // pass through + return mImpl->initWithSettings(settings); +} -int Engine::run() +const Error& Engine::getError() const { - return impl_->run(); + // pass through + return mImpl->mError; } -void Engine::stop(int exitCode) +void Engine::clearError() { - impl_->running = false; - impl_->exitCode = exitCode; + // pass through + mImpl->mError.init(Error::NONE); } -void Engine::setTimestep(Scalar ts) +void Engine::setVideo(VideoP video) { - impl_->timestep = ts; + // pass through + mImpl->mVideo = video; } -Scalar Engine::getTimestep() +VideoP Engine::getVideo() const { - return impl_->timestep; + return mImpl->mVideo; } -void Engine::setMaxFrameRate(long maxFps) + +int Engine::getFps() const { - impl_->drawRate = 1.0 / Scalar(maxFps); + return mImpl->mFps; } -long Engine::getMaxFrameRate() + +void Engine::push(LayerP layer) { - return long(1.0 / impl_->drawRate); + // pass through + mImpl->push(layer); } +LayerP Engine::pop() +{ + // pass through + return mImpl->pop(); +} + +LayerP Engine::pop(Layer* layer) +{ + // pass through + return mImpl->pop(layer); +} + +void Engine::clear() +{ + // pass through + mImpl->clear(); +} + +int Engine::getSize() const +{ + return mImpl->mStack.size(); +} + + +void Engine::run() +{ + // pass through + return mImpl->run(); +} + + +Dispatch::Handler Engine::addHandler(const std::string& event, + const Dispatch::Function& callback) +{ + return mImpl->mDispatch.addHandler(event, callback); +} -Video& Engine::getVideo() +Dispatch::Handler Engine::addHandler(const std::string& event, + const Dispatch::Function& callback, Dispatch::Handler handler) { - return *impl_->video; + return mImpl->mDispatch.addHandler(event, callback, handler); } -long Engine::getFrameRate() +void Engine::dispatch(const std::string& event, + const Dispatch::Message* message) { - return impl_->fps; + mImpl->mDispatch.dispatch(event, message); } -void Engine::update(Scalar t, Scalar dt) {} -void Engine::draw(Scalar alpha) {} -void Engine::handleEvent(const Event& event) {} +Engine engine; } // namespace Mf