settings subsystem now using lua
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Mon, 12 Oct 2009 20:39:42 +0000 (14:39 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Mon, 12 Oct 2009 20:39:42 +0000 (14:39 -0600)
14 files changed:
configure.ac
data/yoinkrc
doc/yoink.6.in
src/Moof/Engine.cc
src/Moof/Log.cc
src/Moof/Log.hh
src/Moof/Scene.cc
src/Moof/Script.hh
src/Moof/Settings.cc
src/Moof/Settings.hh
src/Moof/Sound.cc
src/Moof/Sound.hh
src/Moof/Video.cc
src/YoinkApp.cc

index 47ee0baef14494680d9803a5cb60494e34b6238d..7d8d54591f1b6cb7b01b54bdbec439b11351cc13 100644 (file)
@@ -153,7 +153,7 @@ AC_DEFINE_UNQUOTED([YOINK_DATADIR], ["$DATADIR"],
                                   [Define to path of game asset directory.])
 
 
-CONFIGFILES="\$HOME/.yoinkrc:/etc/yoinkrc"
+CONFIGFILES="/etc/yoinkrc:\$HOME/.yoinkrc"
 
 AC_DEFINE_UNQUOTED([YOINK_CONFIGFILES], ["$CONFIGFILES"],
                                   [Define to colon-delimited configuration file paths.])
index 2faf40dc6bf0d0f2313f1bbaa35405f9cb88331d..bcb0f0645f040edee3631b1fc865e7c4a16c3427 100644 (file)
@@ -1,16 +1,70 @@
-/* C-style comments are allowed. */
-{
-       "engine.timestep": 0.01,
-       "input.grab": false,
-       "video.colorbuffers": [8, 8, 8, 8],
-       "video.cursor": true,
-       "video.doublebuffer": true,
-       "video.fullscreen": false,
-       "video.maxfps": 45,
-       "video.mode": [800, 600],
-       "video.multisamplebuffers": 6,
-       "video.multisamplesamples": 6,
-       "video.resizable": true,
-       //"video.printfps": true,
-       "video.swapcontrol": true
-}
+
+-- Example Yoink Configuration File
+-- vim: ft=lua
+
+print "loading yoinkrc..."
+
+
+-- Set the level of detail to use when drawing scenes.  This can be 1, 2 or
+-- 3, where 1 shows the least amount of detail and 3 draws the scene with
+-- the most detail.
+
+detail = 3
+
+-- Set the amount of time in seconds between each update of the physics
+-- state.  A value of 0.01 or lower is ideal for accurate physics
+-- approximations.  Values that are much higher cause the CPU to do less
+-- work, but accuracy will suffer.  Errors could be introduced in the game
+-- with extremely high values.
+
+timestep = 0.01
+
+-- Set the maximum number of frames that can be drawn per second.  A value
+-- of 50 is pretty good.  If your computer is really old, you can get away
+-- with decreasing this value and still have reasonably smooth animation.
+-- You can set this to a very high number to effectively render as many
+-- frames as is possible, but the actual rate could be limited by vertical
+-- display synchronization, depending on the X11 driver and settings used.
+-- You should not set this option higher than the point where the vertical
+-- synchronization effectively limits the draw rate or else the game may
+-- not be able to update the physics on schedule which could actually
+-- significantly lower the quality of the animation.
+
+maxfps = 45
+
+-- Set whether or not to print the current actual framerate to the console.
+
+printfps = false
+
+-- Set whether or not the game will run in full-screen mode.  If false, the
+-- game will run in a window.
+
+fullscreen = false
+
+-- If the game is running in a window, set whether or not the window will
+-- be resizable.
+
+resizable = true
+
+-- Set 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.  A typical value is 800,600 for a size of
+-- 800x600 pixels with millions of colors (the third number is optional).
+
+videomode = {1024, 786}
+
+-- Set whether or not the cursor will be visible when you mouse over the
+-- display of the game.
+
+showcursor = true
+
+-- Set whether or not the drawing should use two buffers.  This results in
+-- a higher quality animation.  You should usually leave this as true.
+
+doublebuffer = true
+
+-- Set whether or not to sync with the display in order to reduce
+-- distortion.
+
+swapcontrol = true
+
index d9e90bfdd20133ca43bdbe20c311a4c46752dd6d..2432bd5de9d39abdcdaf847bd69e7759b89e2d6c 100644 (file)
@@ -42,7 +42,7 @@ arcade games like Joust, Bombjack, Rampage, and Defender--simple, fast-moving
 action.  Basic arguments include:
 .TP
 .B -h, --help
-display this help and exit
+Display this help and exit.
 .br
 .SH TIPS
 .PP
@@ -69,77 +69,60 @@ around, especially in the sky, if you can't find the last few.
 .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.  Some of the more common options can be set from within the
-game.
+them as arguments.
 .PP
 A
 .B yoink
-configuration file ("yoinkrc") consists of key-value pairs organized in a
-logical hierarchy.  The format of the file is human-readable, so you can get in
-there with your favorite text editor if you like to work under the hood.
+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.
 .B yoink
-looks for configuration files and loads them in this order, with the options in
-prior configuration files taking precedence over the same options if they exist
-in multiple configuration files:
+looks for configuration files and loads them in this order, the options from
+each subsequent configuration files taking precedence over the same options from
+previous files.
 .TP
-1. $YOINKRC
-This is an optional environment variable you can set to point to a configuration
-file.
-.TP
-2. $HOME/.yoinkrc
-This is a specific user's personal configuration file.
+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.
 .TP
-3. /etc/yoinkrc
+2. /etc/yoinkrc
 This is the system-wide configuration file.  Not available on Windows.
 .TP
-4. @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.
+3. $HOME/.yoinkrc
+This is your own personal configuration 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 is good for running the game with a
-temporary setting which you do not intend to retain.  Keep in mind that if you
-edit and save options in-game, any options you have passed as arguments during
-the invocation of the game will be saved to the
-.I $HOME/.yoinkrc
-configuration file.  If this is not what you intended, you may have to go into
-that file and remove any options you didn't intend to set.  When passing options
-as arguments, you must use the fully qualified name of the option if it exists
-in a subgroup.  For example:
+temporary setting which you do not intend to retain.  Examples:
 .PP
 .TP
-yoink video.fullscreen=true
-Set the option
-.I video.fullscreen
-to true.  This will run the game in full-screen mode.
+yoink fullscreen=true
+Run Yoink with the option
+.I fullscreen
+as true.  This will run the game in full-screen mode.
 .TP
-yoink video.maxfps=60
-Set the option
-.I video.maxfps
-to 60.  This will cap the display rate at 60Hz.
+yoink maxfps=60
+Run Yoink with the option
+.I maxfps
+as 60.  This will cap the display rate at 60Hz.
 .PP
 You can also set options with array values.  Arrays can be passed on the command
-line by surrounding all the parts with square brackets and separating each part
-by a comma.  For example:
+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 video.mode=[1024,768]
-Set the option
-.I video.mode
-to an array with numbers 1024 and 768.  The video size will be 1024x768.
+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:
 .TP
-.B engine.rngseed
-The number value used as a seed for the random number generator.  Set this to
-make the game more predictable.  This is typically only useful for debugging.
-.TP
-.B engine.timestep
-The amount of time in seconds between each update of the physics state.  A value
-of 0.01 or lower is ideal for accurate physics approximations.  Values that are
-much higher cause the CPU to do less work, but accuracy will suffer.  Errors
-could be introduced in the game with extremely high values.
-.TP
-.B game.detail
+.B detail
 The level of detail.  Possible values are high, medium, and low.  This effects
 the number of objects drawn to the screen.  A high level of detail will draw
 everything but could cause poor frame rates if the graphics driver can't keep up
@@ -147,32 +130,16 @@ with the load.  Lower levels will omit certain details which aren't crucial for
 playing the game with the benefit of higher frame rates.  See the Notes for more
 ways to get good performance.
 .TP
-.B input.grab
-Takes a boolean (true or false).  If true, the cursor pointer will be "stuck"
-within the area of the window, and many key combinations which would otherwise
-be handled by the window manager will instead be dropped.  This is a low-level
-option of limited usefulness.
-.TP
-.B video.colorbuffers
-This takes an array of four number values which represent the number of bits to
-use for red, green, blue, and the alpha channel.  This is a low-level option of
-limited usefulness.  The default value is almost always preferable.
-.TP
-.B video.showcursor
-This option effects the visibility of the cursor while it is "hovering" over the
-window.  If the value is true, the cursor will be visible.  Otherwise, the
-cursor will be hidden.
-.TP
-.B video.doublebuffer
+.B doublebuffer
 If true, double-buffering will be used to render animations with minimal
 distortions.  Otherwise, a single buffer will be used.  The recommended value is
 true.
 .TP
-.B video.fullscreen
+.B fullscreen
 If true, the window will capture the display and render the game in full screen
 splendor.  A value of false means the game will run in a window.
 .TP
-.B video.maxfps
+.B maxfps
 The maximum number of frames to be drawn per second.  A value of 50 is pretty
 good.  If your computer is pretty old, can get away with decreasing this value
 and still have reasonably smooth animation.  You can set this to a very high
@@ -183,30 +150,34 @@ where the vertical synchronization effectively limits the draw rate or else the
 game may not be able to update the physics on schedule which could actually
 significantly lower the quality of the animation.
 .TP
-.B video.mode
-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.  A typical value is [800,600] for a size of 800x600 pixels with
-millions of colors (the third number is optional).
-.TP
-.B video.multisamplebuffers
-The number of multisample buffers used.
-.TP
-.B video.multisamplesamples
-The number of multisample samples used.
-.TP
-.B video.printfps
+.B printfps
 If true, the current number of frames being draw per second will be printed to
 the console.  This is usually off by default, but you can set this to true if
 you're interested in the draw rate you're actually getting.
 .TP
-.B video.resizable
+.B resizable
 If true, the window will be resizable by the window manager.  This option is
 meaningless if the game is drawing to the full screen.
 .TP
-.B video.swapcontrol
-If true, drawing will take place at a time which will minimize distortion caused
-by the vertical refreshing of displays.  The recommended value is true.
+.B showcursor
+This option effects the visibility of the cursor while it is "hovering" over the
+window.  If the value is true, the cursor will be visible.  Otherwise, the
+cursor will be hidden.
+.TP
+.B timestep
+The amount of time in seconds between each update of the physics state.  A value
+of 0.01 or lower is ideal for accurate physics approximations.  Values that are
+much higher cause the CPU to do less work, but accuracy will suffer.  Errors
+could be introduced in the game with extremely high values.
+.TP
+.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.  A typical value is {800,600} for a size of 800x600 pixels with
+millions of colors (the third number is optional).
+.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 ENVIRONMENT
 .PP
@@ -239,10 +210,7 @@ YOINKRC
 If set to a path of a valid configuration file, 
 .B yoink
 will load the options from that file, and those options will take precedence
-over options loaded from other configuration files.  Any in-game saving will
-cause this file to be over-written by the new options rather than the
-.I $HOME/.yoinkrc
-config file.
+over options loaded from other configuration files.
 .br
 .SH NOTES
 .PP
@@ -251,30 +219,25 @@ accelerated OpenGL driver installed and working, depending on how fast your CPU
 is.  Yoink is really not all that heavy on graphics, but it doesn't take much to
 overload a software implementation.  If you're stuck without hardware
 acceleration, there are some things you can do to get better frame rates:
-.PP
-1. Decrease the resolution with the
-.I video.mode
-option.  Due to the nature of the graphics in the game, you can go as low as
-320x240 and not notice a large reduction in image quality.  You can take
-advantage of this by decreasing the resolution and running full-screen (so the
-window is not so itty bitty on your monitor).  This will help out a lot.  Try
-this:
 .TP
-yoink video.mode=[320,240] video.fullscreen=true
-.PP
-2. Decrease the level of detail with the
-.I game.detail
-option.
+1. Decrease the resolution.
+Use the
+.I videomode
+option.  This speeds up software renderers considerably.
+.TP
+2. Decrease the level of rendering detail.
+Use the
+.I detail
+option.  The game world may look sparse or incomplete, but that may be better
+than choppy animation.
 .PP
 On the other hand, if you already get high frame rates, you may also want to cap
 the rate so that your computer doesn't do more work than it really needs to.
-This may be useful when you run
-.B yoink
-on your production server at work.  You can get reasonably smooth animation at
-around 30fps, but you can probably tell a difference between that and a higher
-rate like 50fps.  The latter will look noticeably smoother and nice, while the
-former is just "acceptable."  See the
-.I video.maxfps
+You can get reasonably smooth animation at around 30fps, but you can probably
+tell a difference between that and a higher rate like 50fps.  The latter will
+look noticeably smoother and nice, while the former is just "okay."  See
+the
+.I maxfps
 option.
 .br
 .SH BUGS
index e97c8b5d1b7edbae52a5b48ebc1072574e697ebe..18ce5d7e5f8c6d0b4664da080b16ba1ad2623ace 100644 (file)
@@ -51,7 +51,9 @@ public:
        Impl(int argc, char* argv[], const std::string& configFile,
                        const std::string& name, const std::string& iconFile,
                        Engine* outer) :
-               interface(outer)
+               interface(outer),
+               timestep(0.01),
+               printFps(false)
        {
 #if defined(_WIN32) || defined (_WIN64) || defined(__WIN32__)
                if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
@@ -70,23 +72,20 @@ public:
                alutInit(&argc, argv);
 
                Settings& settings = Settings::getInstance();
-               settings.parseArgs(argc, argv);
                settings.loadFromFile(configFile);
+               settings.parseArgs(argc, argv);
 
                long randomSeed;
-               if (settings.get("engine.rngseed", randomSeed)) setSeed(randomSeed);
+               if (settings.get("rngseed", randomSeed)) setSeed(randomSeed);
                else setSeed();
 
-               double ts = 0.01;
-               settings.get("engine.timestep", ts);
-               timestep = Scalar(ts);
+               settings.get("timestep", timestep);
 
                long maxFps = 40;
-               settings.getNumber("video.maxfps", maxFps);
+               settings.get("maxfps", maxFps);
                drawRate = 1.0 / Scalar(maxFps);
 
-               printFps = false;
-               settings.get("video.printfps", printFps);
+               settings.get("printfps", printFps);
 
                video = Video::alloc(name, iconFile);
                video->makeActive();
@@ -169,7 +168,7 @@ public:
 
                                        if (printFps)
                                        {
-                                               logInfo("framerate: %d fps", fps);
+                                               logInfo("%d fps", fps);
                                        }
                                }
 
index 0639a601dba5f2edb4e64212eba3862425e8873e..96c70955da1231d9d687260f75698ba5d9c74f74 100644 (file)
@@ -31,6 +31,7 @@
 #include <cstring>             // strcpy
 
 #include "Log.hh"
+#include "Script.hh"
 
 
 namespace Mf {
@@ -50,6 +51,9 @@ inline void printLog_(int logLevel, const char* fmt, va_list args)
                case LOG_WARNING:
                        fprintf(stderr, "warning: ");
                        break;
+               case LOG_SCRIPT:
+                       fprintf(stderr, " script: ");
+                       break;
                case LOG_INFO:
                        fprintf(stderr, "   info: ");
                        break;
@@ -112,6 +116,56 @@ void logDebug(const char* fmt, ...)
        va_end(args);
 }
 
+static void logScript(const char* fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+
+       printLog_(LOG_SCRIPT, fmt, args);
+
+       va_end(args);
+}
+
+int logScript(Script& script)
+{
+       Script::Value param = script[1];
+
+       while (!param.isNone())
+       {
+               if (param.isString())
+               {
+                       std::string str;
+                       param.get(str);
+                       logScript("%s", str.c_str());
+               }
+               else if (param.isBoolean())
+               {
+                       if (param) logScript("true");
+                       else       logScript("false");
+
+               }
+               else if (param.isNil())
+               {
+                       logScript("nil");
+               }
+               else
+               {
+                       logScript("%s (%X)", param.getTypeName().c_str(),
+                                       param.getIdentifier());
+               }
+
+               param.index++;
+       }
+
+       return 0;
+}
+
+
+void importLogScript(Script& script)
+{
+       script.importFunction("print", (int (*)(Script&))logScript);
+}
+
 
 } // namespace Mf
 
