+++ /dev/null
-
-/*******************************************************************************
-
- Copyright (c) 2009, Charles McGarvey
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-#include <algorithm>
-#include <cstdlib> // exit, srand
-#include <ctime> // time
-#include <list>
-#include <string>
-
-#include <AL/alc.h>
-#include <SDL/SDL.h>
-#include "fastevents.h"
-
-
-#include "Engine.hh"
-#include "Event.hh"
-#include "Log.hh"
-#include "Math.hh"
-#include "Settings.hh"
-#include "Timer.hh"
-
-
-namespace Mf {
-
-
-class Engine::Impl
-{
-public:
-
- Impl() :
- mError(Error::NONE),
- mTimestep(0.01),
- mFramerate(0.02),
- mShowFps(false)
- {
-#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
- {
- char name[128];
- SDL_VideoDriverName(name, sizeof(name));
- logInfo << "initialized SDL; using video driver `"
- << name << "'" << std::endl;
- }
-
- if (FE_Init() != 0)
- {
- const char* error = FE_GetError();
- mError.init(Error::FASTEVENTS_INIT, error);
- return; // fatal
- }
-
- 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;
- }
- }
-
- 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);
- mTimestep = 1.0 / timestep;
-
- Scalar framerate = 40.0;
- settings.get("framerate", framerate);
- mFramerate = 1.0 / framerate;
- capFps();
-
- mShowFps = false;
- settings.get("showfps", mShowFps);
-
- return true;
- }
-
- ~Impl()
- {
- // the video object must be destroyed before we can shutdown SDL
- mVideo.reset();
-
- alcMakeContextCurrent(0);
- alcDestroyContext(mAlContext);
- alcCloseDevice(mAlDevice);
-
- FE_Quit();
- SDL_Quit();
- }
-
-
- /**
- * 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
- * the exit code used to stop the loop.
- */
-
- void run()
- {
- Scalar totalTime = 0.0;
- Scalar ticks = Timer::getTicks();
-
- Scalar nextUpdate = ticks;
- Scalar nextDraw = ticks;
- Scalar nextSecond = ticks + SCALAR(1.0);
-
- mFps = 0;
- int frames = 0;
-
- const int MAX_FRAMESKIP = 15;
- const Scalar inverseTimestep = SCALAR(1.0) / mTimestep;
-
- do
- {
- Timer::fireIfExpired();
- dispatchEvents();
-
- int i = 0;
- while (nextUpdate < Timer::getTicks() && i < MAX_FRAMESKIP)
- {
- totalTime += mTimestep;
- update(totalTime, mTimestep);
-
- nextUpdate += mTimestep;
- ++i;
- }
-
- if (nextDraw < (ticks = Timer::getTicks()))
- {
- ++frames;
- draw((ticks + mTimestep - nextUpdate) * inverseTimestep);
- mVideo->swap();
-
- nextDraw += mFramerate;
-
- if (mShowFps && nextSecond < ticks)
- {
- mFps = frames;
- frames = 0;
-
- logInfo << mFps << " fps" << std::endl;
-
- nextSecond += SCALAR(1.0);
- }
- }
-
- // be a good citizen and give back what you don't need
- Timer::sleep(0.0);
- }
- while (!mStack.empty());
-
- mDispatch.dispatch("engine.stopping");
- }
-
- void dispatchEvents()
- {
- SDL_Event event;
-
- while (FE_PollEvent(&event) == 1)
- {
- switch (event.type)
- {
- case SDL_KEYDOWN:
- if (event.key.keysym.sym == SDLK_ESCAPE &&
- (SDL_GetModState() & KMOD_CTRL) )
- {
- // emergency escape
- logWarning("escape forced");
- exit(1);
- }
- break;
-
- case SDL_VIDEORESIZE:
- mVideo->resize(event.resize.w, event.resize.h);
- break;
- }
-
- 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<LayerP>::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<LayerP> layers;
-
- std::list<LayerP>::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;
- //}
- }
-
-
- Error mError;
-
- VideoP mVideo;
- Dispatch mDispatch;
-
- ALCdevice* mAlDevice;
- ALCcontext* mAlContext;
-
- std::list<LayerP> mStack;
- std::list<LayerP>::iterator mStackIt;
-
- Scalar mTimestep;
- Scalar mFramerate;
-
- int mFps;
- bool mShowFps;
-};
-
-
-Engine::Engine() :
- // pass through
- mImpl(new Engine::Impl) {}
-
-
-bool Engine::initWithSettings(const Settings& settings)
-{
- // pass through
- return mImpl->initWithSettings(settings);
-}
-
-const Error& Engine::getError() const
-{
- // pass through
- return mImpl->mError;
-}
-
-void Engine::clearError()
-{
- // pass through
- mImpl->mError.init(Error::NONE);
-}
-
-
-void Engine::setVideo(VideoP video)
-{
- // pass through
- mImpl->mVideo = video;
-}
-
-VideoP Engine::getVideo() const
-{
- return mImpl->mVideo;
-}
-
-
-int Engine::getFps() const
-{
- return mImpl->mFps;
-}
-
-
-void Engine::push(LayerP layer)
-{
- // 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);
-}
-
-Dispatch::Handler Engine::addHandler(const std::string& event,
- const Dispatch::Function& callback, Dispatch::Handler handler)
-{
- return mImpl->mDispatch.addHandler(event, callback, handler);
-}
-
-void Engine::dispatch(const std::string& event,
- const Dispatch::Message* message)
-{
- mImpl->mDispatch.dispatch(event, message);
-}
-
-
-Engine engine;
-
-
-} // namespace Mf
-
-/** vim: set ts=4 sw=4 tw=80: *************************************************/
-