b) Requirements
-boost
-headers
+boost headers
freealut
libvorbis
Lua
.br
.SH OPTIONS
.PP
-There are a plethora of options available for tweaking various aspects of the
-game. All options can be set either from a configuration file or by passing
-them as arguments.
-.PP
-A
-.B yoink
-configuration file ("yoinkrc") consists of key-value pairs. The format is not
-unlike that of other configuration files you are already familiar with. The
-syntax used is lua.
+Options are set from config files and command-line arguments. A
.B yoink
-looks for configuration files and loads them in this order, the options from
-each subsequent configuration files taking precedence over the same options if
-they exist in previous files.
+configfile ("yoinkrc") consists of key-value pairs. They are loaded in this
+order:
.TP
1. @DATADIR@/yoinkrc
-This is the base configuration file which should be considered read-only. Look
-to this file as an example of the format used for configuration files.
+This is the base config file which should be considered read-only. Look to this
+file as an example of the format used for config files.
.TP
2. /etc/yoinkrc
-This is the system-wide configuration file. Not available on Windows.
+This is the system-wide config file. Not available on Windows.
.TP
3. $HOME/.yoinkrc
-This is your own personal configuration file.
+This is your own personal config file.
.TP
4. $YOINKRC
-This is an optional environment variable you can set to point to a configuration
-file.
-.PP
-Options that are passed as arguments take precedence over options loaded from
-the configuration file(s). This mechanism can be used to play the game with
-temporary settings which you do not intend to retain. Here are some examples of
-passing options on the command-line:
-.PP
-.TP
-yoink fullscreen=true
-Run Yoink with the option
-.I fullscreen
-as true. This will run the game in full-screen mode.
-.TP
-yoink maxfps=60
-Run Yoink with the option
-.I maxfps
-as 60. This will cap the display rate at 60Hz.
+This is an optional environment variable you can set to the path of a config
+file at a non-standard location.
.PP
-You can also set options with array values. Arrays can be passed on the command
-line by surrounding all the parts with curly brackets and separating each part
-by a comma. You may also have to quote the brackets so your shell doesn't parse
-them. For example:
-.TP
-yoink videomode=\\{1024,768\\}
-Run Yoink with the top
-.I videomode
-as the numbers 1024 and 768. The video size will be 1024x768.
-.PP
-Here is a list of some of the options available:
+As usual, options that are passed as arguments take precedence over options
+loaded from the config file(s). Here is a list of some of the options available
+at your disposal:
.TP
.B detail
The level of detail. Possible values are 1, 2, or 3 where 1 means the least
.B videomode
The resolution or size of the window. The value is an array with three number
elements representing the width, height, and bits per pixel that make up the
-video mode. The third number is optional. The default value is {800, 600}.
+video mode. The third number is optional. The default value is {800,600}. You
+may need to escape the curly braces so the shell doesn't parse them.
.PP
This is only a list of the more useful options. You'll have to use the source
to find out about the more esoteric options, but you probably won't need to.
.br
+.SH EXAMPLES
+.PP
+Here are some examples of typical usage:
+.PP
+.TP
+yoink fullscreen=true
+Run Yoink in full-screen mode.
+.TP
+yoink maxfps=60
+Cap the allowable frame-rate to 60Hz.
+.TP
+yoink videomode=\\{1024,768\\}
+Run yoink with a resultion of 1024x768. Notice the escapes for the curly
+braces so the shell doesn't parse them.
.SH ENVIRONMENT
.PP
.B yoink
.B yoink
will look for a file at
.I $HOME/.yoinkrc
-and load it as a configuration file.
+and load it as a config file.
.TP
USER
.B yoink
load your own custom assets rather than the defaults.
.TP
YOINKRC
-If set to a path of a valid configuration file,
+If set to a path of a valid config file,
.B yoink
will load the options from that file, and those options will take precedence
-over options loaded from other configuration files.
+over options loaded from other config files.
.br
.SH NOTES
.PP
option. You can set the timestep to be as low as the your
.I maxfps
option, but it is not recommended to set this lower than the target frame rate.
-Remember the trade-off here is decreased simulation accuracy. Try this to set
-your frame rate to 30Hz and your timestep to 60Hz:
+Remember the trade-off here is decreased simulation accuracy. Try to set your
+maxfps to 30Hz and your timestep to 60Hz:
.PP
-yoink maxfps=30 timestep=maxfps\\*2
+yoink maxfps=30 timestep=60
.TP
3. Decrease the level of rendering detail.
Use the
.SH BUGS
.PP
Although the pixelated graphics are intentional, there are some unintended
-artifacts which are more obvious on certain OpenGL implementations.
+artifacts which are more obvious with certain video drivers.
+.PP
+The robots are not very bright.
.PP
Send bug reports, patches, and love notes to:
.br
Mf::Script script;
std::string filePath = Animation::getPath(getName());
- script.importStandardLibraries();
- importLogScript(script);
+ script.importBaseLibrary();
+ importLogPrintFunction(script);
importAnimationBindings(script);
if (script.doFile(filePath) != Mf::Script::SUCCESS)
--- /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 <sstream>
+
+#include "ErrorHandler.hh"
+
+
+std::string getErrorString(const Mf::Exception& e)
+{
+ std::string str;
+
+ switch(e.code())
+ {
+ case Mf::ErrorCode::FASTEVENTS_INIT:
+ case Mf::ErrorCode::SDL_INIT:
+ str += "An error occurred during SDL initialization: ";
+ str += e.what();
+ return str;
+
+ case Mf::ErrorCode::FILE_NOT_FOUND:
+ str += "A required file (";
+ str += e.what();
+ str += ") could not be found.";
+ return str;
+
+ case Mf::ErrorCode::RESOURCE_NOT_FOUND:
+ str += "A required resource (";
+ str += e.what();
+ str += ") could not be found.";
+ return str;
+
+ case Mf::ErrorCode::SCRIPT_ERROR:
+ str += "An error occurred in a script: ";
+ str == e.what();
+ return str;
+
+ case Mf::ErrorCode::SDL_VIDEOMODE:
+ str += "An error occurred while trying to set up the video mode.";
+ return str;
+
+ case Mf::ErrorCode::UNKNOWN_AUDIO_FORMAT:
+ str += "An error occurred while trying to load an audio file, ";
+ str += e.what();
+ str += ".";
+ return str;
+
+ case Mf::ErrorCode::UNKNOWN_IMAGE_FORMAT:
+ str += "An error occurred while trying to load an image file, ";
+ str += e.what();
+ str += ".";
+ return str;
+ }
+
+ std::ostringstream stream;
+ stream << "An unknown error (code " << e.code() << ") occurred.";
+ return stream.str();
+}
+
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
--- /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.
+
+*******************************************************************************/
+
+#ifndef _ERRORHANDLER_HH_
+#define _ERRORHANDLER_HH_
+
+#include <Moof/Exception.hh>
+
+
+std::string getErrorString(const Mf::Exception& e);
+
+
+#endif // _ERRORHANDLER_HH_
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
#include <Moof/Video.hh>
#include "GameLayer.hh"
+#include "Hud.hh"
#if HAVE_CONFIG_H
#include "config.h"
{
Mf::Scalar z;
- mScript.getGlobalTable().pushField("GetZCoord");
- mScript.push(position[0]);
- mScript.push(position[1]);
- mScript.call(2, 1);
- mScript.getTop().get(z);
- mScript.pop();
+ mState.script.getGlobalTable().pushField("GetZCoord");
+ mState.script.push(position[0]);
+ mState.script.push(position[1]);
+ mState.script.call(2, 1);
+ mState.script.getTop().get(z);
+ mState.script.pop();
return z;
}
void GameLayer::loadSceneLoader()
{
+ mState.script.importStandardLibraries();
+ importLogPrintFunction(mState.script);
+
std::string loaderPath = Scene::getPath("loader");
if (loaderPath == "")
{
throw Mf::Exception(Mf::ErrorCode::RESOURCE_NOT_FOUND, "loader");
}
- Mf::Script::Status status = mScript.doFile(loaderPath);
+ Mf::Script::Status status = mState.script.doFile(loaderPath);
if (status != Mf::Script::SUCCESS)
{
std::string str;
- mScript[-1].get(str);
+ mState.script[-1].get(str);
Mf::logScript("%s", str.c_str());
- throw Mf::Exception(Mf::ErrorCode::SCRIPT_ERROR, str.c_str());
+ throw Mf::Exception(Mf::ErrorCode::SCRIPT_ERROR, str);
}
- mScript.getGlobalTable().pushField("scenes");
- mScript.getTop().get(mSceneList);
- if (mSceneList.size() == 0)
+ mState.script.getGlobalTable().pushField("scenes");
+ mState.script.getTop().get(mState.sceneList);
+ if (mState.sceneList.size() == 0)
{
Mf::logScript("no variable `scenes' within loader");
throw Mf::Exception(Mf::ErrorCode::SCRIPT_ERROR, "no scenes to load");
void GameLayer::advanceScene()
{
- if (mSceneList.size() != 0)
+ if (mState.sceneList.size() != 0)
{
- mScene = Scene::alloc(mSceneList[0]);
- mSceneList.erase(mSceneList.begin());
- mScene->load(mScript);
+ mState.scene = Scene::alloc(mState.sceneList[0]);
+ mState.sceneList.erase(mState.sceneList.begin());
+ mState.scene->load(mState.script);
}
}
loadSceneLoader();
advanceScene(); // load the first scene
- mHeroine = Heroine::alloc();
- mHeroine->animation.startSequence("FlyDiagonallyUp");
+ mState.heroine = Heroine::alloc();
+ mState.heroine->animation.startSequence("FlyDiagonallyUp");
Mf::Scalar a[6] = {0.0, 1.5, -0.5, 3.0, -2.0, 1.0};
- mInterp.init(a, 2.0, Mf::Interpolator::OSCILLATE);
+ mState.interp.init(a, 2.0, Mf::Interpolator::OSCILLATE);
setProjection();
-
- mHud = Hud::alloc();
}
void GameLayer::pushed(Mf::Engine& engine)
{
- engine.push(mHud);
+ engine.push(Hud::alloc(mState));
}
-void GameLayer::update(Mf::Scalar t, Mf::Scalar dt)
+void GameLayer::update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt)
{
- mCamera.update(t, dt);
- mHeroine->update(t, dt);
+ mState.camera.update(t, dt);
+ mState.heroine->update(t, dt);
- mScene->checkForCollision(*mHeroine);
+ mState.scene->checkForCollision(*mState.heroine);
- mCamera.setPosition(Mf::Vector3(-mHeroine->getState().position[0],
- -mHeroine->getState().position[1], -10));
- //mCamera.lookAt(Mf::promote(mHeroine->getState().position));
+ mState.camera.setPosition(Mf::Vector3(-mState.heroine->getState().position[0],
+ -mState.heroine->getState().position[1], -10));
+ //mState.camera.lookAt(Mf::promote(mState.heroine->getState().position));
- //Mf::Vector3 heroinePosition = Mf::promote(mHeroine->getState().position);
+ //Mf::Vector3 heroinePosition = Mf::promote(mState.heroine->getState().position);
//Mf::Sound::setListenerPosition(heroinePosition);
-
- mInterp.update(t, dt);
- mHud->setBar1Progress(mInterp.getState(dt));
- mHud->setBar2Progress(1.0 - mInterp.getState(dt));
}
-void GameLayer::draw(Mf::Scalar alpha) const
+void GameLayer::draw(Mf::Engine& engine, Mf::Scalar alpha) const
{
- mCamera.uploadToGL(alpha);
+ mState.camera.uploadToGL(alpha);
// DRAW THE SCENE
Mf::Texture::resetBind();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- mScene->drawIfVisible(alpha, mCamera.getFrustum());
+ mState.scene->drawIfVisible(alpha, mState.camera.getFrustum());
- mHeroine->setZCoord(getZCoord(mHeroine->getState().position));
- mHeroine->draw(alpha);
+ mState.heroine->setZCoord(getZCoord(mState.heroine->getState().position));
+ mState.heroine->draw(alpha);
}
-bool GameLayer::handleEvent(const Mf::Event& event)
+bool GameLayer::handleEvent(Mf::Engine& engine, const Mf::Event& event)
{
switch (event.type)
{
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_SPACE)
{
- mHeroine->animation.startSequence("Flattened");
+ mState.heroine->animation.startSequence("Flattened");
Mf::logInfo("thump!");
mPunchSound.play();
return true;
}
- else if (event.key.keysym.sym == SDLK_p)
+ else if (event.key.keysym.sym == SDLK_m)
{
mMusic.toggle();
return true;
}
- else if (event.key.keysym.sym == SDLK_y)
+ return mState.heroine->handleEvent(event);
+
+ case SDL_KEYUP:
+ if (event.key.keysym.sym == SDLK_ESCAPE)
{
- Mf::Engine::getInstance().pop();
+ engine.pop(this);
return true;
}
-
- case SDL_KEYUP:
- return mHeroine->handleEvent(event);
+ else if (event.key.keysym.sym == SDLK_h)
+ {
+ engine.push(Hud::alloc(mState));
+ return true;
+ }
+ return mState.heroine->handleEvent(event);
case SDL_MOUSEMOTION:
case SDL_MOUSEBUTTONDOWN:
- mCamera.handleEvent(event);
+ mState.camera.handleEvent(event);
return true;
case SDL_VIDEORESIZE:
- setProjection(Mf::Scalar(event.resize.w), Mf::Scalar(event.resize.h));
+ setProjection(event.resize.w, event.resize.h);
break;
}
void GameLayer::setProjection()
{
- Mf::Video& video = Mf::Engine::getInstance().getVideo();
- setProjection(video.getWidth(), video.getHeight());
+ Mf::VideoP video = Mf::Engine::getInstance().getVideo();
+ setProjection(video->getWidth(), video->getHeight());
}
void GameLayer::setProjection(Mf::Scalar width, Mf::Scalar height)
{
- mCamera.setProjection(cml::rad(60.0), width / height, 1.0, 200.0);
+ mState.camera.setProjection(cml::rad(60.0), width / height, 1.0, 200.0);
}
#include <boost/shared_ptr.hpp>
#include <Moof/Camera.hh>
-#include <Moof/Dispatcher.hh>
#include <Moof/Interpolator.hh>
#include <Moof/Layer.hh>
#include <Moof/Math.hh>
#include "Character.hh"
#include "Heroine.hh"
-#include "Hud.hh"
#include "Scene.hh"
void pushed(Mf::Engine& engine);
- void update(Mf::Scalar t, Mf::Scalar dt);
- void draw(Mf::Scalar alpha) const;
- bool handleEvent(const Mf::Event& event);
+ void update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt);
+ void draw(Mf::Engine& engine, Mf::Scalar alpha) const;
+ bool handleEvent(Mf::Engine& engine, const Mf::Event& event);
+
+ struct State
+ {
+ // the script object must be mutable because some script functions must be
+ // called during draw
+ mutable Mf::Script script;
+ std::vector<std::string> sceneList;
+
+ HeroineP heroine;
+ SceneP scene;
+
+ Mf::PolynomialInterpolator<5> interp;
+
+ Mf::Camera camera;
+ };
private:
void setProjection();
void setProjection(Mf::Scalar width, Mf::Scalar height);
-
- // the script object must be mutable because some script functions must be
- // called during draw
- mutable Mf::Script mScript;
- std::vector<std::string> mSceneList;
-
- Mf::Sound mMusic;
- Mf::Sound mPunchSound;
-
- HeroineP mHeroine;
- SceneP mScene;
-
- Mf::PolynomialInterpolator<5> mInterp;
-
- Mf::Camera mCamera;
-
- HudP mHud;
+ State mState;
+ Mf::Sound mMusic;
+ Mf::Sound mPunchSound;
};
*******************************************************************************/
+#include <Moof/Engine.hh>
#include <Moof/OpenGL.hh>
+#include <Moof/Video.hh>
#include "Hud.hh"
-#include <iostream>
-
ProgressBar::ProgressBar(const Tilemap& tilemap, Tilemap::Index index) :
mProgress(0.0),
}
-Hud::Hud() :
+Hud::Hud(GameLayer::State& state) :
+ mState(state),
mBar1(Tilemap("StatusBars"), 0),
mBar2(Tilemap("StatusBars"), 2),
mFont("Font")
{
- resize(800, 600);
+ Mf::VideoP video = Mf::Engine::getInstance().getVideo();
+ resize(video->getWidth(), video->getHeight());
}
}
-void Hud::draw(Mf::Scalar alpha) const
+void Hud::update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt)
+{
+ mState.interp.update(t, dt);
+ setBar1Progress(mState.interp.getState(dt));
+ setBar2Progress(1.0 - mState.interp.getState(dt));
+}
+
+void Hud::draw(Mf::Engine& engine, Mf::Scalar alpha) const
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glPopMatrix();
}
-bool Hud::handleEvent(Mf::Event& event)
+bool Hud::handleEvent(Mf::Engine& engine, const Mf::Event& event)
{
switch (event.type)
{
+ case SDL_KEYUP:
+ if (event.key.keysym.sym == SDLK_h)
+ {
+ // don't want the hud anymore
+ engine.pop(this);
+ return true;
+ }
+ break;
+
case SDL_VIDEORESIZE:
resize(event.resize.w, event.resize.h);
break;
#include <Moof/Math.hh>
#include <Moof/Rectangle.hh>
+#include "GameLayer.hh"
#include "Tilemap.hh"
{
public:
- Hud();
+ Hud(GameLayer::State& state);
- static HudP alloc()
+ static HudP alloc(GameLayer::State& state)
{
- return HudP(new Hud);
+ return HudP(new Hud(state));
}
void setBar1Progress(Mf::Scalar progress)
void resize(int width, int height);
- void draw(Mf::Scalar alpha = 0.0) const;
- bool handleEvent(Mf::Event& event);
+ void update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt);
+ void draw(Mf::Engine& engine, Mf::Scalar alpha = 0.0) const;
+ bool handleEvent(Mf::Engine& engine, const Mf::Event& event);
private:
+ GameLayer::State& mState;
+
ProgressBar mBar1;
ProgressBar mBar2;
#include <string>
#include <unistd.h> // access
-#include <Moof/Dispatcher.hh>
-#include <Moof/Exception.hh>
#include <Moof/Log.hh>
#include <Moof/ModalDialog.hh>
#include <Moof/OpenGL.hh>
#include <Moof/Resource.hh>
+#include <Moof/Settings.hh>
#include <Moof/Transition.hh>
#include <Moof/Video.hh>
+#include "ErrorHandler.hh"
#include "GameLayer.hh"
#include "MainLayer.hh"
#include "TitleLayer.hh"
MainLayer::MainLayer()
{
- Mf::dispatcher::addHandler("video.context_recreated",
- boost::bind(&MainLayer::contextRecreated, this, _1), this);
+ mDispatchHandler = Mf::Engine::getInstance().addHandler("video.newcontext",
+ boost::bind(&MainLayer::contextRecreated, this));
setupGL();
}
-MainLayer::~MainLayer()
-{
- Mf::dispatcher::removeHandler(this);
-}
-
-
void MainLayer::pushed(Mf::Engine& engine)
{
- mEngine = &engine;
-
//Mf::Scalar coeff[] = {0.0, 1.0};
//Mf::Lerp interp(coeff, 0.25);
//Mf::Transition<Mf::Lerp>::alloc(gameLayer, Mf::LayerP(), interp);
//engine->push(transition);
//engine->push(GameLayer::alloc());
- mEngine->push(TitleLayer::alloc());
+ engine.push(TitleLayer::alloc());
}
-void MainLayer::draw(Mf::Scalar alpha) const
+void MainLayer::update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt)
+{
+ if (engine.getSize() == 1)
+ {
+ // this is the only layer left on the stack
+ engine.push(TitleLayer::alloc());
+ }
+}
+
+void MainLayer::draw(Mf::Engine& engine, Mf::Scalar alpha) const
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
}
-bool MainLayer::handleEvent(const Mf::Event& event)
+bool MainLayer::handleEvent(Mf::Engine& engine, const Mf::Event& event)
{
switch (event.type)
{
- case SDL_KEYDOWN:
+ case SDL_KEYUP:
if (event.key.keysym.sym == SDLK_ESCAPE)
{
- quit();
+ engine.clear();
}
else if (event.key.keysym.sym == SDLK_f)
{
- mEngine->getVideo().toggleFull();
+ engine.getVideo()->toggleFull();
}
else if (event.key.keysym.sym == SDLK_l)
{
- Mf::Video& video = mEngine->getVideo();
- video.toggleCursorGrab();
- video.toggleCursorVisible();
- }
- else if (event.key.keysym.sym == SDLK_y)
- {
- mEngine->push(GameLayer::alloc());
+ Mf::VideoP video = engine.getVideo();
+ video->toggleCursorGrab();
+ video->toggleCursorVisible();
}
break;
break;
case SDL_QUIT:
- quit();
+ engine.clear();
break;
}
return false;
}
-void MainLayer::quit()
-{
- // remove all the layers
- mEngine->clear();
-}
-
void MainLayer::setupGL()
{
glMatrixMode(GL_MODELVIEW);
}
-void MainLayer::contextRecreated(const Mf::Notification* note)
+void MainLayer::contextRecreated()
{
// whenever the context is destroyed and a new one created, it probably
// won't contain our state so we need to set that up again
}
}
+
std::cout << std::endl << PACKAGE_STRING << std::endl
<< "Compiled " << __TIME__ " " __DATE__ << std::endl
<< "Send patches and bug reports to <"
Mf::Resource::addSearchPath(YOINK_DATADIR);
- std::string iconFile = Mf::Resource::getPath(PACKAGE".png");
-
// Build the list of config files to search for, in this order:
// 1. YOINK_DATADIR/yoinkrc
- // 2. /etc/yoinkrc
+ // 2. /etc/yoinkrc (not for Windows)
// 3. $HOME/.yoinkrc
// 4. YOINKRC (environment)
std::string configFiles;
configFiles += Mf::Resource::getPath("yoinkrc");
- configFiles += ":/etc/yoinkrc:$HOME/.yoinkrc";
+#if !defined(_WIN32) && !defined(__WIN32__)
+ configFiles += ":/etc/yoinkrc";
+#endif
+ configFiles += ":$HOME/.yoinkrc";
char* configFile = getenv("YOINKRC");
if (configFile)
configFiles += configFile;
}
+ Mf::Settings& settings = Mf::Settings::getInstance();
+ settings.loadFromFile(configFiles);
+ settings.parseArgs(argc, argv);
+
+ std::string iconFile = Mf::Resource::getPath(PACKAGE".png");
+
+
try
{
- Mf::Engine app(argc, argv, PACKAGE_STRING, iconFile, configFiles);
+ Mf::Engine& app = Mf::Engine::getInstance();
+ app.setVideo(Mf::Video::alloc(PACKAGE_STRING, iconFile));
app.push(MainLayer::alloc());
app.run();
}
catch (const Mf::Exception& e)
{
- Mf::logError("unhandled exception (code %d): \"%s\"",
- e.code(), e.what());
-
Mf::ModalDialog dialog;
dialog.title = PACKAGE_STRING;
dialog.text1 = "Unhandled Exception";
- dialog.text2 = e.what();
+ dialog.text2 = getErrorString(e);
dialog.type = Mf::ModalDialog::CRITICAL;
dialog.run();
#include <boost/shared_ptr.hpp>
+#include <Moof/Dispatch.hh>
#include <Moof/Engine.hh>
#include <Moof/Layer.hh>
#include <Moof/Math.hh>
public:
MainLayer();
- ~MainLayer();
static MainLayerP alloc()
{
void pushed(Mf::Engine& engine);
- void draw(Mf::Scalar alpha) const;
- bool handleEvent(const Mf::Event& event);
-
- void quit();
+ void update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt);
+ void draw(Mf::Engine& engine, Mf::Scalar alpha) const;
+ bool handleEvent(Mf::Engine& engine, const Mf::Event& event);
private:
* Set OpenGL to a state we can know and depend on.
*/
void setupGL();
- void contextRecreated(const Mf::Notification* note);
+ void contextRecreated();
- Mf::Engine* mEngine;
+ Mf::Dispatch::Handler mDispatchHandler;
};
Moof/ConvertUTF.c \
Moof/ConvertUTF.h \
Moof/Cullable.hh \
- Moof/Dispatcher.cc \
- Moof/Dispatcher.hh \
+ Moof/Dispatch.cc \
+ Moof/Dispatch.hh \
Moof/Drawable.hh \
Moof/Engine.cc \
Moof/Engine.hh \
Animation.hh \
Character.cc \
Character.hh \
+ ErrorHandler.cc \
+ ErrorHandler.hh \
GameLayer.cc \
GameLayer.hh \
Heroine.cc \
#include <map>
-#include "Dispatcher.hh"
+#include "Dispatch.hh"
namespace Mf {
-class Dispatcher::Impl
+class Dispatch::Impl
{
- friend class Dispatcher;
+public:
Impl() :
- mId(1) {}
+ mId(0) {}
- Dispatcher::Handler getNewHandler()
+ Dispatch::Handler getNewHandler()
{
- mId += 2;
- return (Dispatcher::Handler)mId;
+ ++mId;
+ //return Dispatch::Handler(this, mId);
+ Dispatch::Handler handler(this, mId);
+ return handler;
}
- typedef std::pair<Dispatcher::Handler,Dispatcher::Function> Callback;
- typedef std::multimap<std::string,Callback> CallbackLookup;
- typedef CallbackLookup::iterator CallbackIter;
+ typedef std::pair<unsigned,Dispatch::Function> Callback;
+ typedef std::multimap<std::string,Callback> CallbackLookup;
+ typedef CallbackLookup::iterator CallbackIter;
- typedef std::multimap<Dispatcher::Handler,std::string> HandlerLookup;
- typedef HandlerLookup::iterator HandlerIter;
+ typedef std::multimap<unsigned,std::string> HandlerLookup;
+ typedef HandlerLookup::iterator HandlerIter;
- inline Handler addHandler(const std::string& message,
- const Function& callback, Handler id)
+ inline Handler addHandler(const std::string& event,
+ const Function& callback, Handler handler)
{
- mCallbacks.insert(std::make_pair(message, std::make_pair(id, callback)));
- mHandlers.insert(std::make_pair(id, message));
+ mCallbacks.insert(std::make_pair(event,
+ std::make_pair(handler.getId(), callback)));
+ mHandlers.insert(std::make_pair(handler.getId(), event));
- return id;
+ return handler;
}
- inline void removeHandler(Handler id)
+ inline void removeHandler(unsigned id)
{
std::pair<HandlerIter,HandlerIter> matching(mHandlers.equal_range(id));
mHandlers.erase(id);
}
- void dispatch(const std::string& message, const Notification* param)
+ void dispatch(const std::string& event, const Message* message)
{
std::pair<CallbackIter,CallbackIter>
- callbacks(mCallbacks.equal_range(message));
+ callbacks(mCallbacks.equal_range(event));
for (CallbackIter it = callbacks.first; it != callbacks.second; ++it)
{
Function callback = (*it).second.second;
- callback(param);
+ callback(message);
}
}
- unsigned long mId;
+ unsigned mId;
CallbackLookup mCallbacks;
HandlerLookup mHandlers;
};
-Dispatcher::Dispatcher() :
- mImpl(new Dispatcher::Impl) {}
+Dispatch::Handler::~Handler()
+{
+ if (mId)
+ {
+ mDispatch->removeHandler(mId);
+ }
+}
+
+
+Dispatch::Dispatch() :
+ mImpl(new Dispatch::Impl) {}
-Dispatcher::~Dispatcher() {}
+Dispatch::~Dispatch() {}
-Dispatcher& Dispatcher::getInstance()
+Dispatch& Dispatch::getInstance()
{
- static Dispatcher dispatcher;
- return dispatcher;
+ static Dispatch dispatch;
+ return dispatch;
}
-Dispatcher::Handler Dispatcher::addHandler(const std::string& message,
+Dispatch::Handler Dispatch::addHandler(const std::string& event,
const Function& callback)
{
- return addHandler(message, callback, mImpl->getNewHandler());
+ return addHandler(event, callback, mImpl->getNewHandler());
}
-Dispatcher::Handler Dispatcher::addHandler(const std::string& message,
- const Function& callback, Handler id)
+Dispatch::Handler Dispatch::addHandler(const std::string& event,
+ const Function& callback, Handler handler)
{
// pass through
- return mImpl->addHandler(message, callback, id);
+ return mImpl->addHandler(event, callback, handler);
}
-void Dispatcher::removeHandler(Handler id)
+void Dispatch::removeHandler(unsigned id)
{
// pass through
return mImpl->removeHandler(id);
}
-void Dispatcher::dispatch(const std::string& message, const Notification* param)
+void Dispatch::dispatch(const std::string& event, const Message* message)
{
// pass through
- mImpl->dispatch(message, param);
+ mImpl->dispatch(event, message);
}
*******************************************************************************/
-#ifndef _MOOF_DISPATCHER_HH_
-#define _MOOF_DISPATCHER_HH_
+#ifndef _MOOF_DISPATCH_HH_
+#define _MOOF_DISPATCH_HH_
#include <string>
/**
- * Interface for a notification class.
+ * Dispatcher of messages to interested parties.
*/
-class Notification
+class Dispatch
{
+ class Impl;
+ boost::shared_ptr<Impl> mImpl;
+
+ void removeHandler(unsigned id);
+
public:
- virtual ~Notification() {};
-};
+ /**
+ * Interface for a notification class.
+ */
-/**
- * Dispatcher of notifications to interested parties.
- */
+ class Message
+ {
+ public:
+ virtual ~Message() {};
+ };
-class Dispatcher
-{
- class Impl;
- boost::shared_ptr<Impl> mImpl;
-public:
+ class Handler
+ {
+ public:
- // TODO - the Handler would be even better as an object which automagically
- // removes itself from the dispatcher on destruction, so users don't have to
- // worry about forgetting
- typedef void* Handler;
- typedef boost::function<void(const Notification*)> Function;
+ Handler() :
+ mDispatch(0),
+ mId(0) {}
- Dispatcher();
- ~Dispatcher();
+ Handler(Impl* dispatch, unsigned id) :
+ mDispatch(dispatch),
+ mId(id) {}
- // get global instance
- static Dispatcher& getInstance();
+ Handler(const Handler& handler) :
+ mDispatch(handler.mDispatch),
+ mId(handler.mId)
+ {
+ handler.mId = 0;
+ }
- Handler addHandler(const std::string& message, const Function& callback);
- Handler addHandler(const std::string& message, const Function& callback,
- Handler id);
+ ~Handler();
- void removeHandler(Handler id);
+ Handler& operator = (const Handler& handler)
+ {
+ mDispatch = handler.mDispatch;
+ mId = handler.mId;
+ handler.mId = 0;
+ return *this;
+ }
- void dispatch(const std::string& message, const Notification* param = 0);
-};
+ unsigned getId() const
+ {
+ return mId;
+ }
+
+ private:
+ Impl* mDispatch;
+ mutable unsigned mId;
-namespace dispatcher {
+ };
-inline Dispatcher::Handler addHandler(const std::string& message,
- const Dispatcher::Function& callback)
-{
- return Dispatcher::getInstance().addHandler(message, callback);
-}
+ typedef boost::function<void(const Message*)> Function;
-inline Dispatcher::Handler addHandler(const std::string& message,
- const Dispatcher::Function& callback, Dispatcher::Handler id)
-{
- return Dispatcher::getInstance().addHandler(message, callback, id);
-}
-inline void removeHandler(Dispatcher::Handler id)
-{
- Dispatcher::getInstance().removeHandler(id);
-}
+ Dispatch();
+ ~Dispatch();
-inline void dispatch(const std::string& message, const Notification* param = 0)
-{
- Dispatcher::getInstance().dispatch(message, param);
-}
+ // create and/or get a global instance
+ static Dispatch& getInstance();
-} // namespace dispatcher
+ Handler addHandler(const std::string& event, const Function& callback);
+ Handler addHandler(const std::string& event, const Function& callback,
+ Handler handler);
+
+ void dispatch(const std::string& event, const Message* message = 0);
+};
} // namespace Mf
-#endif // _MOOF_DISPATCHER_HH_
+#endif // _MOOF_DISPATCH_HH_
/** vim: set ts=4 sw=4 tw=80: *************************************************/
#include "fastevents.h"
#include <AL/alut.h>
-#include "Dispatcher.hh"
#include "Engine.hh"
#include "Event.hh"
#include "Exception.hh"
#include "Log.hh"
+#include "Math.hh"
#include "Random.hh"
#include "Settings.hh"
#include "Timer.hh"
-#include "Video.hh"
namespace Mf {
{
public:
- Impl(int argc, char* argv[], const std::string& name,
- const std::string& iconFile, const std::string& configFile,
- Engine& engine) :
+ Impl(Engine& engine) :
mInterface(engine),
mTimestep(0.01),
mPrintFps(false)
{
-#if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
+ // 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
{
const char* error = SDL_GetError();
- logError("sdl is complaining: %s", error);
throw Exception(ErrorCode::SDL_INIT, error);
}
if (FE_Init() != 0)
{
const char* error = FE_GetError();
- logError("fast events error: %s", error);
throw Exception(ErrorCode::FASTEVENTS_INIT, error);
}
- alutInit(&argc, argv);
+ int argc = 1;
+ char name[] = "hello";
+ alutInit(&argc, (char**)&name);
+
+ // now load the settings the engine needs
Settings& settings = Settings::getInstance();
- settings.loadFromFile(configFile);
- settings.parseArgs(argc, argv);
- long randomSeed;
+ unsigned randomSeed;
if (settings.get("rngseed", randomSeed)) setSeed(randomSeed);
else setSeed();
Scalar maxFps = 40.0;
settings.get("maxfps", maxFps);
- mDrawRate = 1.0 / maxFps;
+ mMaxFps = 1.0 / maxFps;
+ capFps();
settings.get("printfps", mPrintFps);
-
- mVideo = Video::alloc(name, iconFile);
- mVideo->makeActive();
}
~Impl()
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 >= mTimestep)
{
- dispatchEvents();
update(totalTime, mTimestep);
totalTime += mTimestep;
draw(accumulator / mTimestep);
mVideo->swap();
- nextDraw += mDrawRate;
+ nextDraw += mMaxFps;
if (ticksNow >= nextDraw)
{
// we missed some scheduled draws, so reset the schedule
- nextDraw = ticksNow + mDrawRate;
+ 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 (!mStack.empty());
}
(SDL_GetModState() & KMOD_CTRL) )
{
// emergency escape
- exit(0);
+ logWarning("escape forced");
+ exit(1);
}
break;
{
for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt)
{
- (*mStackIt)->update(t, dt);
+ (*mStackIt)->update(mInterface, t, dt);
}
}
std::list<LayerP>::reverse_iterator it;
for (it = mStack.rbegin(); it != mStack.rend(); ++it)
{
- (*it)->draw(alpha);
+ (*it)->draw(mInterface, alpha);
}
}
{
for (mStackIt = mStack.begin(); mStackIt != mStack.end(); ++mStackIt)
{
- if ((*mStackIt)->handleEvent(event)) break;
+ if ((*mStackIt)->handleEvent(mInterface, event)) break;
}
}
{
ASSERT(layer && "cannot push null layer");
mStack.push_front(layer);
- logInfo(" push: %d", mStack.size());
+ logDebug("stack: %d [pushed %X]", mStack.size(), layer.get());
layer->pushed(mInterface);
}
bool fixIt = false;
if (mStack.begin() == mStackIt) fixIt = true;
- LayerP popped = mStack.front();
+ LayerP layer = mStack.front();
mStack.pop_front();
- logInfo(" pop: %d", mStack.size());
- popped->popped(mInterface);
+ logDebug("stack: %d [popped %X]", mStack.size(), layer.get());
+ layer->popped(mInterface);
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 = mStack.begin(); it != mStack.end(); ++it)
{
- popped.push_back(*it);
+ layers.push_back(*it);
if (it == mStackIt) fixIt = true;
++it;
mStack.erase(mStack.begin(), it);
- for (it = popped.begin(); it != popped.end(); ++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 popped.back();
+ return layers.back();
}
}
{
mStack.clear();
mStackIt = mStack.begin();
- logInfo("clear: %d", mStack.size());
+ logDebug("stack: 0 [cleared]");
}
- Engine& mInterface;
+ void capFps()
+ {
+ if (mMaxFps < mTimestep)
+ {
+ logWarning("capping maximum fps to timestep (%f)", mTimestep);
+ mMaxFps = mTimestep;
+ }
+ }
+
- VideoP mVideo;
+ Engine& mInterface;
+ VideoP mVideo;
+ Dispatch mDispatch;
std::list<LayerP> mStack;
std::list<LayerP>::iterator mStackIt;
- Scalar mTimestep;
- Scalar mDrawRate;
+ Scalar mTimestep;
+ Scalar mMaxFps;
- long mFps;
- bool mPrintFps;
+ int mFps;
+ bool mPrintFps;
};
-static Engine* instance = 0;
-
-Engine::Engine(int argc, char* argv[], const std::string& name,
- const std::string& iconFile, const std::string& configFile) :
- mImpl(new Engine::Impl(argc, argv, name, iconFile, configFile, *this))
-{
- instance = this;
-}
-
+Engine::Engine() :
+ // pass through
+ mImpl(new Engine::Impl(*this)) {}
Engine& Engine::getInstance()
{
- ASSERT(instance && "dereferencing null pointer");
- return *instance;
- // TODO this has not been completely thought out
- //static Engine engine;
- //return engine;
+ static Engine engine;
+ return engine;
}
-void Engine::run()
+void Engine::setVideo(VideoP video)
{
- return mImpl->run();
+ // pass through
+ mImpl->mVideo = video;
}
-void Engine::setTimestep(Scalar ts)
+VideoP Engine::getVideo() const
{
- mImpl->mTimestep = ts;
+ return mImpl->mVideo;
}
-Scalar Engine::getTimestep() const
+
+void Engine::setTimestep(int ts)
{
- return mImpl->mTimestep;
+ mImpl->mTimestep = 1.0 / Scalar(ts);
+ mImpl->capFps();
}
-void Engine::setMaxFrameRate(long maxFps)
+int Engine::getTimestep() const
{
- mImpl->mDrawRate = 1.0 / Scalar(maxFps);
+ return int(1.0 / mImpl->mTimestep);
}
-long Engine::getMaxFrameRate() const
+
+void Engine::setMaxFps(int maxFps)
{
- return long(1.0 / mImpl->mDrawRate);
+ mImpl->mMaxFps = 1.0 / Scalar(maxFps);
+ mImpl->capFps();
}
-
-Video& Engine::getVideo() const
+int Engine::getMaxFps() const
{
- return *mImpl->mVideo;
+ return int(1.0 / mImpl->mMaxFps);
}
-long Engine::getFrameRate() const
+
+int Engine::getFps() const
{
return mImpl->mFps;
}
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);
+}
+
} // namespace Mf
#include <boost/shared_ptr.hpp>
+#include <Moof/Dispatch.hh>
+#include <Moof/Video.hh>
#include <Moof/Layer.hh>
-#include <Moof/Math.hh>
namespace Mf {
-// forward declarations
-class Video;
+/**
+ * The engine is essentially a stack of layers. While running, it updates each
+ * layer from the bottom up every timestep. It also draws each layer from the
+ * bottom up, adhering to the maximum frame-rate. Events are send to each layer
+ * from the top down until a layer signals the event was handled. The engine is
+ * also responsible for firing timers on time. The engine will continue running
+ * as long as there are layers on the stack.
+ */
class Engine
{
public:
- Engine(int argc, char* argv[], const std::string& name,
- const std::string& iconFile, const std::string& configFile);
~Engine() {}
// get global instance
static Engine& getInstance();
- void run();
+ // setting the video is required before you can run the engine and should
+ // probably be done before adding any layers
+ void setVideo(VideoP video);
+ VideoP getVideo() const;
+
+ void setTimestep(int ts);
+ int getTimestep() const;
+
+ void setMaxFps(int maxFps); // draw rate is always capped at the timestep
+ int getMaxFps() const;
+
+ int getFps() const;
- void setTimestep(Scalar ts);
- Scalar getTimestep() const;
- void setMaxFrameRate(long maxFps);
- long getMaxFrameRate() const;
+ void push(LayerP layer); // push a layer onto the top
+ LayerP pop(); // pop the top layer
+ LayerP pop(Layer* layer); // pops a specific layer and all layers above it
+ void clear(); // remove all layers (the engine will stop)
- Video& getVideo() const;
- long getFrameRate() const;
+ int getSize() const; // get the size of the stack
- void push(LayerP layer);
- LayerP pop();
- // pops a specific layer and all layers above it
- LayerP pop(Layer* layer);
- void clear();
+ // set this machine in motion
+ void run();
+
+ Dispatch::Handler addHandler(const std::string& event,
+ const Dispatch::Function& callback);
+ Dispatch::Handler addHandler(const std::string& event,
+ const Dispatch::Function& callback, Dispatch::Handler handler);
+
+ void dispatch(const std::string& event,
+ const Dispatch::Message* message = 0);
private:
+ Engine(); // use getInstance() to access the engine
+
class Impl;
boost::shared_ptr<Impl> mImpl;
};
#include <cstring>
#include <exception>
+#include <string>
#include <Moof/Math.hh>
{
public:
- explicit Exception(unsigned code, const char* what = "")
+ explicit Exception(unsigned code, const std::string& what = "")
{
mWhat[sizeof(mWhat)-1] = '\0';
- strncpy(mWhat, what, sizeof(mWhat)-1);
+ strncpy(mWhat, what.c_str(), sizeof(mWhat)-1);
mCode = code;
}
virtual ~Exception() throw() {}
SCRIPT_ERROR, // description
SDL_INIT, // description
SDL_VIDEOMODE, // -
- UNKNOWN_AUDIO_FORMAT, // -
- UNKNOWN_IMAGE_FORMAT, // -
+ UNKNOWN_AUDIO_FORMAT, // name of resource
+ UNKNOWN_IMAGE_FORMAT, // name of resource
};
} // namespace ErrorCode
#include <boost/shared_ptr.hpp>
-#include <Moof/Drawable.hh>
#include <Moof/Event.hh>
#include <Moof/Math.hh>
class Engine;
-class Layer : public Drawable
+class Layer
{
public:
virtual void pushed(Engine& engine) {}
virtual void popped(Engine& engine) {}
- virtual void update(Scalar t, Scalar dt) {}
- virtual void draw(Scalar alpha) const {}
- virtual bool handleEvent(const Event& event) { return false; }
+ virtual void update(Engine& engine, Scalar t, Scalar dt) {}
+ virtual void draw(Engine& engine, Scalar alpha) const {}
+ virtual bool handleEvent(Engine& engine, const Event& event)
+ {
+ return false;
+ }
};
typedef boost::shared_ptr<Layer> LayerP;
}
-void importLogScript(Script& script)
+void importLogPrintFunction(Script& script)
{
script.importFunction("print", (int (*)(Script&))logScript);
}
void logScript(const char* fmt, ...);
class Script;
int logScript(Script& script);
-void importLogScript(Script& script);
+void importLogPrintFunction(Script& script);
} // namespace Mf
#include <string>
+#if HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
#if defined(_WIN32) || defined(__WIN32__)
#include <windows.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <QMessageBox>
#endif
+#include <Moof/Log.hh>
#include <Moof/Resource.hh>
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
namespace Mf {
CRITICAL = 3
};
+
std::string title;
Type type;
std::string text1;
std::string text2;
+
void run() const
{
+ switch (type)
+ {
+ case WARNING:
+ logWarning("%s", text1.c_str());
+ logWarning("%s", text2.c_str());
+ break;
+ case CRITICAL:
+ logError("%s", text1.c_str());
+ logError("%s", text2.c_str());
+ break;
+ default:
+ logInfo("%s", text1.c_str());
+ logInfo("%s", text2.c_str());
+ break;
+ }
+
#if USE_GTK
int argc = 0;
Script() :
- mState(luaL_newstate())
+ mState(0)
{
- lua_pushlightuserdata(mState, this);
- lua_setfield(mState, LUA_REGISTRYINDEX, "_script_obj");
+ reset();
}
~Script()
{
- if (mIsMainThread) lua_close(mState);
+ destroy();
}
return ScriptP(new Script);
}
+ void reset()
+ {
+ if (mState) destroy();
+ mState = luaL_newstate();
+ lua_pushlightuserdata(mState, this);
+ lua_setfield(mState, LUA_REGISTRYINDEX, "_script_obj");
+ }
+
void importStandardLibraries()
{
luaL_openlibs(mState);
}
+ void importBaseLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_base);
+ push(LUA_COLIBNAME);
+ call(1, 0);
+ }
+
+ void importPackageLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_package);
+ push(LUA_LOADLIBNAME);
+ call(1, 0);
+ }
+
+ void importStringLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_string);
+ push(LUA_STRLIBNAME);
+ call(1, 0);
+ }
+
+ void importTableLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_table);
+ push(LUA_TABLIBNAME);
+ call(1, 0);
+ }
+
+ void importMathLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_math);
+ push(LUA_MATHLIBNAME);
+ call(1, 0);
+ }
+
+ void importIoLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_io);
+ push(LUA_IOLIBNAME);
+ call(1, 0);
+ }
+
+ void importOsLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_os);
+ push(LUA_OSLIBNAME);
+ call(1, 0);
+ }
+
+ void importDebugLibrary()
+ {
+ lua_pushcfunction(mState, luaopen_debug);
+ push(LUA_DBLIBNAME);
+ call(1, 0);
+ }
+
+
void importFunction(const std::string& name, const Function& function)
{
push(function);
return (*function)(*script);
}
+ void destroy()
+ {
+ if (mIsMainThread) lua_close(mState);
+ }
+
lua_State* mState;
bool mIsMainThread;
std::list<Function> mFunctions;
}
+void Settings::clear()
+{
+ mScript.reset();
+}
+
+
} // namepsace Mf
/** vim: set ts=4 sw=4 tw=80: *************************************************/
mGlobals(mScript.getGlobalTable()),
mTop(mScript[-1])
{
- importLogScript(mScript);
+ mScript.importBaseLibrary();
+ importLogPrintFunction(mScript);
}
// get global instance
void loadFromFile(const std::string& filePath);
void loadFromFiles(const std::vector<std::string>& filePaths);
+ void clear(); // remove all settings
+
template <typename T>
bool get(const std::string& key, T& value);
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
+#include "Engine.hh"
#include "Exception.hh"
#include "Library.hh"
#include "Log.hh"
{
logWarning("error while loading sound %s",
getName().c_str());
- throw Exception(ErrorCode::UNKNOWN_AUDIO_FORMAT);
+ throw Exception(ErrorCode::UNKNOWN_AUDIO_FORMAT, getName());
}
vorbis_info* vorbisInfo = ov_info(&mOggStream, -1);
mFormat = getAudioFormat(vorbisInfo);
mFreq = vorbisInfo->rate;
-
- logDebug(" channels: %d", vorbisInfo->channels);
- logDebug(" frequency: %d", vorbisInfo->rate);
}
if (size == 0)
{
logWarning("decoded no bytes from %s", getName().c_str());
- //throw Exception("file_not_found");
return;
}
void init()
{
+ // make sure the engine is initialized
+ Engine::getInstance();
+
ALfloat zero[] = {0.0f, 0.0f, 0.0f};
alGenSources(1, &mSource);
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
-#include "Dispatcher.hh"
+#include "Dispatch.hh"
+#include "Engine.hh"
#include "Exception.hh"
#include "Library.hh"
#include "Log.hh"
{
if (mObject)
{
- if (mObject == globalObject_)
+ if (mObject == gObject)
{
- globalObject_ = 0;
+ gObject = 0;
}
glDeleteTextures(1, &mObject);
* to cache it if the client has plenty of RAM.
*/
- void contextRecreated(const Notification* note)
+ void contextRecreated()
{
- mObject = globalObject_ = 0;
+ mObject = gObject = 0;
uploadToGL();
}
mWrapT(GL_CLAMP),
mObject(0)
{
- loadFromFile();
+ // make sure the engine is initialized
+ Engine& engine = Engine::getInstance();
+ VideoP video = engine.getVideo();
+ ASSERT(video && "cannot load textures without a current video context");
// we want to know when the GL context is recreated
- Dispatcher::getInstance().addHandler("video.context_recreated",
- boost::bind(&Impl::contextRecreated, this, _1), this);
+ mDispatchHandler = engine.addHandler("video.newcontext",
+ boost::bind(&Impl::contextRecreated, this));
+
+ loadFromFile();
}
~Impl()
}
unloadFromGL();
-
- Dispatcher::getInstance().removeHandler(this);
}
if (!surface)
{
logWarning("texture not found: %s", getName().c_str());
- throw Exception(ErrorCode::FILE_NOT_FOUND, getName().c_str());
+ throw Exception(ErrorCode::FILE_NOT_FOUND, getName());
}
SDL_Surface* temp = prepareImageForGL(surface);
if (!temp)
{
- throw Exception(ErrorCode::UNKNOWN_IMAGE_FORMAT);
+ throw Exception(ErrorCode::UNKNOWN_IMAGE_FORMAT, getName());
}
if (temp->format->BytesPerPixel == 3)
else
{
SDL_FreeSurface(temp);
- throw Exception(ErrorCode::UNKNOWN_IMAGE_FORMAT);
+ throw Exception(ErrorCode::UNKNOWN_IMAGE_FORMAT, getName());
}
mWidth = temp->w;
{
uploadToGL();
}
- if (mObject != globalObject_)
+ if (mObject != gObject)
{
glBindTexture(GL_TEXTURE_2D, mObject);
- globalObject_ = mObject;
+ gObject = mObject;
}
}
- SDL_Surface* mContext;
- unsigned mWidth; ///< Horizontal dimension of the image.
- unsigned mHeight; ///< Vertical dimension.
+ SDL_Surface* mContext;
+ unsigned mWidth; ///< Horizontal dimension of the image.
+ unsigned mHeight; ///< Vertical dimension.
+
+ GLuint mMode; ///< GL_RGB or GL_RGBA.
+ GLuint mMinFilter; ///< Minifcation filter.
+ GLuint mMagFilter; ///< Magnification filter.
+ GLuint mWrapS; ///< Wrapping behavior horizontally.
+ GLuint mWrapT; ///< Wrapping behavior vertically.
- GLuint mMode; ///< Depth of the image, GL_RGB or GL_RGBA.
- GLuint mMinFilter; ///< Minifcation filter.
- GLuint mMagFilter; ///< Magnification filter.
- GLuint mWrapS; ///< Wrapping behavior horizontally.
- GLuint mWrapT; ///< Wrapping behavior vertically.
+ GLuint mObject; ///< GL texture handle.
+ static GLuint gObject; ///< Global GL texture handle.
- GLuint mObject; ///< GL texture handle.
- static GLuint globalObject_; ///< Global GL texture handle.
+ Dispatch::Handler mDispatchHandler;
};
-GLuint Texture::Impl::globalObject_ = 0;
+GLuint Texture::Impl::gObject = 0;
Texture::Texture(const std::string& name) :
void Texture::resetBind()
{
glBindTexture(GL_TEXTURE_2D, 0);
- Impl::globalObject_ = 0;
+ Impl::gObject = 0;
}
{
mFunction = function;
- if (mode == ABSOLUTEE)
+ if (mode == ACTUAL)
{
mAbsolute = seconds;
}
return Scalar(ts.tv_sec - reference) + Scalar(ts.tv_nsec) / 1000000000.0;
}
-void Timer::sleep(Scalar seconds, bool absolute)
+void Timer::sleep(Scalar seconds, Mode mode)
{
struct timespec ts;
int ret;
- if (absolute) seconds -= getTicks();
+ if (mode == ACTUAL) seconds -= getTicks();
ts.tv_sec = time_t(seconds);
ts.tv_nsec = long((seconds - Scalar(ts.tv_sec)) * 1000000000.0);
return Scalar(ms / 1000) + Scalar(ms % 1000) / 1000.0;
}
-void Timer::sleep(Scalar seconds, bool absolute)
+void Timer::sleep(Scalar seconds, Mode mode)
{
- if (absolute) seconds -= getTicks();
+ if (mode == ACTUAL) seconds -= getTicks();
SDL_Delay(Uint32(cml::clamp(int(seconds * 1000.0), 0, 1000)));
}
{
INVALID = -1,
NORMAL = 0,
- ABSOLUTEE = 1, // the ABSOLUTE keyword isn't available on win32...
+ ACTUAL = 1,
REPEAT = 2
};
* sleep for the requested amount of time (and maybe longer).
*/
- static void sleep(Scalar seconds, bool absolute = false);
+ static void sleep(Scalar seconds, Mode mode = NORMAL);
static Scalar getNextFire()
T mInterp;
- Engine* mEngine;
-
public:
Transition(LayerP t, LayerP f, const T& interp) :
mTo(t),
mFrom(f),
- mInterp(interp),
- mEngine(0) {}
+ mInterp(interp) {}
typedef boost::shared_ptr<Transition> Ptr;
}
- void pushed(Engine& engine)
- {
- mEngine = &engine;
- }
-
void popped(Engine& engine)
{
if (mTo) engine.push(mTo);
}
- void update(Scalar t, Scalar dt)
+ void update(Engine& engine, Scalar t, Scalar dt)
{
mInterp.update(t, dt);
- if (mFrom) mFrom->update(t, dt);
- if (mTo) mTo->update(t, dt);
+ if (mFrom) mFrom->update(engine, t, dt);
+ if (mTo) mTo->update(engine, t, dt);
if (mInterp.isDone())
{
// to should /replace/ this
- mEngine->pop(this);
+ engine.pop(this);
}
}
glPopMatrix();
}
- void draw(Scalar alpha) const
+ void draw(Engine& engine, Scalar alpha) const
{
Scalar a = mInterp.getState(alpha);
- logInfo("draw state: %f", a);
+ logDebug("transition state: %f", a);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPushMatrix();
glLoadIdentity();
glRotate(180.0 * a, 0.0, 1.0, 0.0);
- mFrom->draw(alpha);
+ mFrom->draw(engine, alpha);
glPopMatrix();
}
//drawFade(a);
glPushMatrix();
glLoadIdentity();
glRotate(180.0 * (1.0 - a), 0.0, 1.0, 0.0);
- mTo->draw(alpha);
+ mTo->draw(engine, alpha);
glPopMatrix();
}
//drawFade(1.0 - a);
}
- bool handleEvent(const Event& event)
+ bool handleEvent(Engine& engine, const Event& event)
{
if (mTo)
{
- return mTo->handleEvent(event);
+ return mTo->handleEvent(engine, event);
}
else if (mFrom)
{
- return mFrom->handleEvent(event);
+ return mFrom->handleEvent(engine, event);
}
return false;
}
#include <SDL/SDL_image.h>
-#include "Dispatcher.hh"
+#include "Dispatch.hh"
+#include "Engine.hh"
#include "Exception.hh"
#include "Log.hh"
#include "Settings.hh"
void Video::init(const Attributes& attribs)
{
+ // make sure the engine is initialized before setting up the video
+ Engine::getInstance();
+
mContext = 0;
mFlags = 0;
mAttribs = attribs;
// on win32, creating a new context via SDL_SetVideoMode will wipe
// out the GL state, so we gotta notify everyone to reload their
// state after the change
- Mf::dispatcher::dispatch("video.context_recreated");
+ Engine::getInstance().dispatch("video.newcontext");
+
logInfo("video context recreated");
#endif
}
return mAttribs.caption;
}
+const std::string& Video::getIcon() const
+{
+ return mAttribs.icon;
+}
+
void Video::setFull(bool full)
{
}
-void Video::makeActive()
-{
- // NOP until the day SDL supports more than only one window.
- // Still waiting...
-}
-
void Video::swap()
{
SDL_GL_SwapBuffers();
void setCaption(const std::string& caption);
std::string getCaption() const;
+ const std::string& getIcon() const;
+
void setFull(bool full);
void toggleFull();
bool isFull() const;
void toggleCursorGrab();
bool isCursorGrab() const;
- void makeActive();
void swap();
int getWidth() const;
std::string filePath = Tilemap::getPath(getName());
script.importStandardLibraries();
- importLogScript(script);
+ importLogPrintFunction(script);
bindScriptConstants(script);
if (script.doFile(filePath) != Mf::Script::SUCCESS)
void TitleLayer::pushed(Mf::Engine& engine)
{
- mEngine = &engine;
-
Mf::Scalar coeff[] = {0.0, 1.0};
mFadeIn.init(coeff, 0.1);
mGameLayer = GameLayer::alloc();
}
-void TitleLayer::update(Mf::Scalar t, Mf::Scalar dt)
+void TitleLayer::update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt)
{
if (!mFadeIn.isDone()) mFadeIn.update(t, dt);
}
-void TitleLayer::draw(Mf::Scalar alpha) const
+void TitleLayer::draw(Mf::Engine& engine, Mf::Scalar alpha) const
{
glClearColor(0.0, 0.0, mFadeIn.getState(alpha), 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
-bool TitleLayer::handleEvent(const Mf::Event& event)
+bool TitleLayer::handleEvent(Mf::Engine& engine, const Mf::Event& event)
{
switch (event.type)
{
case SDL_KEYUP:
- Mf::LayerP titleLayer = mEngine->pop(this);
- //mEngine->pushLayer(GameLayer::alloc());
+ //if (event.key.keysym.sym == SDLK_ESCAPE)
+ //{
+ //break;
+ //}
+
+ Mf::LayerP titleLayer = engine.pop(this);
+ //engine.pushLayer(GameLayer::alloc());
- Mf::Scalar coeff[] = {0.0, 1.0};
- Mf::Lerp interp(coeff, 0.2);
+ Mf::Scalar coeff[] = {0.0, 0.75, 0.99, 1.0};
+ Mf::PolynomialInterpolator<3> interp(coeff, 0.1);
//Mf::LayerP mGameLayer = GameLayer::alloc();
- Mf::Transition<Mf::Lerp>::Ptr transition =
- Mf::Transition<Mf::Lerp>::alloc(mGameLayer, titleLayer, interp);
- mEngine->push(transition);
+ Mf::Transition<Mf::PolynomialInterpolator<3> >::Ptr transition =
+ Mf::Transition<Mf::PolynomialInterpolator<3> >::alloc(mGameLayer, titleLayer, interp);
+ engine.push(transition);
return true;
}
void pushed(Mf::Engine& engine);
- void update(Mf::Scalar t, Mf::Scalar dt);
- void draw(Mf::Scalar alpha) const;
- bool handleEvent(const Mf::Event& event);
+ void update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt);
+ void draw(Mf::Engine& engine, Mf::Scalar alpha) const;
+ bool handleEvent(Mf::Engine& engine, const Mf::Event& event);
private:
Mf::Lerp mFadeIn;
- Mf::Engine* mEngine;
-
Mf::LayerP mGameLayer;
};