]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Scene.cc
new lua scripting for scene loading
[chaz/yoink] / src / Moof / Scene.cc
index 418c0512e3c690e4f29406181cac8346c67ada80..2e1a79363302ebb527e8a0c9d7ce8a13480495f3 100644 (file)
 
 #include "Aabb.hh"
 #include "Camera.hh"
-#include "Deserializer.hh"
 #include "Entity.hh"
 #include "Log.hh"
 #include "Math.hh"
 #include "Scene.hh"
-#include "Serializable.hh"
+#include "Script.hh"
+#include "Settings.hh"
 #include "Tilemap.hh"
 
 
 namespace Mf {
 
 
-static void loadBox(Aabb& theBox, SerializableP obj)
+static std::string getPath(const std::string& name)
 {
-       Serializable::Array numbers;
-
-       if (obj->get(numbers) && numbers.size() == 6)
-       {
-               Serializable::Float num;
-
-               if (numbers[0]->getNumber(num)) theBox.min[0] = Scalar(num);
-               if (numbers[1]->getNumber(num)) theBox.min[1] = Scalar(num);
-               if (numbers[2]->getNumber(num)) theBox.min[2] = Scalar(num);
-               if (numbers[3]->getNumber(num)) theBox.max[0] = Scalar(num);
-               if (numbers[4]->getNumber(num)) theBox.max[1] = Scalar(num);
-               if (numbers[5]->getNumber(num)) theBox.max[2] = Scalar(num);
-       }
+       return Resource::getPath("scenes/" + name + ".lua");
 }
 
 
-static void loadTilemap(SerializableP root, const Matrix4& transform,
-               const std::string& texture, OctreeP octree)
+struct Meh
 {
-       Serializable::Map rootObj;
-       Serializable::Map::iterator it;
+       Matrix4         transform;
+       std::string     texture;
+
+       OctreeP         octree;
 
-       if (!root->get(rootObj))
+       Meh()
        {
-               logError("invalid tilemap instruction");
-               return;
+               octree = Octree::alloc(Aabb());
        }
 
-       long width = 1;
-       long height = 1;
-       std::vector< std::vector<Tilemap::Index> > indices;
-
-       if ((it = rootObj.find("width")) != rootObj.end())
+       static int loadBox(Script& script, Aabb& aabb)
        {
-               (*it).second->get(width);
+               Script::Value table[] = {script[1], script[2]};
+
+               if (!table[0].isTable() || !table[1].isTable())
+               {
+                       logWarning("wrong arguments to setPlayfieldBounds; ignoring...");
+                       return 0;
+               }
+
+               for (int i = 0; i <= 1; ++i)
+               {
+                       for (int j = 1; j <= 3; ++j)
+                       {
+                               script.push((long)j);
+                               table[i].pushField();
+                       }
+               }
+
+               script[3].get(aabb.min[0]);
+               script[4].get(aabb.min[1]);
+               script[5].get(aabb.min[2]);
+               script[6].get(aabb.max[0]);
+               script[7].get(aabb.max[1]);
+               script[8].get(aabb.max[2]);
+
+               return 0;
        }
-       else
+
+       int setPlayfieldBounds(Script& script)
        {
-               logError("missing required field width for tilemap instruction");
-               return;
+               Aabb bounds;
+               return loadBox(script, bounds);
        }
 
-       Serializable::Array tiles;
-
-       if ((it = rootObj.find("tiles")) != rootObj.end() &&
-                       (*it).second->get(tiles) &&
-                       tiles.size() % width == 0)
+       int setMaximumBounds(Script& script)
        {
-               Serializable::Array::iterator jt;
-               int w, h;
+               Aabb bounds;
+               int ret = loadBox(script, bounds);
+               octree = Octree::alloc(bounds);
+               return ret;
+       }
 
-               height = tiles.size() / width;
-               indices.resize(height);
+       int resetTransform(Script& script)
+       {
+               transform.identity();
+               return 0;
+       }
 
-               // 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
+       int translate(Script& script)
+       {
+               Script::Value x = script[1];
+               Script::Value y = script[2];
+               Script::Value z = script[3];
 
-               for (h = height - 1, jt = tiles.begin(); jt != tiles.end(); --h)
+               if (!x.isNumber() || !y.isNumber() || !z.isNumber())
                {
-                       std::vector<Tilemap::Index> row;
+                       logWarning("wrong arguments to translate; ignoring...");
+                       return 0;
+               }
 
-                       for (w = 0; w < width && jt != tiles.end(); ++w, ++jt)
-                       {
-                               Serializable::Integer index;
+               Vector3 vec;
+               x.get(vec[0]);
+               y.get(vec[1]);
+               z.get(vec[2]);
 
-                               if ((*jt)->get(index))
-                               {
-                                       row.push_back(Tilemap::Index(index));
-                               }
-                       }
+               Matrix4 translation;
+               cml::matrix_translation(translation, vec);
+               transform = translation * transform;
 
-                       indices[h] = row;
-               }
+               return 0;
        }
-       else
+
+       int scale(Script& script)
        {
-               logError("invalid tiles in tilemap instruction");
-               return;
-       }
+               if (script.getSize() == 3)
+               {
+                       Vector3 vec;
+                       script[1].get(vec[0]);
+                       script[2].get(vec[1]);
+                       script[3].get(vec[2]);
+
+                       Matrix4 scaling;
+                       cml::matrix_scale(scaling, vec);
+                       transform = scaling * transform;
+               }
+               else if (script.getSize() == 1)
+               {
+                       Scalar value = 1.0;
+                       script[1].get(value);
 
-       Vector4 vertices[height+1][width+1];
+                       Matrix4 scaling;
+                       cml::matrix_uniform_scale(scaling,
+                                       Scalar(value));
+                       transform = scaling * transform;
+               }
+               else
+               {
+                       logWarning("wrong arguments to scale; ignoring...");
+               }
 
-       Matrix4 transposedTransform = transform;
-       transposedTransform.transpose();
+               return 0;
+       }
 