index 263ede8fdff0d950743139b39a5f2159c166728b..09130ed5010aeb535eef7abc09802d959494c98e 100644 (file)
@@ -66,8 +66,9 @@ enum LogLevel
        LOG_NONE                = -1,           ///< Disable all logging.
        LOG_ERROR               =  1,           ///< Log only errors.
        LOG_WARNING             =  2,           ///< Log warnings and errors.
-       LOG_INFO                =  3,           ///< Log info, warnings, errors.
-       LOG_DEBUG               =  4            ///< Log all messages.
+       LOG_SCRIPT              =  3,           ///< Log messages from Lua, too.
+       LOG_INFO                =  4,           ///< Log info, warnings, errors.
+       LOG_DEBUG               =  5,           ///< Log all messages.
 };
 
 
@@ -113,6 +114,10 @@ void logInfo(const char* fmt, ...);
 
 void logDebug(const char* fmt, ...);
 
+class Script;
+int logScript(Script& script);
+void importLogScript(Script& script);
+
 
 } // namespace Mf
 
index 2e1a79363302ebb527e8a0c9d7ce8a13480495f3..fe49ed276d8706edc8626b566db7db51dd108dd8 100644 (file)
@@ -368,40 +368,6 @@ struct Meh
 };
 
 
-static int luaPrint(Script& script)
-{
-       Script::Value param = script[1];
-
-       while (!param.isNone())
-       {
-               if (param.isString())
-               {
-                       std::string str;
-                       param.get(str);
-                       logInfo("lua: %s", str.c_str());
-               }
-               else if (param.isBoolean())
-               {
-                       if (param) logInfo("lua: true");
-                       else logInfo("lua: false");
-
-               }
-               else if (param.isNil())
-               {
-                       logInfo("lua: nil");
-               }
-               else
-               {
-                       logInfo("lua: %s (%X)", param.getTypeName().c_str(),
-                                       param.getIdentifier());
-               }
-
-               param.index++;
-       }
-
-       return 0;
-}
-
 static void importScriptBindings(Script& script, Meh& scene)
 {
        script.importFunction("SetPlayfieldBounds",
@@ -422,7 +388,6 @@ static void importScriptBindings(Script& script, Meh& scene)
                        boost::bind(&Meh::makeTilemap, &scene, _1));
        script.importFunction("MakeBillboard",
                        boost::bind(&Meh::makeBillboard, &scene, _1));
-       script.importFunction("print", luaPrint);
 }
 
 
