From: Charles McGarvey Date: Mon, 12 Oct 2009 20:39:42 +0000 (-0600) Subject: settings subsystem now using lua X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;h=ca0f7bdfba63140dca0bd20586d31980f3938eb2;p=chaz%2Fyoink settings subsystem now using lua --- diff --git a/configure.ac b/configure.ac index 47ee0ba..7d8d545 100644 --- a/configure.ac +++ b/configure.ac @@ -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.]) diff --git a/data/yoinkrc b/data/yoinkrc index 2faf40d..bcb0f06 100644 --- a/data/yoinkrc +++ b/data/yoinkrc @@ -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 + diff --git a/doc/yoink.6.in b/doc/yoink.6.in index d9e90bf..2432bd5 100644 --- a/doc/yoink.6.in +++ b/doc/yoink.6.in @@ -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 diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index e97c8b5..18ce5d7 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -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); } } diff --git a/src/Moof/Log.cc b/src/Moof/Log.cc index 0639a60..96c7095 100644 --- a/src/Moof/Log.cc +++ b/src/Moof/Log.cc @@ -31,6 +31,7 @@ #include // 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 diff --git a/src/Moof/Log.hh b/src/Moof/Log.hh index 263ede8..09130ed 100644 --- a/src/Moof/Log.hh +++ b/src/Moof/Log.hh @@ -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 diff --git a/src/Moof/Scene.cc b/src/Moof/Scene.cc index 2e1a793..fe49ed2 100644 --- a/src/Moof/Scene.cc +++ b/src/Moof/Scene.cc @@ -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"); diff --git a/src/Moof/Script.hh b/src/Moof/Script.hh index b48f5f4..f954e58 100644 --- a/src/Moof/Script.hh +++ b/src/Moof/Script.hh @@ -39,7 +39,9 @@ */ #include +#include #include +#include #include #include @@ -48,6 +50,7 @@ #include #include +#include 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 - 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 + bool get(std::vector& 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 + bool get(std::map& 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 - //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); } diff --git a/src/Moof/Settings.cc b/src/Moof/Settings.cc index 6883ddc..53cb850 100644 --- a/src/Moof/Settings.cc +++ b/src/Moof/Settings.cc @@ -28,23 +28,13 @@ #include #include // getenv -#include // strchr -#include - -#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(stringValue)); - } - } + script_.doString(argv[i]); } } -void Settings::loadFromFile(const std::string& filePath, bool precedence) +void Settings::loadFromFile(const std::string& filePath) { std::vector paths; boost::split(paths, filePath, boost::is_any_of(":")); - loadFromFiles(paths, precedence); + loadFromFiles(paths); } -void Settings::loadFromFiles(const std::vector& filePaths, - bool precedence) +void Settings::loadFromFiles(const std::vector& filePaths) { std::vector::const_iterator it; @@ -108,30 +74,12 @@ void Settings::loadFromFiles(const std::vector& 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(); } } } diff --git a/src/Moof/Settings.hh b/src/Moof/Settings.hh index 653d456..dc29deb 100644 --- a/src/Moof/Settings.hh +++ b/src/Moof/Settings.hh @@ -34,10 +34,13 @@ * Load, store, save program settings. */ -#include #include +#include -#include +#include + +#include +#include 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& filePaths, - bool precedence = false); + void loadFromFile(const std::string& filePath); + void loadFromFiles(const std::vector& filePaths); template bool get(const std::string& key, T& value); - template - bool getNumber(const std::string& key, T& value); private: - Serializable::Map map_; + Script script_; + Script::Value globals_, top_; }; template bool Settings::get(const std::string& key, T& value) { - Serializable::Map::const_iterator it = map_.find(key); + std::vector 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 -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::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; } diff --git a/src/Moof/Sound.cc b/src/Moof/Sound.cc index d9a673c..4cb2913 100644 --- a/src/Moof/Sound.cc +++ b/src/Moof/Sound.cc @@ -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"); diff --git a/src/Moof/Sound.hh b/src/Moof/Sound.hh index c9929ce..e5d312a 100644 --- a/src/Moof/Sound.hh +++ b/src/Moof/Sound.hh @@ -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); diff --git a/src/Moof/Video.cc b/src/Moof/Video.cc index 8610a7b..ef966c7 100644 --- a/src/Moof/Video.cc +++ b/src/Moof/Video.cc @@ -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 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 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 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); } diff --git a/src/YoinkApp.cc b/src/YoinkApp.cc index a8a06cc..8690143 100644 --- a/src/YoinkApp.cc +++ b/src/YoinkApp.cc @@ -27,6 +27,7 @@ *******************************************************************************/ #include // getenv +#include #include #include @@ -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