-       for (int h = 0; h <= height; ++h)
+       int rotate(Script& script)
        {
-               for (int w = 0; w <= width; ++w)
+               Script::Value a = script[1];
+               Script::Value d = script[2];
+
+               if (!a.isString() || !d.isNumber())
                {
-                       vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) *
-                               transposedTransform;
+                       logWarning("wrong arguments to rotate; ignoring...");
+                       return 0;
                }
+
+               std::string axis;
+               a.get(axis);
+
+               size_t index = 0;
+               if (axis == "x")      index = 0;
+               else if (axis == "y") index = 1;
+               else if (axis == "z") index = 2;
+
+               Scalar value;
+               d.get(value);
+
+               cml::matrix_rotate_about_world_axis(transform,
+                               index, cml::rad(Scalar(value)));
+
+               return 0;
        }
 
-       for (int h = 0; h < height; ++h)
+       int setTexture(Script& script)
        {
-               for (int w = 0; w < width; ++w)
-               {
-                       if (indices[h][w] == Tilemap::NO_TILE) continue;
+               Script::Value t = script[1];
 
-                       Vector3 quadVertices[4];
+               if (t.isString()) t.get(texture);
+               else logWarning("wrong arguments to setTexture; ignoring...");
 
-                       demoteVector(quadVertices[0], vertices[h][w]);
-                       demoteVector(quadVertices[1], vertices[h][w+1]);
-                       demoteVector(quadVertices[2], vertices[h+1][w+1]);
-                       demoteVector(quadVertices[3], vertices[h+1][w]);
+               return 0;
+       }
 
-                       Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
-                       boost::shared_ptr<Quad> quadPtr(quad);
+       int makeTilemap(Script& script)
+       {
+               Script::Value table = script[1];
+               Script::Value top = script[-1];
 
-                       octree->insert(quadPtr);
+               if (!table.isTable())
+               {
+                       logWarning("wrong arguments to makeTilemap; ignoring...");
+                       return 0;
                }
-       }
-}
 