@@ -430,14 +395,15 @@ OctreeP loadScene(const std::string& name)
 {
        std::string filePath = getPath(name);
 
+       Meh cool;
+
        Script script;
        script.importStandardLibraries();
-
-       Meh cool;
+       importLogScript(script);
        importScriptBindings(script, cool);
 
        long detail = 3;
-       Settings::getInstance().getNumber("game.detail", detail);
+       Settings::getInstance().get("detail", detail);
 
        script.push(detail);
        script.set("detail");
index b48f5f440ae04b49f3a6f778cf3e3e3eb4d3ccb1..f954e583488a786e2740c7042a4ab89782697577 100644 (file)
@@ -39,7 +39,9 @@
  */
 
 #include <list>
+#include <map>
 #include <string>
+#include <vector>
 
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
@@ -48,6 +50,7 @@
 #include <lua.hpp>
 
 #include <Moof/Exception.hh>
+#include <Moof/Log.hh>
 
 
 namespace Mf {
@@ -119,11 +122,7 @@ struct Script
                 * Value will be invalid even if index is manually changed to a valid
                 * index.  You have to index the script itself to get a valid Value.
                 */
-               Value() :
-                       index(0),
-                       state(0) {}
-
-               Value(lua_State* s, int i) :
+               Value(lua_State* s = 0, int i = 0) :
                        index(i),
                        state(s) {}
 
@@ -159,6 +158,23 @@ struct Script
                        return std::string(lua_typename(state, (int)getType()));
                }
 
+
+               /**
+                * Get the length of the value according to the definition given by Lua.
+                */
+
+               size_t getLength() const
+               {
+                       return lua_objlen(state, index);
+               }
+
+               int getRealIndex() const
+               {
+                       if (index < 0) return lua_gettop(state) + 1 + index;
+                       else           return index;
+               }
+
+
                /**
                 * Get a pointer value (for userdata, tables, threads, and functions).
                 */
@@ -206,61 +222,115 @@ struct Script
                }
 
 
