/******************************************************************************* Copyright (c) 2009, Charles McGarvey All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include #include #include "Aabb.hh" #include "Camera.hh" #include "Entity.hh" #include "Log.hh" #include "Math.hh" #include "Scene.hh" #include "Script.hh" #include "Settings.hh" #include "Tilemap.hh" namespace Mf { static std::string getPath(const std::string& name) { return Resource::getPath("scenes/" + name + ".lua"); } struct Meh { Matrix4 transform; std::string texture; OctreeP octree; Meh() { octree = Octree::alloc(Aabb()); } static int loadBox(Script& script, Aabb& aabb) { 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; } int setPlayfieldBounds(Script& script) { Aabb bounds; return loadBox(script, bounds); } int setMaximumBounds(Script& script) { Aabb bounds; int ret = loadBox(script, bounds); octree = Octree::alloc(bounds); return ret; } int resetTransform(Script& script) { transform.identity(); return 0; } int translate(Script& script) { Script::Value x = script[1]; Script::Value y = script[2]; Script::Value z = script[3]; if (!x.isNumber() || !y.isNumber() || !z.isNumber()) { logWarning("wrong arguments to translate; ignoring..."); return 0; } Vector3 vec; x.get(vec[0]); y.get(vec[1]); z.get(vec[2]); Matrix4 translation; cml::matrix_translation(translation, vec); transform = translation * transform; return 0; } int scale(Script& script) { 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); Matrix4 scaling; cml::matrix_uniform_scale(scaling, Scalar(value)); transform = scaling * transform; } else { logWarning("wrong arguments to scale; ignoring..."); } return 0; } int rotate(Script& script) { Script::Value a = script[1]; Script::Value d = script[2]; if (!a.isString() || !d.isNumber()) { logWarning("wrong arguments to rotate; ignoring..."); return 0; } std::string axis; a.get(axis); 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; } int setTexture(Script& script) { Script::Value t = script[1]; if (t.isString()) t.get(texture); else logWarning("wrong arguments to setTexture; ignoring..."); return 0; } int makeTilemap(Script& script) { Script::Value table = script[1]; Script::Value top = script[-1]; if (!table.isTable()) { logWarning("wrong arguments to makeTilemap; ignoring..."); return 0; } long width = 1; long height = 1; table.pushField("width"); top.get(width); long nTiles = 0; table.pushField("tiles"); Script::Value tiles = script.getTop(); nTiles = tiles.getLength(); std::vector< std::vector > indices; if (nTiles % width == 0) { 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) { std::vector 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; } } else { logError("invalid tiles in tilemap instruction"); return 0; } Vector4 vertices[height+1][width+1]; Matrix4 transposedTransform = transform; transposedTransform.transpose(); for (int h = 0; h <= height; ++h) { 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; Vector3 quadVertices[4]; 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]); Quad* quad = new Quad(quadVertices, texture, indices[h][w]); boost::shared_ptr quadPtr(quad); octree->insert(quadPtr); } } return 0; } int makeBillboard(Script& script) { Script::Value table = script[1]; Script::Value top = script[-1]; long index = 0; long width = 1; bool blending = false; bool fog = false; if (table.isTable()) { table.pushField("tile"); if (top.isNumber()) top.get(index); table.pushField("u_scale"); if (top.isNumber()) top.get(width); table.pushField("blend"); if (top.isBoolean()) top.get(blending); table.pushField("fog"); if (top.isBoolean()) top.get(fog); } Vector4 vertices[2][width+1]; Matrix4 transposedTransform = transform; transposedTransform.transpose(); Scalar xf; Scalar increment = 1.0 / Scalar(width); 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; } } for (int w = 0; w < width; ++w) { 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]); Quad* quad = new Quad(quadVertices, texture, Tilemap::Index(index)); quad->setBlending(blending); quad->setFog(fog); boost::shared_ptr quadPtr(quad); octree->insert(quadPtr); } return 0; } }; static void importScriptBindings(Script& script, Meh& scene) { 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)); } OctreeP loadScene(const std::string& name) { std::string filePath = getPath(name); Meh cool; Script script; script.importStandardLibraries(); importLogScript(script); importScriptBindings(script, cool); long detail = 3; Settings::getInstance().get("detail", detail); script.push(detail); script.set("detail"); logInfo("doing file..."); if (script.doFile(filePath) != 0) { std::string str; script[-1].get(str); logError("lua error: %s", str.c_str()); } logInfo("done"); cool.octree->sort(); return cool.octree; } } // namespace Mf /** vim: set ts=4 sw=4 tw=80: *************************************************/