-static void loadBillboard(SerializableP root, const Matrix4& transform,
-               const std::string& texture, OctreeP octree)
-{
-       Serializable::Map rootObj;
-       Serializable::Map::iterator it;
+               long width = 1;
+               long height = 1;
 
-       Tilemap::Index  index = 0;
-       long                    width = 1;
-       bool                    blending = false;
-       bool                    fog = false;
+               table.pushField("width");
+               top.get(width);
 
-       if (root->get(rootObj))
-       {
-               if ((it = rootObj.find("tile")) != rootObj.end())
+               long nTiles = 0;
+
+               table.pushField("tiles");
+               Script::Value tiles = script.getTop();
+               nTiles = tiles.getLength();
+
+               std::vector< std::vector<Tilemap::Index> > indices;
+
+               if (nTiles % width == 0)
                {
-                       Serializable::Integer value;
-                       if ((*it).second->get(value))
+                       int i, w, h;
+
+                       height = nTiles / width;
+                       indices.resize(height);
+
+                       // 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
+
+                       i = 1;
+                       for (h = height - 1; h >= 0; --h)
                        {
-                               index = Tilemap::Index(value);
+                               std::vector<Tilemap::Index> row;
+
+                               for (w = 0; w < width; ++w, ++i)
+                               {
+                                       script.checkStack(2);
+                                       script.push(long(i));
+                                       tiles.pushField();
+
+                                       long index;
+                                       top.get(index);
+
+                                       row.push_back(Tilemap::Index(index));
+                               }
+
+                               indices[h] = row;
                        }
                }
-
-               if ((it = rootObj.find("u_scale")) != rootObj.end())
+               else
                {
-                       (*it).second->get(width);
+                       logError("invalid tiles in tilemap instruction");
+                       return 0;
                }
 
-               if ((it = rootObj.find("blend")) != rootObj.end())
-               {
-                       (*it).second->get(blending);
-               }
+               Vector4 vertices[height+1][width+1];
+
+               Matrix4 transposedTransform = transform;
+               transposedTransform.transpose();
 
-               if ((it = rootObj.find("fog")) != rootObj.end())
+               for (int h = 0; h <= height; ++h)
                {
-                       (*it).second->get(fog);
+                       for (int w = 0; w <= width; ++w)
+                       {
+                               vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) *
+                                       transposedTransform;
+                       }
                }
-       }
 
+               for (int h = 0; h < height; ++h)
+               {
+                       for (int w = 0; w < width; ++w)
+                       {
+                               if (indices[h][w] == Tilemap::NO_TILE) continue;
 
-       Vector4 vertices[2][width+1];
+                               Vector3 quadVertices[4];
 
-       Matrix4 transposedTransform = transform;
-       transposedTransform.transpose();
+                               demoteVector(quadVertices[0], vertices[h][w]);
+                               demoteVector(quadVertices[1], vertices[h][w+1]);
+                               demoteVector(quadVertices[2], vertices[h+1][w+1]);
+                               demoteVector(quadVertices[3], vertices[h+1][w]);
 
-       Scalar xf;
-       Scalar increment = 1.0 / Scalar(width);
+                               Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
+                               boost::shared_ptr<Quad> quadPtr(quad);
 
-       for (int h = 0; h <= 1; ++h)
-       {
-               xf = 0.0;
-               for (int w = 0; w <= width; ++w, xf += increment)
-               {
-                       vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) *
-                               transposedTransform;
+                               octree->insert(quadPtr);
+                       }
                }
+
+               return 0;
        }
 
-       for (int w = 0; w < width; ++w)
+       int makeBillboard(Script& script)
        {
-               Vector3 quadVertices[4];
-
-               demoteVector(quadVertices[0], vertices[0][w]);
-               demoteVector(quadVertices[1], vertices[0][w+1]);
-               demoteVector(quadVertices[2], vertices[1][w+1]);
-               demoteVector(quadVertices[3], vertices[1][w]);
+               Script::Value table = script[1];
+               Script::Value top = script[-1];
 
-               Quad* quad = new Quad(quadVertices, texture, index);
-               quad->setBlending(blending);
-               quad->setFog(fog);
+               long    index = 0;
+               long    width = 1;
+               bool    blending = false;
+               bool    fog = false;
 
-               boost::shared_ptr<Quad> quadPtr(quad);
+               if (table.isTable())
+               {
+                       table.pushField("tile");
+                       if (top.isNumber()) top.get(index);
 
-               octree->insert(quadPtr);
-       }
-}
+                       table.pushField("u_scale");
+                       if (top.isNumber()) top.get(width);
 