-               /**
-                * Get the length of the value according to the definition given by Lua.
-                */
-
-               size_t getLength() const
-               {
-                       return lua_objlen(state, index);
-               }
-
-
                /**
                 * Convert the underlying value to a C++ type.
                 */
 
                template <typename T>
-               void get(T& value) const
+               bool get(T& value) const
                {
-                       value = (T)lua_tointeger(state, index);
+                       if (isNumber())
+                       {
+                               value = (T)lua_tointeger(state, index);
+                               return true;
+                       }
+                       return false;
                }
 
-               void get(bool& value) const
+               bool get(float& value) const
                {
-                       value = (bool)lua_toboolean(state, index);
+                       if (isNumber())
+                       {
+                               value = (float)lua_tonumber(state, index);
+                               return true;
+                       }
+                       return false;
                }
-
-               void get(float& value) const
+               bool get(double& value) const
                {
-                       value = (float)lua_tonumber(state, index);
+                       if (isNumber())
+                       {
+                               value = (double)lua_tonumber(state, index);
+                               return true;
+                       }
+                       return false;
                }
-               void get(double& value) const
+
+               bool get(bool& value) const
                {
-                       value = (double)lua_tonumber(state, index);
+                       if (isBoolean())
+                       {
+                               value = (bool)lua_toboolean(state, index);
+                               return true;
+                       }
+                       return false;
                }
 
