X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FEngine.cc;h=5d703da15d745110a4caa63d938c6fc7890bcde3;hp=bcc336c1244f1f8b0a8ed041507c4b5f3e0f7834;hb=4f62ce947db282f0bbf4d49b3aafb83d7cf51adc;hpb=c2321281bf12a7efaedde930422c7ddbc92080d4 diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index bcc336c..5d703da 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -26,65 +26,108 @@ *******************************************************************************/ -#include // exit -#include -#include +#include +#include // exit, srand +#include // time +#include #include +#include #include #include "fastevents.h" -#include "Dispatcher.hh" + #include "Engine.hh" -#include "Random.hh" +#include "Event.hh" +#include "Log.hh" +#include "Math.hh" #include "Settings.hh" #include "Timer.hh" -#include "Video.hh" namespace Mf { -class Engine::EngineImpl +class Engine::Impl { public: - EngineImpl(const std::string& name, int argc, char* argv[], - const std::string& configFile, Engine* outer) : - settings(argc, argv), - interface(outer) + + Impl() : + mError(Error::NONE), + mTimestep(0.01), + mFramerate(0.02), + mShowFps(false) { - if (SDL_Init(SDL_INIT_EVERYTHING | SDL_INIT_EVENTTHREAD) != 0) +#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 + { + const char* error = SDL_GetError(); + mError.init(Error::SDL_INIT, error); + return; // fatal + } + else { - throw std::runtime_error(SDL_GetError()); + char name[128]; + SDL_VideoDriverName(name, sizeof(name)); + logInfo << "initialized SDL; using video driver `" + << name << "'" << std::endl; } + if (FE_Init() != 0) { - throw std::runtime_error(FE_GetError()); + const char* error = FE_GetError(); + mError.init(Error::FASTEVENTS_INIT, error); + return; // fatal } - setSeed(); + 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; + } + } - settings.loadFromFile(configFile); + bool initWithSettings(const Settings& settings) + { + unsigned randomSeed; + if (settings.get("rngseed", randomSeed)) srand(randomSeed); + else srand(time(0)); - video = VideoPtr(new Video(name)); - video->makeActive(); + Scalar timestep = 80.0; + settings.get("timestep", timestep); + mTimestep = 1.0 / timestep; - double ts = 0.01; - settings.get("engine.timestep", ts); - timestep = Scalar(ts); + Scalar framerate = 40.0; + settings.get("framerate", framerate); + mFramerate = 1.0 / framerate; + capFps(); - long maxFps = 40; - settings.getNumber("video.maxfps", maxFps); - drawRate = 1.0 / Scalar(maxFps); + mShowFps = false; + settings.get("showfps", mShowFps); - printFps = false; - settings.get("video.printfps", printFps); + return true; } - ~EngineImpl() + ~Impl() { - // The video object must be destroyed before we can shutdown SDL. - video.reset(); + // the video object must be destroyed before we can shutdown SDL + mVideo.reset(); + + alcMakeContextCurrent(0); + alcDestroyContext(mAlContext); + alcCloseDevice(mAlDevice); FE_Quit(); SDL_Quit(); @@ -95,86 +138,66 @@ public: * 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 - * with a value of 0 if the member variable running becomes true. + * 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 += timestep; - accumulator -= timestep; + totalTime += mTimestep; + update(totalTime, mTimestep); - nextStep += timestep; + nextUpdate += mTimestep; + ++i; } - if (ticksNow >= nextDraw) + if (nextDraw < (ticks = Timer::getTicks())) { - frameAccum++; + ++frames; + draw((ticks + mTimestep - nextUpdate) * inverseTimestep); + mVideo->swap(); - if (ticksNow >= nextFpsUpdate) // determine the actual fps - { - fps = frameAccum; - frameAccum = 0; - - nextFpsUpdate += 1.0; - if (ticksNow >= nextFpsUpdate) - { - nextFpsUpdate = ticksNow + 1.0; - } + nextDraw += mFramerate; - if (printFps) - { - std::cout << "FPS: " << fps << std::endl; - } - } + if (mShowFps && nextSecond < ticks) + { + mFps = frames; + frames = 0; - interface->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 - sleep(std::min(nextStep, nextDraw), true); + Timer::sleep(0.0); } - while (running); + while (!mStack.empty()); - return 0; + mDispatch.dispatch("engine.stopping"); } - void dispatchEvents() { SDL_Event event; @@ -187,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; + //} } - Settings settings; - Dispatcher dispatcher; - VideoPtr video; + Error mError; + + VideoP mVideo; + Dispatch mDispatch; - bool running; + ALCdevice* mAlDevice; + ALCcontext* mAlContext; - Scalar timestep; - Scalar drawRate; + std::list mStack; + std::list::iterator mStackIt; - long fps; - bool printFps; + Scalar mTimestep; + Scalar mFramerate; - Engine* interface; + int mFps; + bool mShowFps; }; -Engine::Engine(const std::string& name, int argc, char* argv[], - const std::string& configFile) : - impl_(new Engine::EngineImpl(name, argc, argv, configFile, 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() +void Engine::clearError() { - impl_->running = false; + // 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