+                       table.pushField("blend");
+                       if (top.isBoolean()) top.get(blending);
 
-static void loadInstructions(SerializableP root, OctreeP octree)
-{
-       Serializable::Array rootObj;
-       Serializable::Array::iterator it;
+                       table.pushField("fog");
+                       if (top.isBoolean()) top.get(fog);
+               }
 
-       if (!root->get(rootObj))
-       {
-               logError("scene instructions must be an array");
-               return;
-       }
+               Vector4 vertices[2][width+1];
 
-       Matrix4         transform;
-       std::string     texture;
+               Matrix4 transposedTransform = transform;
+               transposedTransform.transpose();
 
-       for (it = rootObj.begin(); it != rootObj.end(); ++it)
-       {
-               std::string instruction;
+               Scalar xf;
+               Scalar increment = 1.0 / Scalar(width);
 
-               if ((*it)->get(instruction))
+               for (int h = 0; h <= 1; ++h)
                {
-                       if (instruction == "reset_transform")
+                       xf = 0.0;
+                       for (int w = 0; w <= width; ++w, xf += increment)
                        {
-                               transform.identity();
+                               vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) *
+                                       transposedTransform;
                        }
-                       else if (instruction == "translate")
-                       {
-                               Serializable::Array values;
+               }
 
-                               ++it;
-                               if ((*it)->get(values))
-                               {
-                                       Vector3 vec;
+               for (int w = 0; w < width; ++w)
+               {
+                       Vector3 quadVertices[4];
 
-                                       for (size_t i = 0; i < values.size(); ++i)
-                                       {
-                                               Serializable::Float value;
+                       demoteVector(quadVertices[0], vertices[0][w]);
+                       demoteVector(quadVertices[1], vertices[0][w+1]);
+                       demoteVector(quadVertices[2], vertices[1][w+1]);
+                       demoteVector(quadVertices[3], vertices[1][w]);
 
-                                               if (values[i]->getNumber(value))
-                                               {
-                                                       vec[i] = value;
-                                               }
-                                       }
+                       Quad* quad = new Quad(quadVertices, texture, Tilemap::Index(index));
+                       quad->setBlending(blending);
+                       quad->setFog(fog);
 
-                                       Matrix4 translation;
-                                       cml::matrix_translation(translation, vec);
-                                       transform = translation * transform;
-                               }
-                       }
-                       else if (instruction == "scale")
-                       {
-                               Serializable::Array values;
+                       boost::shared_ptr<Quad> quadPtr(quad);
 
-                               ++it;
-                               if ((*it)->get(values))
-                               {
-                                       if (values.size() == 1)
-                                       {
-                                               Serializable::Float value = 1.0;
-
-                                               values[0]->getNumber(value);
-
-                                               Matrix4 scaling;
-                                               cml::matrix_uniform_scale(scaling,
-                                                               Scalar(value));
-                                               transform = scaling * transform;
-                                       }
-                                       else if (values.size() == 3)
-                                       {
-                                               Vector3 vec;
-
-                                               for (size_t i = 0; i < values.size(); ++i)
-                                               {
-                                                       Serializable::Float value;
-
-                                                       if (values[i]->getNumber(value))
-                                                       {
-                                                               vec[i] = value;
-                                                       }
-                                               }
-
-                                               Matrix4 scaling;
-                                               cml::matrix_scale(scaling, vec);
-                                               transform = scaling * transform;
-                                       }
-                               }
-                       }
-                       else if (instruction == "rotate")
-                       {
-                               Serializable::Array values;
+                       octree->insert(quadPtr);
+               }
 
-                               ++it;
-                               if ((*it)->get(values))
-                               {
-                                       if (values.size() == 2)
-                                       {
-                                               std::string axis;
-                                               size_t index = 0;
-                                               Serializable::Float value = 0.0;
-
-                                               if (values[0]->get(axis))
-                                               {
-                                                       if (axis == "x")      index = 0;
-                                                       else if (axis == "y") index = 1;
-                                                       else if (axis == "z") index = 2;
-
-                                                       values[1]->getNumber(value);
-                                               }
-
-                                               cml::matrix_rotate_about_world_axis(transform,
-                                                               index, cml::rad(Scalar(value)));
-                                       }
-                               }
-                       }
-                       else if (instruction == "texture")
-                       {
-                               ++it;
-                               (*it)->get(texture);
-                       }
-                       else if (instruction == "tilemap")
-                       {
-                               ++it;
-                               loadTilemap(*it, transform, texture, octree);
-                       }
-                       else if (instruction == "billboard")
-                       {
-                               ++it;
-                               loadBillboard(*it, transform, texture, octree);
-                       }
+               return 0;
+       }
+};
+
+
+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 std::string getPath(const std::string& name)
+static void importScriptBindings(Script& script, Meh& scene)
 {
-       return Resource::getPath("scenes/" + name + ".json");
+       script.importFunction("SetPlayfieldBounds",
+                       boost::bind(&Meh::setPlayfieldBounds, &scene, _1));
+       script.importFunction("SetMaximumBounds",
+                       boost::bind(&Meh::setMaximumBounds, &scene, _1));
+       script.importFunction("ResetTransform",
+                       boost::bind(&Meh::resetTransform, &scene, _1));
+       script.importFunction("Translate",
+                       boost::bind(&Meh::translate, &scene, _1));
+       script.importFunction("Scale",
+                       boost::bind(&Meh::scale, &scene, _1));
+       script.importFunction("Rotate",
+                       boost::bind(&Meh::rotate, &scene, _1));
+       script.importFunction("SetTexture",
+                       boost::bind(&Meh::setTexture, &scene, _1));
+       script.importFunction("MakeTilemap",
+                       boost::bind(&Meh::makeTilemap, &scene, _1));
+       script.importFunction("MakeBillboard",
+                       boost::bind(&Meh::makeBillboard, &scene, _1));
+       script.importFunction("print", luaPrint);
 }
 