-               void get(std::string& value) const
+               bool get(std::string& value) const
                {
-                       size_t size;
-                       const char* str = lua_tolstring(state, index, &size);
-                       value.assign(str, size);
+                       if (isString())
+                       {
+                               size_t size;
+                               const char* str = lua_tolstring(state, index, &size);
+                               value.assign(str, size);
+                               return true;
+                       }
+                       return false;
                }
 
+               template <typename T>
+               bool get(std::vector<T>& array) const
+               {
+                       if (!isTable()) return false;
+
+                       array.clear();
 
-               void set(std::string& value)
+                       Value   value(state, -1);
+                       int             realIndex = getRealIndex();
+
+                       bool done = false;
+                       for (int i = 1; !done; ++i)
+                       {
+                               lua_rawgeti(state, realIndex, i);
+
+                               T v;
+                               if (value.get(v)) array.push_back(v);
+                               else              done = true;
+
+                               lua_pop(state, 1);
+                       }
+
+                       return true;
+               }
+
+               template <typename T>
+               bool get(std::map<std::string,T>& dictionary) const
                {
+                       if (!isTable()) return false;
+
+                       dictionary.clear();
+
+                       Value   key(state, -2);
+                       Value   value(state, -1);
+                       int             realIndex = getRealIndex();
+
+                       lua_pushnil(state);
+                       while (lua_next(state, realIndex) != 0)
+                       {
+                               std::string k;
+                               if (!key.isNumber() && key.get(k))
+                               {
+                                       T v;
+                                       if (value.get(v)) dictionary[k] = v;
+                               }
+                               lua_pop(state, 1);
+                       }
+                       lua_pop(state, 1);
+
+                       return true;
                }
 
-               //template <typename T>
-               //void get(const std::string& field, T& value) const
-               //{
-                       ////lua_getfield(state_, field.c_str());
-                       //pushField(field);
-                       //get(-1, value);
-                       //lua_pop(state_, 1);
-               //}
-               
+
 
                /**
                 * Copy the value and push the copy to the stack.
@@ -557,7 +627,7 @@ struct Script
         * Pops n values from the top of the stack.
         */
 
-       void pop(int n)
+       void pop(int n = 1)
        {
                lua_pop(state_, n);
        }
index 6883ddc4f852d3edd4191957e81529f87f155c8a..53cb850f5a6f1cc661057ca4c6f10d4e5a31b3b2 100644 (file)
 
 #include <sstream>
 #include <cstdlib>             // getenv
-#include <cstring>             // strchr
 
