From 892da43bf5796e7c5f593a6d0f53bd797a36bd3e Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Tue, 13 Oct 2009 21:24:26 -0600 Subject: [PATCH] new level-based controllers --- configure.ac | 8 +- cscope.make | 2 +- data/scenes/Classic.lua | 102 +++++----- src/GameLayer.cc | 187 +++++++++++++++++++ src/{YoinkApp.hh => GameLayer.hh} | 39 ++-- src/Hud.cc | 12 ++ src/Hud.hh | 12 +- src/{YoinkApp.cc => MainLayer.cc} | 299 +++++++++--------------------- src/MainLayer.hh | 80 ++++++++ src/Makefile.am | 7 +- src/Moof/Engine.cc | 180 ++++++++++++++---- src/Moof/Engine.hh | 41 ++-- src/Moof/Interpolator.hh | 4 +- src/Moof/Layer.hh | 66 +++++++ src/Moof/Log.cc | 2 +- src/Moof/Log.hh | 1 + src/Moof/Scene.cc | 160 ++++++++-------- src/Moof/Scene.hh | 14 +- src/Moof/Script.hh | 89 ++++++++- src/Moof/Settings.cc | 2 +- 20 files changed, 858 insertions(+), 449 deletions(-) create mode 100644 src/GameLayer.cc rename src/{YoinkApp.hh => GameLayer.hh} (82%) rename src/{YoinkApp.cc => MainLayer.cc} (50%) create mode 100644 src/MainLayer.hh create mode 100644 src/Moof/Layer.hh diff --git a/configure.ac b/configure.ac index 7d8d545..f7e75b0 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ AC_INIT([Yoink], [0.1], [chaz@dogcows.com], [yoink]) AC_CANONICAL_TARGET -AC_CONFIG_SRCDIR([src/YoinkApp.cc]) +AC_CONFIG_SRCDIR([src/GameLayer.cc]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE @@ -153,12 +153,6 @@ AC_DEFINE_UNQUOTED([YOINK_DATADIR], ["$DATADIR"], [Define to path of game asset directory.]) -CONFIGFILES="/etc/yoinkrc:\$HOME/.yoinkrc" - -AC_DEFINE_UNQUOTED([YOINK_CONFIGFILES], ["$CONFIGFILES"], - [Define to colon-delimited configuration file paths.]) - - # # Split the version number into components. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/cscope.make b/cscope.make index 258acca..990b01c 100755 --- a/cscope.make +++ b/cscope.make @@ -10,5 +10,5 @@ find "$current" \ cd "$current" -#cscope -b -q +cscope -b -q diff --git a/data/scenes/Classic.lua b/data/scenes/Classic.lua index 62b8a97..4cae26a 100644 --- a/data/scenes/Classic.lua +++ b/data/scenes/Classic.lua @@ -57,12 +57,12 @@ MakeTilemap({ -- Right side ResetTransform() -Rotate('y', 90) +Rotate(Y, 90) Translate(0, 0, 5) Scale(32) MakeTilemap({ width = 5, - surface_type = 'right', + surface_type = RIGHT, tiles = { 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, @@ -85,12 +85,12 @@ MakeTilemap({ -- Top ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(-5, 15, 0) Scale(32) MakeTilemap({ width = 5, - surface_type = 'top', + surface_type = TOP, tiles = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -125,7 +125,7 @@ if detail > 1 then -- Right side ResetTransform() - Rotate('y', 90) + Rotate(Y, 90) Translate(7, 0, 0) Scale(32) MakeTilemap({ @@ -145,7 +145,7 @@ if detail > 1 then -- Top ResetTransform() - Rotate('x', 90) + Rotate(X, 90) Translate(-2, 8, -6) Scale(32) MakeTilemap({ @@ -167,13 +167,13 @@ end -- Left wall ResetTransform() -Rotate('y', -90) +Rotate(Y, -90) Translate(10, 0, 1) Scale(32) SetTexture("Building") MakeTilemap({ width = 4, - surface_type = 'left', + surface_type = LEFT, tiles = { -1, 9, 11, -1, 9, 10, 12, 11, @@ -186,12 +186,12 @@ MakeTilemap({ -- Right wall ResetTransform() -Rotate('y', -90) +Rotate(Y, -90) Translate(13, 0, 1) Scale(32) MakeTilemap({ width = 4, - surface_type = 'right', + surface_type = RIGHT, tiles = { -1, 9, 11, -1, 9, 10, 12, 11, @@ -218,7 +218,7 @@ MakeTilemap({ -- Pitched roof ResetTransform() -Rotate('x', 135) +Rotate(X, 135) Scale(1, 1.5, 1.5) Translate(10, 5, 3) Scale(32) @@ -249,7 +249,7 @@ Translate(10, 4, 3) Scale(32) MakeTilemap({ width = 3, - surface_type = 'top', + surface_type = TOP, tiles = { -1, -1, -1 } @@ -261,13 +261,13 @@ MakeTilemap({ -- Courtyard ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(-3, 0, 0) Scale(32) SetTexture("Scenery") MakeTilemap({ width = 13, - surface_type = 'top', + surface_type = TOP, tiles = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -306,7 +306,7 @@ if detail > 2 then ResetTransform() Scale(4, 1, 1) - Rotate('y', -90) + Rotate(Y, -90) Translate(1, -0.5, 1) Scale(32) MakeBillboard({ @@ -318,7 +318,7 @@ if detail > 2 then ResetTransform() Scale(4, 1, 1) - Rotate('y', -90) + Rotate(Y, -90) Translate(9, -0.5, 1) Scale(32) MakeBillboard({ @@ -363,7 +363,7 @@ if detail > 1 then -- Left wall ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(19, 0, -3) Scale(32) MakeTilemap({ @@ -379,7 +379,7 @@ if detail > 1 then -- Right wall ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(23, 0, -3) Scale(32) MakeTilemap({ @@ -395,9 +395,9 @@ if detail > 1 then -- Left pitched roof ResetTransform() - Rotate('x', 135) + Rotate(X, 135) Scale(1, 1.5, 1.5) - Rotate('y', -90) + Rotate(Y, -90) Translate(21, 6, -3) Scale(32) MakeTilemap({ @@ -411,9 +411,9 @@ if detail > 1 then -- Right pitched roof ResetTransform() - Rotate('x', -135) + Rotate(X, -135) Scale(1, 1.5, 1.5) - Rotate('y', -90) + Rotate(Y, -90) Translate(21, 6, -3) Scale(32) MakeTilemap({ @@ -427,7 +427,7 @@ if detail > 1 then -- Finial ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(21, 6, -3) Scale(32) MakeTilemap({ @@ -444,13 +444,13 @@ end -- Ground under house ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(10, 0, 0) Scale(32) SetTexture("Scenery") MakeTilemap({ width = 3, - surface_type = 'top', + surface_type = TOP, tiles = { 1, 1, 1, 1, 1, 1, @@ -465,12 +465,12 @@ MakeTilemap({ -- Left part of center courtyard ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(13, 0, 0) Scale(32) MakeTilemap({ width = 8, - surface_type = 'top', + surface_type = TOP, tiles = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -528,7 +528,7 @@ if detail > 2 then -- Left grass ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(14, -0.5, 1) Scale(32) MakeTilemap({ @@ -541,7 +541,7 @@ if detail > 2 then -- Grass left of house ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(18, -0.5, 0) Scale(32) MakeBillboard({ @@ -552,7 +552,7 @@ if detail > 2 then -- Grass right of house ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(24, -0.5, 0) Scale(32) MakeBillboard({ @@ -586,7 +586,7 @@ if detail > 2 then ResetTransform() Scale(2, 1, 1) - Rotate('y', -90) + Rotate(Y, -90) Translate(19, -0.5, 2) Scale(32) MakeBillboard({ @@ -598,7 +598,7 @@ if detail > 2 then ResetTransform() Scale(2, 1, 1) - Rotate('y', -90) + Rotate(Y, -90) Translate(23, -0.5, 2) Scale(32) MakeBillboard({ @@ -610,12 +610,12 @@ end -- Right part of center courtyard ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(21, 0, 0) Scale(32) MakeTilemap({ width = 7, - surface_type = 'top', + surface_type = TOP, tiles = { 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, @@ -654,7 +654,7 @@ if detail > 2 then ResetTransform() Scale(2, 1, 1) - Rotate('y', -90) + Rotate(Y, -90) Translate(26, -0.5, 5) Scale(32) MakeBillboard({ @@ -666,7 +666,7 @@ if detail > 2 then ResetTransform() Scale(2, 1, 1) - Rotate('y', -90) + Rotate(Y, -90) Translate(35, -0.5, 5) Scale(32) MakeBillboard({ @@ -699,7 +699,7 @@ if detail > 2 then -- Extra bit of back grass ResetTransform() - Rotate('y', -90) + Rotate(Y, -90) Translate(34, -0.5, 0) Scale(32) MakeBillboard({ @@ -711,12 +711,12 @@ end -- Ground around tower block ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(28, 0, 4) Scale(32) MakeTilemap({ width = 5, - surface_type = 'top', + surface_type = TOP, tiles = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -727,12 +727,12 @@ MakeTilemap({ -- Rightmost ground ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(33, 0, 0) Scale(32) MakeTilemap({ width = 10, - surface_type = 'top', + surface_type = TOP, tiles = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, @@ -769,12 +769,12 @@ MakeTilemap({ -- Right side ResetTransform() -Rotate('y', 90) +Rotate(Y, 90) Translate(33, 0, 4) Scale(32) MakeTilemap({ width = 6, - surface_type = 'right', + surface_type = RIGHT, tiles = { 2, 2, 2, 2, 2, 2, 0, 1, 0, 0, 1, 0, @@ -789,12 +789,12 @@ MakeTilemap({ -- Left side ResetTransform() -Rotate('y', 90) +Rotate(Y, 90) Translate(28, 0, 4) Scale(32) MakeTilemap({ width = 6, - surface_type = 'left', + surface_type = LEFT, tiles = { 2, 2, 2, 2, 2, 2, 0, 1, 6, 0, 1, 0, @@ -809,12 +809,12 @@ MakeTilemap({ -- Top ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(28, 7, -2) Scale(32) MakeTilemap({ width = 5, - surface_type = 'top', + surface_type = TOP, tiles = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -857,12 +857,12 @@ MakeTilemap({ -- Left side ResetTransform() -Rotate('y', 90) +Rotate(Y, 90) Translate(40, 0, 5) Scale(32) MakeTilemap({ width = 5, - surface_type = 'left', + surface_type = LEFT, tiles = { 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, @@ -885,12 +885,12 @@ MakeTilemap({ -- Top ResetTransform() -Rotate('x', 90) +Rotate(X, 90) Translate(40, 15, 0) Scale(32) MakeTilemap({ width = 5, - surface_type = 'top', + surface_type = TOP, tiles = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, diff --git a/src/GameLayer.cc b/src/GameLayer.cc new file mode 100644 index 0000000..dfdadaa --- /dev/null +++ b/src/GameLayer.cc @@ -0,0 +1,187 @@ + +/******************************************************************************* + + 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 +#include +#include +#include + +#include "GameLayer.hh" + +#if HAVE_CONFIG_H +#include "config.h" +#endif + + +GameLayer::GameLayer() : + music("NightFusionIntro"), + punchSound("Thump") +{ + music.setLooping(true); + music.enqueue("NightFusionLoop"); + music.stream(); + + heroine = Character::alloc("RobotTrooper"); + heroine->getAnimation().startSequence("Run"); + + Mf::Scalar a[6] = {0.0, 1.5, -0.5, 3.0, -2.0, 1.0}; + interp.init(a, 2.0, Mf::Interpolator::OSCILLATE); + + Mf::Scalar b[2] = {1.0, 0.0}; + fadeIn.init(b, 1.0); + + octree = Mf::loadScene("Classic"); + heroine->treeNode = octree->insert(heroine); + + camera.setProjection(cml::rad(60.0), 1.33333, 32.0, 2500.0); + camera.uploadProjectionToGL(); +} + + +void GameLayer::pushed(Mf::Engine& engine) +{ + hud = Hud::alloc(); + engine.pushLayer(hud); +} + + +void GameLayer::update(Mf::Scalar t, Mf::Scalar dt) +{ + //dt *= 0.7; + + fadeIn.update(dt); + camera.update(t, dt); + heroine->update(t, dt); + + // reinsert heroine + heroine->treeNode = octree->reinsert(heroine, heroine->treeNode); + octree->print(heroine->treeNode); + + //camera.lookAt(heroine->getSphere().point); + camera.setPosition(Mf::Vector3(-heroine->current.position[0], + -heroine->current.position[1], -256)); + + Mf::Vector3 heroinePosition; + Mf::promoteVector(heroinePosition, heroine->current.position); + Mf::Sound::setListenerPosition(heroinePosition); + + interp.update(dt); + hud->setBar1Progress(interp.getState(dt)); + hud->setBar2Progress(1.0 - interp.getState(dt)); +} + + +void GameLayer::draw(Mf::Scalar alpha) const +{ + glMatrixMode(GL_MODELVIEW); + glLoadMatrix(camera.getModelviewMatrix().data()); + + // DRAW THE SCENE + Mf::Texture::resetBind(); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + octree->drawIfVisible(alpha, camera.getFrustum()); + + //heroine->draw(alpha); + heroine->getAabb().draw(); + + // DRAW FADE + glEnable(GL_BLEND); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glColor4f(0.0f, 0.0f, 0.0f, fadeIn.getState(alpha)); + Mf::Texture::resetBind(); + + //glRectf(-1.0f, -1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glVertex3f(-1.0, -1.0, -0.1); + glVertex3f(1.0, -1.0, -0.1); + glVertex3f(1.0, 1.0, -0.1); + glVertex3f(-1.0, 1.0, -0.1); + glEnd(); + + glDisable(GL_BLEND); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +bool GameLayer::handleEvent(const Mf::Event& event) +{ + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_SPACE) + { + heroine->getAnimation().startSequence("Punch"); + Mf::logInfo("thump!"); + punchSound.play(); + return true; + } + else if (event.key.keysym.sym == SDLK_p) + { + music.toggle(); + return true; + } + else if (event.key.keysym.sym == SDLK_y) + { + Mf::Engine::getInstance().popLayer(); + return true; + } + + case SDL_KEYUP: + heroine->handleEvent(event); + break; + + case SDL_MOUSEMOTION: + case SDL_MOUSEBUTTONDOWN: + camera.handleEvent(event); + return true; + + case SDL_VIDEORESIZE: + glViewport(0, 0, event.resize.w, event.resize.h); + camera.setProjection(cml::rad(60.0), + double(event.resize.w) / double(event.resize.h), 32.0, 2500.0); + camera.uploadProjectionToGL(); + break; + } + + return false; +} + + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/YoinkApp.hh b/src/GameLayer.hh similarity index 82% rename from src/YoinkApp.hh rename to src/GameLayer.hh index 950d319..b2df7ef 100644 --- a/src/YoinkApp.hh +++ b/src/GameLayer.hh @@ -26,21 +26,23 @@ *******************************************************************************/ -#ifndef _YOINKAPP_HH_ -#define _YOINKAPP_HH_ +#ifndef _GAMELAYER_HH_ +#define _GAMELAYER_HH_ /** - * @file YoinkApp.hh + * @file GameLayer.hh * This is the big enchilada. */ #include #include +#include + #include #include -#include #include +#include #include #include #include @@ -49,22 +51,25 @@ #include "Hud.hh" -class YoinkApp : public Mf::Engine +class GameLayer; +typedef boost::shared_ptr GameLayerP; + +class GameLayer : public Mf::Layer { public: - YoinkApp(int argc, char* argv[]); - ~YoinkApp(); + GameLayer(); -private: + static GameLayerP alloc() + { + return GameLayerP(new GameLayer); + } + + void pushed(Mf::Engine& engine); void update(Mf::Scalar t, Mf::Scalar dt); - void draw(Mf::Scalar alpha); - void handleEvent(const Mf::Event& event); + void draw(Mf::Scalar alpha) const; + bool handleEvent(const Mf::Event& event); - /** - * Set OpenGL to a state we can know and depend on. - */ - void setupGL(); - void contextRecreated(const Mf::Notification* note); +private: Mf::Sound music; @@ -77,11 +82,11 @@ private: Mf::Camera camera; Mf::OctreeP octree; - Hud hud; + HudP hud; }; -#endif // _YOINKAPP_HH_ +#endif // _GAMELAYER_HH_ /** vim: set ts=4 sw=4 tw=80: *************************************************/ diff --git a/src/Hud.cc b/src/Hud.cc index d5ec7bc..c535da5 100644 --- a/src/Hud.cc +++ b/src/Hud.cc @@ -171,6 +171,18 @@ void Hud::draw(Mf::Scalar alpha) const glPopMatrix(); } +bool Hud::handleEvent(Mf::Event& event) +{ + switch (event.type) + { + case SDL_VIDEORESIZE: + resize(event.resize.w, event.resize.h); + break; + } + + return false; +} + /** vim: set ts=4 sw=4 tw=80: *************************************************/ diff --git a/src/Hud.hh b/src/Hud.hh index 8fec549..966ae43 100644 --- a/src/Hud.hh +++ b/src/Hud.hh @@ -35,6 +35,7 @@ */ #include +#include #include #include #include @@ -65,12 +66,20 @@ private: }; -class Hud : public Mf::Drawable +class Hud; +typedef boost::shared_ptr HudP; + +class Hud : public Mf::Layer { public: Hud(); + static HudP alloc() + { + return HudP(new Hud); + } + void setBar1Progress(Mf::Scalar progress) { // pass through @@ -88,6 +97,7 @@ public: void resize(int width, int height); void draw(Mf::Scalar alpha = 0.0) const; + bool handleEvent(Mf::Event& event); private: diff --git a/src/YoinkApp.cc b/src/MainLayer.cc similarity index 50% rename from src/YoinkApp.cc rename to src/MainLayer.cc index 8690143..51881a7 100644 --- a/src/YoinkApp.cc +++ b/src/MainLayer.cc @@ -31,98 +31,81 @@ #include #include +#include #include #include -#include #include -#include -#include -#include +#include #include -#include "YoinkApp.hh" +#include "GameLayer.hh" +#include "MainLayer.hh" #if HAVE_CONFIG_H #include "config.h" #endif -static std::string configFiles() +MainLayer::MainLayer() { - std::string files; - - // look in the configured data directory last of all - char* dataDir = getenv("YOINK_DATADIR"); - files += (dataDir ? dataDir : YOINK_DATADIR); - files += "/yoinkrc"; - - // add the colon-delimited paths from configure - files += ":"; - files += YOINK_CONFIGFILES; - - char* configFile = getenv("YOINKRC"); - if (configFile) - { - // if a config file from the environment variable is specified, we want - // to load it first so it has precedence - files += ":"; - files += configFile; - } - - return files; + Mf::dispatcher::addHandler("video.context_recreated", + boost::bind(&MainLayer::contextRecreated, this, _1), this); + setupGL(); } -static std::string iconFile() +MainLayer::~MainLayer() { - char* dataDir = getenv("YOINK_DATADIR"); - - // first set up the search paths so we can find the icon and other resources - if (dataDir) - { - // look first in the data directory specified by the environment - Mf::Resource::addSearchPath(dataDir); - } - - // then look in the configured data directory - Mf::Resource::addSearchPath(YOINK_DATADIR); - - return Mf::Resource::getPath("yoink.png"); + Mf::dispatcher::removeHandler(this); } -YoinkApp::YoinkApp(int argc, char* argv[]) : - Mf::Engine(argc, argv, configFiles(), PACKAGE_STRING, iconFile()), - music("NightFusionIntro"), - punchSound("RobotPunch") +void MainLayer::pushed(Mf::Engine& e) { - Mf::dispatcher::addHandler("video.context_recreated", - boost::bind(&YoinkApp::contextRecreated, this, _1), this); - setupGL(); - - music.setLooping(true); - music.enqueue("NightFusionLoop"); - music.stream(); - - heroine = Character::alloc("RobotTrooper"); - heroine->getAnimation().startSequence("Run"); - - Mf::Scalar a[6] = {0.0, 1.5, -0.5, 3.0, -2.0, 1.0}; - interp.init(a, 2.0, Mf::Interpolator::OSCILLATE); + engine = &e; + engine->pushLayer(GameLayer::alloc()); +} - Mf::Scalar b[2] = {1.0, 0.0}; - fadeIn.init(b, 1.0); - octree = Mf::loadScene("Classic"); - heroine->treeNode = octree->insert(heroine); +void MainLayer::draw(Mf::Scalar alpha) const +{ + glClear(GL_DEPTH_BUFFER_BIT); } -YoinkApp::~YoinkApp() +bool MainLayer::handleEvent(const Mf::Event& event) { - Mf::dispatcher::removeHandler(this); + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) + { + engine->clearLayers(); + } + else if (event.key.keysym.sym == SDLK_f) + { + engine->getVideo().toggleFull(); + } + else if (event.key.keysym.sym == SDLK_l) + { + Mf::Video& video = engine->getVideo(); + video.toggleCursorGrab(); + video.toggleCursorVisible(); + } + else if (event.key.keysym.sym == SDLK_y) + { + engine->pushLayer(GameLayer::alloc()); + } + break; + + case SDL_QUIT: + engine->clearLayers(); + break; + } + + return false; } -void YoinkApp::setupGL() +void MainLayer::setupGL() { glEnable(GL_TEXTURE_2D); @@ -146,155 +129,20 @@ void YoinkApp::setupGL() //glMatrixMode(GL_PROJECTION); //glLoadIdentity(); //gluPerspective(60.0, 1.33333, 1.0, 2500.0); - camera.setProjection(cml::rad(60.0), 1.33333, 32.0, 2500.0); - camera.uploadProjectionToGL(); //glMatrixMode(GL_MODELVIEW); //glLineWidth(10.0f); } -void YoinkApp::contextRecreated(const Mf::Notification* note) +void MainLayer::contextRecreated(const Mf::Notification* note) { - // 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. + // 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 setupGL(); } -void YoinkApp::update(Mf::Scalar t, Mf::Scalar dt) -{ - //dt *= 0.7; - - fadeIn.update(dt); - camera.update(t, dt); - heroine->update(t, dt); - - // reinsert heroine - heroine->treeNode = octree->reinsert(heroine, heroine->treeNode); - octree->print(heroine->treeNode); - - //camera.lookAt(heroine->getSphere().point); - camera.setPosition(Mf::Vector3(-heroine->current.position[0], - -heroine->current.position[1], -256)); - - Mf::Vector3 heroinePosition; - Mf::promoteVector(heroinePosition, heroine->current.position); - Mf::Sound::setListenerPosition(heroinePosition); - - interp.update(dt); - hud.setBar1Progress(interp.getState(dt)); - hud.setBar2Progress(1.0 - interp.getState(dt)); -} - - -void YoinkApp::draw(Mf::Scalar alpha) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadMatrix(camera.getModelviewMatrix().data()); - - // DRAW THE SCENE - Mf::Texture::resetBind(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - octree->drawIfVisible(alpha, camera.getFrustum()); - - //heroine->draw(alpha); - heroine->getAabb().draw(); - - hud.draw(); - - // DRAW FADE - glEnable(GL_BLEND); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glColor4f(0.0f, 0.0f, 0.0f, fadeIn.getState(alpha)); - Mf::Texture::resetBind(); - - //glRectf(-1.0f, -1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glVertex3f(-1.0, -1.0, -0.1); - glVertex3f(1.0, -1.0, -0.1); - glVertex3f(1.0, 1.0, -0.1); - glVertex3f(-1.0, 1.0, -0.1); - glEnd(); - - glDisable(GL_BLEND); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -void YoinkApp::handleEvent(const Mf::Event& event) -{ - switch (event.type) - { - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) - { - stop(); - break; - } - else if (event.key.keysym.sym == SDLK_f) - { - getVideo().toggleFull(); - break; - } - else if (event.key.keysym.sym == SDLK_SPACE) - { - heroine->getAnimation().startSequence("Punch"); - punchSound.play(); - break; - } - else if (event.key.keysym.sym == SDLK_t) - { - Mf::dispatcher::dispatch("video.context_recreated"); - break; - } - else if (event.key.keysym.sym == SDLK_p) - { - music.toggle(); - break; - } - else if (event.key.keysym.sym == SDLK_l) - { - getVideo().toggleCursorGrab(); - getVideo().toggleCursorVisible(); - break; - } - - case SDL_KEYUP: - heroine->handleEvent(event); - - case SDL_MOUSEMOTION: - case SDL_MOUSEBUTTONDOWN: - camera.handleEvent(event); - break; - - case SDL_QUIT: - stop(); - break; - - case SDL_VIDEORESIZE: - glViewport(0, 0, event.resize.w, event.resize.h); - hud.resize(event.resize.w, event.resize.h); - camera.setProjection(cml::rad(60.0), - double(event.resize.w) / double(event.resize.h), 32.0, 2500.0); - camera.uploadProjectionToGL(); - break; - } -} - void printUsage() { @@ -328,6 +176,7 @@ int main(int argc, char* argv[]) << "Send patches and bug reports to <" PACKAGE_BUGREPORT << ">." << std::endl << std::endl; + #if YOINK_LOGLEVEL >= 4 Mf::setLogLevel(Mf::LOG_DEBUG); #elif YOINK_LOGLEVEL >= 3 @@ -340,23 +189,57 @@ int main(int argc, char* argv[]) Mf::setLogLevel(Mf::LOG_NONE); #endif - int status = 0; + + // Add search paths; they should be searched in this order: + // 1. YOINK_DATADIR (environment) + // 2. YOINK_DATADIR (configure) + + char* dataDir = getenv("YOINK_DATADIR"); + if (dataDir) + { + Mf::Resource::addSearchPath(dataDir); + } + + Mf::Resource::addSearchPath(YOINK_DATADIR); + + std::string iconFile = Mf::Resource::getPath("yoink.png"); + + + // Build the list of config files to search for, in this order: + // 1. YOINK_DATADIR/yoinkrc + // 2. /etc/yoinkrc + // 3. $HOME/.yoinkrc + // 4. YOINKRC (environment) + + std::string configFiles; + + configFiles += Mf::Resource::getPath("yoinkrc"); + configFiles += ":/etc/yoinkrc:$HOME/.yoinkrc"; + + char* configFile = getenv("YOINKRC"); + if (configFile) + { + configFiles += ":"; + configFiles += configFile; + } + try { - YoinkApp app(argc, argv); - status = app.run(); + Mf::Engine app(argc, argv, PACKAGE_STRING, iconFile, configFiles); + app.pushLayer(MainLayer::alloc()); + + app.run(); } catch (Mf::Exception e) { Mf::logError("unhandled exception: <<%s>>", e.what()); Mf::logInfo("it's time to crash now :-("); - //status = 1; throw e; } std::cout << std::endl << "Goodbye..." << std::endl << std::endl; - return status; + return 0; } diff --git a/src/MainLayer.hh b/src/MainLayer.hh new file mode 100644 index 0000000..db529a1 --- /dev/null +++ b/src/MainLayer.hh @@ -0,0 +1,80 @@ + +/******************************************************************************* + + 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 _MAINLAYER_HH_ +#define _MAINLAYER_HH_ + +/** + * @file MainLayer.hh + * This is where all the fun begins. + */ + +#include +#include + +#include + +#include +#include +#include + + +class MainLayer; +typedef boost::shared_ptr MainLayerP; + +struct MainLayer : public Mf::Layer +{ + MainLayer(); + ~MainLayer(); + + static MainLayerP alloc() + { + return MainLayerP(new MainLayer); + } + + void pushed(Mf::Engine& engine); + + void draw(Mf::Scalar alpha) const; + bool handleEvent(const Mf::Event& event); + +private: + + /** + * Set OpenGL to a state we can know and depend on. + */ + void setupGL(); + void contextRecreated(const Mf::Notification* note); + + Mf::Engine* engine; +}; + + +#endif // _MAINLAYER_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Makefile.am b/src/Makefile.am index 80372e2..ff31804 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,6 +36,7 @@ libmoof_a_SOURCES = \ Moof/Hash.cc \ Moof/Hash.hh \ Moof/Interpolator.hh \ + Moof/Layer.hh \ Moof/Log.cc \ Moof/Log.hh \ Moof/Math.hh \ @@ -110,14 +111,16 @@ bin_PROGRAMS = yoink yoink_SOURCES = \ Character.cc \ Character.hh \ + GameLayer.cc \ + GameLayer.hh \ Hud.cc \ Hud.hh \ + MainLayer.cc \ + MainLayer.hh \ TilemapFont.cc \ TilemapFont.hh \ Typesetter.cc \ Typesetter.hh \ - YoinkApp.cc \ - YoinkApp.hh \ $(ENDLIST) if WIN32 diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index 18ce5d7..5bfaaf3 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -26,7 +26,9 @@ *******************************************************************************/ +#include #include // exit +#include #include #include @@ -35,6 +37,7 @@ #include "Dispatcher.hh" #include "Engine.hh" +#include "Event.hh" #include "Log.hh" #include "Random.hh" #include "Settings.hh" @@ -48,10 +51,10 @@ 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(int argc, char* argv[], const std::string& name, + const std::string& iconFile, const std::string& configFile, + Engine& engine) : + interface(engine), timestep(0.01), printFps(false) { @@ -109,7 +112,7 @@ public: * the exit code used to stop the loop. */ - int run() + void run() { Scalar ticksNow = Timer::getTicks(); @@ -124,7 +127,6 @@ public: fps = 0; int frameAccum = 0; - running = true; do { Scalar newTicks = Timer::getTicks(); @@ -139,7 +141,7 @@ public: while (accumulator >= timestep) { dispatchEvents(); - interface->update(totalTime, timestep); + update(totalTime, timestep); totalTime += timestep; accumulator -= timestep; @@ -172,7 +174,7 @@ public: } } - interface->draw(accumulator / timestep); + draw(accumulator / timestep); video->swap(); nextDraw += drawRate; @@ -187,12 +189,9 @@ public: Timer::sleep(std::min(std::min(nextStep, nextDraw), Timer::getNextFire()), true); } - while (running); - - return exitCode; + while (!stack.empty()); } - void dispatchEvents() { SDL_Event event; @@ -205,7 +204,8 @@ public: if (event.key.keysym.sym == SDLK_ESCAPE && (SDL_GetModState() & KMOD_CTRL) ) { - exit(0); + // emergency escape + exit(0); } break; @@ -214,51 +214,133 @@ public: break; } - interface->handleEvent(event); + handleEvent(event); } } - Engine* interface; + void update(Scalar t, Scalar dt) + { + for (stackIt = stack.begin(); stackIt != stack.end(); ++stackIt) + { + (*stackIt)->update(t, dt); + } + } - VideoP video; + void draw(Scalar alpha) + { + // FIXME - this will crash if the layer being drawn pops itself + std::list::reverse_iterator it; + for (it = stack.rbegin(); it != stack.rend(); ++it) + { + (*it)->draw(alpha); + } + } - bool running; - int exitCode; + void handleEvent(const Event& event) + { + for (stackIt = stack.begin(); stackIt != stack.end(); ++stackIt) + { + if ((*stackIt)->handleEvent(event)) break; + } + } - Scalar timestep; - Scalar drawRate; - long fps; - bool printFps; -}; + void pushLayer(LayerP layer) + { + ASSERT(layer && "cannot push null layer"); + stack.push_front(layer); + layer->pushed(interface); + } + + void popLayer() + { + bool fixIt = false; + if (stack.begin() == stackIt) fixIt = true; + LayerP popped = stack.front(); + stack.pop_front(); + popped->popped(interface); -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)) {} + if (fixIt) stackIt = --stack.begin(); + } + + void popLayer(Layer* layer) + { + bool fixIt = false; -Engine::~Engine() {} + std::list::iterator it; + for (it = stack.begin(); it != stack.end(); ++it) + { + if (it == stackIt) fixIt = true; + if ((*it).get() == layer) + { + ++it; + do + { + LayerP popped = stack.front(); + stack.pop_front(); + popped->popped(interface); + } + while (stack.begin() != it); + + if (fixIt) stackIt = --stack.begin(); + return; + } + } + } -int Engine::run() + void clearLayers() + { + stack.clear(); + stackIt = stack.begin(); + } + + + Engine& interface; + + VideoP video; + + std::list stack; + std::list::iterator stackIt; + + Scalar timestep; + Scalar drawRate; + + long fps; + bool printFps; +}; + + +static Engine* instance = 0; + +Engine::Engine(int argc, char* argv[], const std::string& name, + const std::string& iconFile, const std::string& configFile) : + impl_(new Engine::Impl(argc, argv, name, iconFile, configFile, *this)) { - return impl_->run(); + instance = this; } -void Engine::stop(int exitCode) + +Engine& Engine::getInstance() { - impl_->running = false; - impl_->exitCode = exitCode; + ASSERT(instance && "dereferencing null pointer"); + return *instance; } +void Engine::run() +{ + return impl_->run(); +} + void Engine::setTimestep(Scalar ts) { impl_->timestep = ts; } -Scalar Engine::getTimestep() +Scalar Engine::getTimestep() const { return impl_->timestep; } @@ -268,26 +350,46 @@ void Engine::setMaxFrameRate(long maxFps) impl_->drawRate = 1.0 / Scalar(maxFps); } -long Engine::getMaxFrameRate() +long Engine::getMaxFrameRate() const { return long(1.0 / impl_->drawRate); } -Video& Engine::getVideo() +Video& Engine::getVideo() const { return *impl_->video; } -long Engine::getFrameRate() +long Engine::getFrameRate() const { return impl_->fps; } -void Engine::update(Scalar t, Scalar dt) {} -void Engine::draw(Scalar alpha) {} -void Engine::handleEvent(const Event& event) {} +void Engine::pushLayer(LayerP layer) +{ + // pass through + impl_->pushLayer(layer); +} + +void Engine::popLayer() +{ + // pass through + impl_->popLayer(); +} + +void Engine::popLayer(Layer* layer) +{ + // pass through + impl_->popLayer(layer); +} + +void Engine::clearLayers() +{ + // pass through + impl_->clearLayers(); +} } // namespace Mf diff --git a/src/Moof/Engine.hh b/src/Moof/Engine.hh index 0617b1a..a0c2300 100644 --- a/src/Moof/Engine.hh +++ b/src/Moof/Engine.hh @@ -29,47 +29,42 @@ #ifndef _MOOF_ENGINE_HH_ #define _MOOF_ENGINE_HH_ -#include - #include -#include #include +#include #include namespace Mf { -// forward declaration +// forward declarations class Video; -class Engine +struct Engine { -protected: - - Engine(int argc, char* argv[], const std::string& configFile, - const std::string& name, const std::string& iconFile); + Engine(int argc, char* argv[], const std::string& name, + const std::string& iconFile, const std::string& configFile); + ~Engine() {} -public: + // get global instance + static Engine& getInstance(); - virtual ~Engine(); - - int run(); - void stop(int exitCode = 0); + void run(); void setTimestep(Scalar ts); - Scalar getTimestep(); + Scalar getTimestep() const; void setMaxFrameRate(long maxFps); - long getMaxFrameRate(); + long getMaxFrameRate() const; - Video& getVideo(); - long getFrameRate(); + Video& getVideo() const; + long getFrameRate() const; - // override these if you want - virtual void update(Scalar t, Scalar dt); - virtual void draw(Scalar alpha); - virtual void handleEvent(const Event& event); + void pushLayer(LayerP layer); + void popLayer(); + void popLayer(Layer* layer); + void clearLayers(); struct Exception : public Mf::Exception { @@ -83,8 +78,6 @@ public: }; private: - Engine() {} // this class must be subclassed to be useful - class Impl; boost::shared_ptr impl_; }; diff --git a/src/Moof/Interpolator.hh b/src/Moof/Interpolator.hh index b32482c..7ded928 100644 --- a/src/Moof/Interpolator.hh +++ b/src/Moof/Interpolator.hh @@ -139,12 +139,12 @@ public: virtual void calculate(T& value, Scalar alpha) = 0; - const T& getValue() + const T& getValue() const { return value_; } - const T getState(Scalar alpha) + const T getState(Scalar alpha) const { return cml::lerp(previous_, value_, alpha); } diff --git a/src/Moof/Layer.hh b/src/Moof/Layer.hh new file mode 100644 index 0000000..8ec678d --- /dev/null +++ b/src/Moof/Layer.hh @@ -0,0 +1,66 @@ + +/******************************************************************************* + + 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 _MOOF_LAYER_HH_ +#define _MOOF_LAYER_HH_ + +#include + +#include +#include +#include + + +namespace Mf { + + +// forward declaration +class Engine; + + +struct Layer : public Drawable +{ + virtual ~Layer() {} + + 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; } +}; + +typedef boost::shared_ptr LayerP; + + +} // namespace Mf + +#endif // _MOOF_LAYER_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Moof/Log.cc b/src/Moof/Log.cc index 96c7095..96827e1 100644 --- a/src/Moof/Log.cc +++ b/src/Moof/Log.cc @@ -116,7 +116,7 @@ void logDebug(const char* fmt, ...) va_end(args); } -static void logScript(const char* fmt, ...) +void logScript(const char* fmt, ...) { va_list args; va_start(args, fmt); diff --git a/src/Moof/Log.hh b/src/Moof/Log.hh index 09130ed..1f9d0c6 100644 --- a/src/Moof/Log.hh +++ b/src/Moof/Log.hh @@ -114,6 +114,7 @@ void logInfo(const char* fmt, ...); void logDebug(const char* fmt, ...); +void logScript(const char* fmt, ...); class Script; int logScript(Script& script); void importLogScript(Script& script); diff --git a/src/Moof/Scene.cc b/src/Moof/Scene.cc index fe49ed2..b331312 100644 --- a/src/Moof/Scene.cc +++ b/src/Moof/Scene.cc @@ -56,6 +56,13 @@ struct Meh OctreeP octree; + enum AXIS + { + X = 0, + Y = 1, + Z = 2 + }; + Meh() { octree = Octree::alloc(Aabb()); @@ -112,15 +119,9 @@ struct Meh int translate(Script& script) { - Script::Value x = script[1]; - Script::Value y = script[2]; - Script::Value z = script[3]; - - if (!x.isNumber() || !y.isNumber() || !z.isNumber()) - { - logWarning("wrong arguments to translate; ignoring..."); - return 0; - } + Script::Value x = script[1].requireNumber(); + Script::Value y = script[2].requireNumber(); + Script::Value z = script[3].requireNumber(); Vector3 vec; x.get(vec[0]); @@ -139,9 +140,9 @@ struct Meh if (script.getSize() == 3) { Vector3 vec; - script[1].get(vec[0]); - script[2].get(vec[1]); - script[3].get(vec[2]); + script[1].requireNumber().get(vec[0]); + script[2].requireNumber().get(vec[1]); + script[3].requireNumber().get(vec[2]); Matrix4 scaling; cml::matrix_scale(scaling, vec); @@ -150,16 +151,15 @@ struct Meh else if (script.getSize() == 1) { Scalar value = 1.0; - script[1].get(value); + script[1].requireNumber().get(value); Matrix4 scaling; - cml::matrix_uniform_scale(scaling, - Scalar(value)); + cml::matrix_uniform_scale(scaling, value); transform = scaling * transform; } else { - logWarning("wrong arguments to scale; ignoring..."); + script.getTop().throwError("wrong number of arguments"); } return 0; @@ -167,53 +167,34 @@ struct Meh int rotate(Script& script) { - Script::Value a = script[1]; - Script::Value d = script[2]; - - if (!a.isString() || !d.isNumber()) - { - logWarning("wrong arguments to rotate; ignoring..."); - return 0; - } - - std::string axis; - a.get(axis); + Script::Value axis = script[1].requireString(); + Script::Value angle = script[2].requireNumber(); size_t index = 0; - if (axis == "x") index = 0; - else if (axis == "y") index = 1; - else if (axis == "z") index = 2; + axis.get(index); Scalar value; - d.get(value); + angle.get(value); - cml::matrix_rotate_about_world_axis(transform, - index, cml::rad(Scalar(value))); + cml::matrix_rotate_about_world_axis(transform, index, cml::rad(value)); return 0; } int setTexture(Script& script) { - Script::Value t = script[1]; + Script::Value name = script[1].requireString(); - if (t.isString()) t.get(texture); - else logWarning("wrong arguments to setTexture; ignoring..."); + name.get(texture); return 0; } int makeTilemap(Script& script) { - Script::Value table = script[1]; + Script::Value table = script[1].requireTable(); Script::Value top = script[-1]; - if (!table.isTable()) - { - logWarning("wrong arguments to makeTilemap; ignoring..."); - return 0; - } - long width = 1; long height = 1; @@ -226,43 +207,37 @@ struct Meh Script::Value tiles = script.getTop(); nTiles = tiles.getLength(); - std::vector< std::vector > indices; + if (nTiles % width != 0) table.throwError("invalid number of tiles"); - if (nTiles % width == 0) - { - int i, w, h; + std::vector< std::vector > indices; - height = nTiles / width; - indices.resize(height); + int i, w, h; - // the indices are stored upside-down in the scene file so that they - // are easier to edit as text, so we'll need to load them last row - // first + height = nTiles / width; + indices.resize(height); - i = 1; - for (h = height - 1; h >= 0; --h) - { - std::vector row; + // the indices are stored upside-down in the scene file so that they + // are easier to edit as text, so we'll need to load them last row + // first - for (w = 0; w < width; ++w, ++i) - { - script.checkStack(2); - script.push(long(i)); - tiles.pushField(); + i = 1; + for (h = height - 1; h >= 0; --h) + { + std::vector row; - long index; - top.get(index); + for (w = 0; w < width; ++w, ++i) + { + script.checkStack(2); + script.push(long(i)); + tiles.pushField(); - row.push_back(Tilemap::Index(index)); - } + long index; + top.get(index); - indices[h] = row; + row.push_back(Tilemap::Index(index)); } - } - else - { - logError("invalid tiles in tilemap instruction"); - return 0; + + indices[h] = row; } Vector4 vertices[height+1][width+1]; @@ -315,16 +290,16 @@ struct Meh if (table.isTable()) { table.pushField("tile"); - if (top.isNumber()) top.get(index); + top.get(index); table.pushField("u_scale"); - if (top.isNumber()) top.get(width); + top.get(width); table.pushField("blend"); - if (top.isBoolean()) top.get(blending); + top.get(blending); table.pushField("fog"); - if (top.isBoolean()) top.get(fog); + top.get(fog); } Vector4 vertices[2][width+1]; @@ -368,7 +343,7 @@ struct Meh }; -static void importScriptBindings(Script& script, Meh& scene) +static void importSceneBindings(Script& script, Meh& scene) { script.importFunction("SetPlayfieldBounds", boost::bind(&Meh::setPlayfieldBounds, &scene, _1)); @@ -388,6 +363,25 @@ static void importScriptBindings(Script& script, Meh& scene) boost::bind(&Meh::makeTilemap, &scene, _1)); script.importFunction("MakeBillboard", boost::bind(&Meh::makeBillboard, &scene, _1)); + + long detail = 3; + Settings::getInstance().get("detail", detail); + script.push(detail); + script.set("detail"); + + script.push(Quad::LEFT); + script.set("LEFT"); + script.push(Quad::RIGHT); + script.set("RIGHT"); + script.push(Quad::TOP); + script.set("TOP"); + + script.push(Meh::X); + script.set("X"); + script.push(Meh::Y); + script.set("Y"); + script.push(Meh::Z); + script.set("Z"); } @@ -400,22 +394,14 @@ OctreeP loadScene(const std::string& name) Script script; script.importStandardLibraries(); importLogScript(script); - importScriptBindings(script, cool); - - long detail = 3; - Settings::getInstance().get("detail", detail); - - script.push(detail); - script.set("detail"); + importSceneBindings(script, cool); - logInfo("doing file..."); - if (script.doFile(filePath) != 0) + if (script.doFile(filePath) != Script::SUCCESS) { std::string str; script[-1].get(str); - logError("lua error: %s", str.c_str()); + logScript("%s", str.c_str()); } - logInfo("done"); cool.octree->sort(); return cool.octree; diff --git a/src/Moof/Scene.hh b/src/Moof/Scene.hh index 107e993..ce57bcd 100644 --- a/src/Moof/Scene.hh +++ b/src/Moof/Scene.hh @@ -53,16 +53,21 @@ class Quad : public Entity Tilemap tilemap_; - long detail_; bool blending_; bool fog_; public: + enum SURFACE_TYPE + { + LEFT = 1, + RIGHT = 2, + TOP = 3 + }; + Quad(const Vector3 vertices[4], const std::string& texture, Tilemap::Index tileIndex) : tilemap_(texture), - detail_(0), blending_(false), fog_(false) { @@ -90,11 +95,6 @@ public: sphere_.radius = (aabb_.min - sphere_.point).length(); } - void setDetail(long detail) - { - detail_ = detail; - } - void setBlending(bool blending) { blending_ = blending; diff --git a/src/Moof/Script.hh b/src/Moof/Script.hh index f954e58..553e31a 100644 --- a/src/Moof/Script.hh +++ b/src/Moof/Script.hh @@ -140,6 +140,73 @@ struct Script bool isData() const { return (bool)lua_isuserdata(state, index); } bool isLightData() const { return (bool)lua_islightuserdata(state, index); } + /** + * Check the value and throw and error if its the wrong type. This + * method never returns because it does a long jump. Consequently, + * constructed C++ objects which exist on the stack between the current + * frame and some lua function will not be destructed. That's not a + * problem for objects that only exist on the stack, but any objects + * that allocate memory on the heap (such as containers or strings) will + * leak. Therefore, you should only call this method after cleaning up + * such objects. + */ + + void requireType(TYPE type) const + { + if (type != getType()) + { + luaL_typerror(state, index, lua_typename(state, type)); + } + } + + void throwError(const char* error) + { + luaL_argerror(state, index, error); + } + + + Value& requireBoolean() + { + if (!isBoolean()) luaL_typerror(state, index, "boolean"); + return *this; + } + Value& requireNumber() + { + if (!isNumber()) luaL_typerror(state, index, "number"); + return *this; + } + Value& requireString() + { + if (!isString()) luaL_typerror(state, index, "string"); + return *this; + } + Value& requireTable() + { + if (!isTable()) luaL_typerror(state, index, "table"); + return *this; + } + Value& requireFunction() + { + if (!isFunction()) luaL_typerror(state, index, "function"); + return *this; + } + Value& requireData() + { + if (!isData()) luaL_typerror(state, index, "data"); + return *this; + } + Value& requireNil() + { + if (!isNil()) luaL_typerror(state, index, "nil"); + return *this; + } + Value& requireThread() + { + if (!isThread()) luaL_typerror(state, index, "thread"); + return *this; + } + + /** * Get the type of the value. */ @@ -155,7 +222,7 @@ struct Script std::string getTypeName() const { - return std::string(lua_typename(state, (int)getType())); + return std::string(luaL_typename(state, index)); } @@ -465,6 +532,22 @@ struct Script } + /** + * Throw an error with the value at the top of the stack. This method never + * returns because it does a long jump. Consequently, constructed C++ + * objects which exist on the stack between the current frame and some lua + * function will not be destructed. That's not a problem for objects that + * only exist on the stack, but any objects that allocate memory on the heap + * (such as containers or strings) will leak. Therefore, you should only + * call this method after cleaning up such objects. + */ + + void throwError() + { + lua_error(state_); + } + + /** * Get significant values. */ @@ -561,6 +644,10 @@ struct Script { lua_pushlstring(state_, value.c_str(), value.length()); } + void push(const char* value) + { + lua_pushstring(state_, value); + } void push(const char* value, size_t length) { lua_pushlstring(state_, value, length); diff --git a/src/Moof/Settings.cc b/src/Moof/Settings.cc index 53cb850..5a321b0 100644 --- a/src/Moof/Settings.cc +++ b/src/Moof/Settings.cc @@ -78,7 +78,7 @@ void Settings::loadFromFiles(const std::vector& filePaths) { std::string str; script_[-1].get(str); - logWarning("running config file: %s", str.c_str()); + logScript("%s", str.c_str()); script_.clear(); } } -- 2.43.0