+
 OctreeP loadScene(const std::string& name)
 {
        std::string filePath = getPath(name);
 
-       Deserializer    deserializer(filePath, true);
-       SerializableP   root = deserializer.deserialize();
-
-       Serializable::Map rootObj;
-       Serializable::Map::iterator it;
-
-       if (!root || !root->get(rootObj))
-       {
-               logError("no root map in scene file");
-               return OctreeP();
-       }
+       Script script;
+       script.importStandardLibraries();
 
-       Aabb playfieldBounds;
-       Aabb maximumBounds;
+       Meh cool;
+       importScriptBindings(script, cool);
 
-       if ((it = rootObj.find("playfield_bounds")) != rootObj.end())
-       {
-               loadBox(playfieldBounds, (*it).second);
-       }
-       if ((it = rootObj.find("maximum_bounds")) != rootObj.end())
-       {
-               loadBox(maximumBounds, (*it).second);
-       }
-       else
-       {
-               logError("missing required maximum bounds");
-               return OctreeP();
-       }
+       long detail = 3;
+       Settings::getInstance().getNumber("game.detail", detail);
 
-       // create the tree to store the quads
-       OctreeP octree = Octree::alloc(maximumBounds);
+       script.push(detail);
+       script.set("detail");
 
-       if ((it = rootObj.find("instructions")) != rootObj.end())
+       logInfo("doing file...");
+       if (script.doFile(filePath) != 0)
        {
-               loadInstructions((*it).second, octree);
+               std::string str;
+               script[-1].get(str);
+               logError("lua error: %s", str.c_str());
        }
+       logInfo("done");
 
-       octree->sort();
-
-       return octree;
+       cool.octree->sort();
+       return cool.octree;
 }
 
 
This page took 0.03162 seconds and 4 git commands to generate.