-#include <boost/algorithm/string.hpp>
-
-#include "Log.hh"
 #include "Settings.hh"
 
 
 namespace Mf {
 
 
-Settings::Settings(int argc, char* argv[])
-{
-       parseArgs(argc, argv);
-}
-
-
 Settings& Settings::getInstance()
 {
        static Settings settings;
@@ -56,44 +46,20 @@ void Settings::parseArgs(int argc, char* argv[])
 {
        for (int i = 1; i < argc; ++i)
        {
-               char* where = strchr(argv[i], (int)'=');
-
-               if (where)
-               {
-                       std::string key(argv[i], (size_t)(where - argv[i]));
-                       std::string stringValue(where + 1);
-
-                       std::stringstream stream;
-                       stream << stringValue << std::endl;
-
-                       Deserializer deserializer(stream);
-
-                       try
-                       {
-                               SerializableP value(deserializer.deserialize());
-                               map_[key] = value;
-                       }
-                       catch (std::exception e)
-                       {
-                               // it doesn't deserialize to anything we know, so just store it
-                               // as a string
-                               map_[key] = SerializableP(new SerializableBasic<Serializable::String>(stringValue));
-                       }
-               }
+               script_.doString(argv[i]);
        }
 }
 
 
-void Settings::loadFromFile(const std::string& filePath, bool precedence)
+void Settings::loadFromFile(const std::string& filePath)
 {
        std::vector<std::string> paths;
        boost::split(paths, filePath, boost::is_any_of(":"));
 
-       loadFromFiles(paths, precedence);
+       loadFromFiles(paths);
 }
 
-void Settings::loadFromFiles(const std::vector<std::string>& filePaths,
-               bool precedence)
+void Settings::loadFromFiles(const std::vector<std::string>& filePaths)
 {
        std::vector<std::string>::const_iterator it;
 
@@ -108,30 +74,12 @@ void Settings::loadFromFiles(const std::vector<std::string>& filePaths,
                        boost::replace_all(path, "$HOME", home);
                }
 
-               try
-               {
-                       Deserializer deserializer(*it, true);
-
-                       SerializableP obj = deserializer.deserialize();
-                       Serializable::Map map;
-
-                       if (obj && obj->get(map))
-                       {
-                               if (!precedence)
-                               {
-                                       map_.insert(map.begin(), map.end());
-                               }
-                               else
-                               {
-                                       map.insert(map_.begin(), map_.end());
-                                       map_ = map;
-                               }
-                       }
-               }
-               catch (Deserializer::Exception e)
+               if (script_.doFile(path) != Script::SUCCESS)
                {
-                       logWarning("cannot load settings from %s because an exception was"
-                                       "thrown: %s", (*it).c_str(), e.what());
+                       std::string str;
+                       script_[-1].get(str);
+                       logWarning("running config file: %s", str.c_str());
+                       script_.clear();
                }
        }
 }
index 653d4561dd1e2af4dd4b66ddcd1232b90b893f1d..dc29deb3ad260e772348bd8c40abe7e080a271c4 100644 (file)
  * Load, store, save program settings.
  */
 
-#include <map>
 #include <string>
+#include <vector>
 
-#include <Moof/Serializable.hh>
+#include <boost/algorithm/string.hpp>
+
+#include <Moof/Log.hh>
+#include <Moof/Script.hh>
 
 
 namespace Mf {
@@ -46,58 +49,55 @@ namespace Mf {
 class Settings
 {
 public:
-       Settings() {}
-       Settings(int argc, char* argv[]);
+       Settings() :
+               globals_(script_.getGlobalTable()),
+               top_(script_[-1])
+       {
+               importLogScript(script_);
+       }
 
        // get global instance
        static Settings& getInstance();
 
        void parseArgs(int argc, char* argv[]);
 
-       void loadFromFile(const std::string& filePath, bool precedence = false);
-       void loadFromFiles(const std::vector<std::string>& filePaths,
-                       bool precedence = false);
+       void loadFromFile(const std::string& filePath);
+       void loadFromFiles(const std::vector<std::string>& filePaths);
 
        template <typename T>
        bool get(const std::string& key, T& value);
-       template <typename T>
-       bool getNumber(const std::string& key, T& value);
 
 private:
-       Serializable::Map map_;
+       Script                  script_;
+       Script::Value   globals_, top_;
 };
 
 
 template <typename T>
 bool Settings::get(const std::string& key, T& value)
 {
-       Serializable::Map::const_iterator it = map_.find(key);
+       std::vector<std::string> fields;
+       boost::split(fields, key, boost::is_any_of("."));
 
-       if (it != map_.end())
-       {
-               SerializableP obj = (*it).second;
-               return obj->get(value);
-       }
-       else
-       {
-               return false;
-       }
-}
-
-template <typename T>
-bool Settings::getNumber(const std::string& key, T& value)
-{
-       Serializable::Map::const_iterator it = map_.find(key);
+       globals_.pushCopy();
 
-       if (it != map_.end())
+       std::vector<std::string>::iterator it;
+       for (it = fields.begin(); it != fields.end(); ++it)
        {
-               SerializableP obj = (*it).second;
-               return obj->getNumber(value);
-       }
-       else
-       {
-               return false;
+               if (top_.isTable())
+               {
+                       top_.pushField(*it);
+               }
+               else
+               {
+                       script_.clear();
+                       return false;
+               }
        }
+
+       bool got = top_.get(value);
+       script_.clear();
+       return got;
 }
 
 
index d9a673c58d58698545904c23b05e7c15e093d9de..4cb291300850dec5c29e38a1808c42a986287789 100644 (file)
@@ -524,13 +524,13 @@ bool Sound::isPlaying() const
        return impl_->isPlaying();
 }
 
-void Sound::setPosition(Vector3 position)
+void Sound::setPosition(const Vector3& position)
 {
        float p[3] = {position[0], position[1], position[2]};
        alSourcefv(impl_->source_, AL_POSITION, p);
 }
 
-void Sound::setVelocity(Vector3 velocity)
+void Sound::setVelocity(const Vector3& velocity)
 {
        float v[3] = {velocity[0], velocity[1], velocity[2]};
        alSourcefv(impl_->source_, AL_VELOCITY, v);
@@ -553,6 +553,31 @@ void Sound::setLooping(bool looping)
 }
 
 
+void Sound::setListenerPosition(const Vector3& position)
+{
+       alListener3f(AL_POSITION, float(position[0]), float(position[1]),
+                       float(position[2]));
+}
+
+void Sound::setListenerVelocity(const Vector3& velocity)
+{
+       alListener3f(AL_VELOCITY, float(velocity[0]), float(velocity[1]),
+                       float(velocity[2]));
+}
+
+void Sound::setListenerOrientation(const Vector3& forward, const Vector3& up)
+{
+       float vec[6];
+       vec[0] = float(forward[0]);
+       vec[1] = float(forward[1]);
+       vec[2] = float(forward[2]);
+       vec[3] = float(up[0]);
+       vec[4] = float(up[1]);
+       vec[5] = float(up[2]);
+       alListenerfv(AL_ORIENTATION, vec);
+}
+
+
 std::string Sound::getPath(const std::string& name)
 {
        std::string path = Resource::getPath("sounds/" + name + ".ogg");
index c9929cedeae2169b4c61bedf7d557802395f47ba..e5d312a776acfe26533a2224260a16c95bd1d2e6 100644 (file)
@@ -80,12 +80,17 @@ public:
 
        bool isPlaying() const;
 
-       void setPosition(Vector3 position);
-       void setVelocity(Vector3 velocity);
+       void setPosition(const Vector3& position);
+       void setVelocity(const Vector3& velocity);
        void setGain(Scalar gain);
        void setPitch(Scalar pitch);
        void setLooping(bool looping);
 
+       static void setListenerPosition(const Vector3& position);
+       static void setListenerVelocity(const Vector3& velocity);
+       static void setListenerOrientation(const Vector3& forward,
+                       const Vector3& up);
+
        static std::string getPath(const std::string& name);
 
 
index 8610a7b8be499e1106d741433d98f7beab9cb513..ef966c7996e91fc2f33ca6aa6a5604d31ca2504d 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "Dispatcher.hh"
 #include "Log.hh"
-#include "Serializable.hh"
 #include "Settings.hh"
 #include "Video.hh"
 
@@ -319,47 +318,50 @@ Video::Attributes::Attributes()
 
        Settings& settings = Settings::getInstance();
 
-       Serializable::Array colors;
-       settings.get("video.colorbuffers", colors);
-       if (colors.size() > 0) colors[0]->get(colorBuffer[0]);
-       if (colors.size() > 1) colors[1]->get(colorBuffer[1]);
-       if (colors.size() > 2) colors[2]->get(colorBuffer[2]);
-       if (colors.size() > 3) colors[3]->get(colorBuffer[3]);
-
-       settings.get("video.framebuffer", frameBuffer);
-       settings.get("video.doublebuffer", doubleBuffer);
-       settings.get("video.depthbuffer", depthBuffer);
-       settings.get("video.stencilbuffer", stencilBuffer);
-
-       Serializable::Array accum;
-       settings.get("video.accumbuffers", accum);
-       if (accum.size() > 0) accum[0]->get(accumBuffer[0]);
-       if (accum.size() > 1) accum[1]->get(accumBuffer[1]);
-       if (accum.size() > 2) accum[2]->get(accumBuffer[2]);
-       if (accum.size() > 3) accum[3]->get(accumBuffer[3]);
-
-       settings.get("video.stereo", stereo);
-       settings.get("video.multiesamplebuffers", multisampleBuffers);
-       settings.get("video.multiesamplesamples", multisampleSamples);
-       settings.get("video.swapcontrol", swapControl);
-       settings.get("video.hardwareonly", hardwareonly);
-
-       if (!settings.get("video.caption", caption))
+       std::vector<long> colors;
+       settings.get("colorbuffers", colors);
+       if (colors.size() > 0) colorBuffer[0] = colors[0];
+       if (colors.size() > 1) colorBuffer[1] = colors[1];
+       if (colors.size() > 2) colorBuffer[2] = colors[2];
+       if (colors.size() > 3) colorBuffer[3] = colors[3];
+
+       settings.get("framebuffer", frameBuffer);
+       settings.get("doublebuffer", doubleBuffer);
+       settings.get("depthbuffer", depthBuffer);
+       settings.get("stencilbuffer", stencilBuffer);
+
+       std::vector<long> accum;
+       settings.get("accumbuffers", accum);
+       if (accum.size() > 0) accumBuffer[0] = accum[0];
+       if (accum.size() > 1) accumBuffer[1] = accum[1];
+       if (accum.size() > 2) accumBuffer[2] = accum[2];
+       if (accum.size() > 3) accumBuffer[3] = accum[3];
+
+       settings.get("stereo", stereo);
+       settings.get("multiesamplebuffers", multisampleBuffers);
+       settings.get("multiesamplesamples", multisampleSamples);
+       settings.get("swapcontrol", swapControl);
+       settings.get("hardwareonly", hardwareonly);
+
+       if (!settings.get("caption", caption))
        {
                caption = "Untitled";
        }
-       settings.get("video.icon", icon);
-
-       Serializable::Array dimensions;
-       settings.get("video.mode", dimensions);
-       if (dimensions.size() > 0) dimensions[0]->get(mode[0]);
-       if (dimensions.size() > 1) dimensions[1]->get(mode[1]);
-       if (dimensions.size() > 2) dimensions[2]->get(mode[2]);
-
-       settings.get("video.fullscreen", fullscreen);
-       settings.get("video.resizable", resizable);
-       settings.get("video.showcursor", cursorVisible);
-       settings.get("input.grab", cursorGrab);
+       settings.get("icon", icon);
+
+       std::vector<long> dimensions;
+       settings.get("videomode", dimensions);
+       if (dimensions.size() > 1)
+       {
+               mode[0] = dimensions[0];
+               mode[1] = dimensions[1];
+       }
+       if (dimensions.size() > 2) mode[2] = dimensions[2];
+
+       settings.get("fullscreen", fullscreen);
+       settings.get("resizable", resizable);
+       settings.get("showcursor", cursorVisible);
+       settings.get("grab", cursorGrab);
 }
 
 
index a8a06cc82f6d1e6f9f694fda7114c3c7f322ef08..8690143d16b7356439849753bff0468ec8575a83 100644 (file)
@@ -27,6 +27,7 @@
 *******************************************************************************/
 
 #include <cstdlib>             // getenv
+#include <cstring>
 #include <iostream>
 #include <string>
 
@@ -50,34 +51,24 @@ static std::string configFiles()
 {
        std::string files;
 
-       char* configFile = getenv("YOINKRC");
+       // look in the configured data directory last of all
        char* dataDir = getenv("YOINK_DATADIR");
-
-       if (configFile)
-       {
-               // if a config file from the environment variable is specified, we want
-               // to load it first so it has precedence
-               files += configFile;
-               files += ":";
-       }
+       files += (dataDir ? dataDir : YOINK_DATADIR);
+       files += "/yoinkrc";
 
        // add the colon-delimited paths from configure
+       files += ":";
        files += YOINK_CONFIGFILES;
 
-       if (dataDir)
+       char* configFile = getenv("YOINKRC");
+       if (configFile)
        {
-               // if another data directory is set in the environment, look for a
-               // config file there
+               // if a config file from the environment variable is specified, we want
+               // to load it first so it has precedence
                files += ":";
-               files += dataDir;
-               files += "/yoinkrc";
+               files += configFile;
        }
 
-       // look in the configured data directory last of all
-       files += ":";
-       files += (dataDir ? dataDir : YOINK_DATADIR);
-       files += "/yoinkrc";
-
        return files;
 }
 
@@ -187,6 +178,10 @@ void YoinkApp::update(Mf::Scalar t, Mf::Scalar dt)
        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));
@@ -301,9 +296,33 @@ void YoinkApp::handleEvent(const Mf::Event& event)
 }
 
 
+void printUsage()
+{
+       std::cout << "Usage: "PACKAGE" [-h|--help] [OPTION=VALUE]..." << std::endl
+                         << "The alien-smashing action game." << std::endl
+                         << std::endl
+                         << "Options:" << std::endl
+                         << "  -h, --help" << std::endl
+                         << "      show this help and exit" << std::endl
+                         << "  detail=1|2|3" << std::endl
+                         << "      the level of detail of game scenes" << std::endl
+                         << "  fullscreen=true|false" << std::endl
+                         << "      if true, uses the entire display" << std::endl
+                         << "  maxfps=num" << std::endl
+                         << "      the maximum number of frames per second" << std::endl
+                         << std::endl
+                         << "See documentation for more options." << std::endl;
+}
 
 int main(int argc, char* argv[])
 {
+       if (argc > 1 &&
+                       (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0))
+       {
+               printUsage();
+               return 0;
+       }
+
        std::cout << std::endl << PACKAGE_STRING << std::endl
                          << "Compiled " << __TIME__ " " __DATE__ << std::endl
                          << "Send patches and bug reports to <"
@@ -314,7 +333,7 @@ int main(int argc, char* argv[])
 #elif  YOINK_LOGLEVEL >= 3
        Mf::setLogLevel(Mf::LOG_INFO);
 #elif  YOINK_LOGLEVEL >= 2
-       Mf::setLogLevel(Mf::LOG_WARNING);
+       Mf::setLogLevel(Mf::LOG_SCRIPT);
 #elif  YOINK_LOGLEVEL >= 1
        Mf::setLogLevel(Mf::LOG_ERROR);
 #elif  YOINK_LOGLEVEL
This page took 0.054714 seconds and 4 git commands to generate.