--- /dev/null
+
+/*******************************************************************************
+
+ 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 <iostream>
+#include <map>
+#include <vector>
+
+#include "Aabb.hh"
+#include "Camera.hh"
+#include "Cullable.hh"
+#include "Deserializer.hh"
+#include "Drawable.hh"
+#include "Math.hh"
+#include "Mippleton.hh"
+#include "OpenGL.hh"
+#include "Scene.hh"
+#include "Serializable.hh"
+#include "Tilemap.hh"
+
+
+namespace Mf {
+
+
+class Scene::SceneImpl : public Mippleton<SceneImpl>
+{
+ class Scenery : public Drawable, public Cullable
+ {
+ public:
+ Scenery(const Matrix4& transform, const std::string& textureName) :
+ transformation(transform),
+ image(textureName) {}
+
+ protected:
+ Matrix4 transformation;
+ Tilemap image;
+ bool blending;
+ long detail;
+ bool fog;
+ };
+
+ class TilePanel : public Scenery
+ {
+ public:
+ TilePanel(const Matrix4& transform, const std::string& textureName,
+ SerializablePtr root) :
+ Scenery(transform, textureName),
+ width(1),
+ height(1)
+ {
+ std::map<std::string,SerializablePtr> rootObj;
+
+ if (root->get(rootObj))
+ {
+ std::map<std::string,SerializablePtr>::iterator it;
+
+ if ((it = rootObj.find("width")) != rootObj.end())
+ {
+ (*it).second->get(width);
+ }
+ if ((it = rootObj.find("tiles")) != rootObj.end())
+ {
+ std::vector<SerializablePtr> theTiles;
+
+ if ((*it).second->get(theTiles))
+ {
+ std::vector<SerializablePtr>::iterator jt;
+
+ height = theTiles.size() / width;
+ int w, h;
+
+ indices.resize(height);
+
+ for (h = height - 1, jt = theTiles.begin();
+ jt != theTiles.end(); h--)
+ {
+ std::vector<Tilemap::Index> row;
+
+ for (w = 0; w < width && jt != theTiles.end();
+ w++, jt++)
+ {
+ long index;
+
+ if ((*jt)->get(index))
+ {
+ row.push_back(Tilemap::Index(index));
+ }
+ }
+
+ indices[h] = row;
+ }
+ }
+ }
+ }
+ }
+
+ void draw(Scalar alpha)
+ {
+ glPushMatrix();
+ //std::cout << "transforming..." << std::endl;
+ //std::cout << transformation << std::endl;
+ glMultMatrixf(transformation.data());
+
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ image.bind();
+
+ long x, y;
+ Scalar xf, yf;
+
+ for (y = 0, yf = 0.0; y < height; y++, yf += 1.0)
+ {
+ for (x = 0, xf = 0.0; x < width; x++, xf += 1.0)
+ {
+ Scalar texCoords[8];
+
+ Tilemap::Index index = indices[y][x];
+
+ if (image.getTileCoords(index, texCoords))
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glTexCoord2f(texCoords[0], texCoords[1]);
+ glVertex3f(xf, yf, 0.0f);
+ glTexCoord2f(texCoords[2], texCoords[3]);
+ glVertex3f(xf+1.0, yf, 0.0f);
+ glTexCoord2f(texCoords[4], texCoords[5]);
+ glVertex3f(xf+1.0, yf+1.0, 0.0f);
+ glTexCoord2f(texCoords[6], texCoords[7]);
+ glVertex3f(xf, yf+1.0, 0.0f);
+ glEnd();
+ }
+ }
+ }
+
+ glPopMatrix();
+ }
+
+ bool isVisible(const Camera& cam)
+ {
+ return true;
+ }
+
+ private:
+ long width, height;
+ std::vector<std::vector<Tilemap::Index> > indices;
+ };
+
+ class Billboard : public Scenery
+ {
+ public:
+ Billboard(const Matrix4& transform, const std::string& textureName,
+ SerializablePtr root) :
+ Scenery(transform, textureName),
+ index(0)
+ {
+ std::map<std::string,SerializablePtr> rootObj;
+
+ if (root->get(rootObj))
+ {
+ std::map<std::string,SerializablePtr>::iterator it;
+
+ if ((it = rootObj.find("tile")) != rootObj.end())
+ {
+ long value;
+ if ((*it).second->get(value))
+ {
+ index = Tilemap::Index(value);
+ }
+ }
+ }
+
+ image.getTileCoords(index, texCoords);
+ }
+
+ void draw(Scalar alpha)
+ {
+ glPushMatrix();
+ glMultMatrixf(transformation.data());
+
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ image.bind();
+
+ glBegin(GL_TRIANGLE_FAN);
+ glTexCoord2f(texCoords[0], texCoords[1]);
+ glVertex2f(0.0f, 0.0f);
+ glTexCoord2f(texCoords[2], texCoords[3]);
+ glVertex2f(1.0f, 0.0f);
+ glTexCoord2f(texCoords[4], texCoords[5]);
+ glVertex2f(1.0f, 1.0f);
+ glTexCoord2f(texCoords[6], texCoords[7]);
+ glVertex2f(0.0f, 1.0f);
+ glEnd();
+
+ glPopMatrix();
+ }
+
+ bool isVisible(const Camera& cam)
+ {
+ return false;
+ }
+
+ private:
+ Tilemap::Index index;
+ Scalar texCoords[8];
+ };
+
+
+ static bool loadBox(Aabb& theBox, SerializablePtr obj)
+ {
+ std::vector<SerializablePtr> numbers;
+
+ if (obj->get(numbers))
+ {
+ if (numbers.size() == 6)
+ {
+ double num;
+
+ if (numbers[0]->getNumber(num))
+ {
+
+ }
+ }
+ }
+
+ return false;
+ }
+
+public:
+ SceneImpl(const std::string& name) :
+ Mippleton<SceneImpl>(name)
+ {
+ loadFromFile();
+ }
+
+
+ void loadInstructions(SerializablePtr root)
+ {
+ std::vector<SerializablePtr> rootObj;
+
+ if (root->get(rootObj))
+ {
+ std::vector<SerializablePtr>::iterator it;
+
+ Matrix4 transform;
+ std::string texture;
+
+ for (it = rootObj.begin(); it != rootObj.end(); it++)
+ {
+ std::string instruction;
+
+ if ((*it)->get(instruction))
+ {
+ if (instruction == "reset_transform")
+ {
+ transform.identity();
+ //std::cout << "===================RESET=====================" << std::endl;
+ }
+ else if (instruction == "translate")
+ {
+ std::vector<SerializablePtr> values;
+
+ it++;
+ if ((*it)->get(values))
+ {
+ Vector3 vec;
+
+ for (size_t i = 0; i < values.size(); i++)
+ {
+ double value;
+
+ if (values[i]->getNumber(value))
+ {
+ vec[i] = value;
+ }
+ }
+
+ Matrix4 translation;
+ cml::matrix_translation(translation, vec);
+ transform = translation * transform;
+ //std::cout << "TRANSLATE\t" << vec << std::endl
+ //<< transform << std::endl;
+ }
+ }
+ else if (instruction == "scale")
+ {
+ std::vector<SerializablePtr> values;
+
+ it++;
+ if ((*it)->get(values))
+ {
+ if (values.size() == 1)
+ {
+ double value = 1.0;
+
+ values[0]->getNumber(value);
+
+ Matrix4 scaling;
+ cml::matrix_uniform_scale(scaling, Scalar(value));
+ transform = scaling * transform;
+ //std::cout << "SCALE\t\t" << value << std::endl
+ //<< transform << std::endl;
+ }
+ else if (values.size() == 3)
+ {
+ Vector3 vec;
+
+ for (size_t i = 0; i < values.size(); i++)
+ {
+ double value;
+
+ if (values[i]->getNumber(value))
+ {
+ vec[i] = value;
+ }
+ }
+
+ Matrix4 scaling;
+ cml::matrix_scale(scaling, vec);
+ transform = scaling * transform;
+ //std::cout << "SCALE\t\t" << vec << std::endl
+ //<< transform << std::endl;
+ }
+ }
+ }
+ else if (instruction == "rotate")
+ {
+ std::vector<SerializablePtr> values;
+
+ it++;
+ if ((*it)->get(values))
+ {
+ if (values.size() == 2)
+ {
+ std::string axis;
+ size_t axisIndex = 0;
+ double value = 0.0;
+
+ if (values[0]->get(axis))
+ {
+ if (axis == "x")
+ {
+ axisIndex = 0;
+ }
+ else if (axis == "y")
+ {
+ axisIndex = 1;
+ }
+ else if (axis == "z")
+ {
+ axisIndex = 2;
+ }
+ values[1]->getNumber(value);
+ }
+
+ cml::matrix_rotate_about_local_axis(transform,
+ axisIndex, Scalar(value * cml::constantsd::rad_per_deg()));
+ //std::cout << "ROTATE\t" << axis << " " << value << std::endl
+ //<< transform << std::endl;
+ }
+ }
+ }
+ else if (instruction == "texture")
+ {
+ it++;
+ (*it)->get(texture);
+ }
+ else if (instruction == "tilemap")
+ {
+ //std::cout << "TILEMAP\t" << texture<< std::endl;
+ //std::cout << transform << std::endl;
+
+ it++;
+ TilePanel* tilePanel = new TilePanel(transform, texture,
+ *it);
+ boost::shared_ptr<Scenery> sceneItem(tilePanel);
+ objects.push_back(sceneItem);
+ }
+ else if (instruction == "billboard")
+ {
+ //std::cout << "BILLBOARD\t" << texture << std::endl;
+ //std::cout << transform << std::endl;
+
+ it++;
+ Billboard* billboard = new Billboard(transform, texture,
+ *it);
+ boost::shared_ptr<Scenery> sceneItem(billboard);
+ objects.push_back(sceneItem);
+ }
+ }
+ }
+ }
+ }
+
+
+ void loadFromFile()
+ {
+ std::string filePath = Scene::getPathToResource(getName());
+
+ Deserializer deserializer(filePath, true);
+
+ SerializablePtr root = deserializer.deserialize();
+
+ if (root)
+ {
+ std::map<std::string,SerializablePtr> rootObj;
+
+ if (root->get(rootObj))
+ {
+ std::map<std::string,SerializablePtr>::iterator it;
+
+ if ((it = rootObj.find("playfield_bounds")) != rootObj.end())
+ {
+ loadBox(playfieldBounds, (*it).second);
+ }
+ if ((it = rootObj.find("maximum_bounds")) != rootObj.end())
+ {
+ loadBox(maximumBounds, (*it).second);
+ }
+ if ((it = rootObj.find("instructions")) != rootObj.end())
+ {
+ loadInstructions((*it).second);
+ }
+ }
+ }
+ }
+
+
+ void draw(Scalar alpha)
+ {
+ SceneryVector::iterator it;
+
+ for (it = objects.begin(); it != objects.end(); it++)
+ {
+ //std::cout << "draw object";
+ (*it)->draw(alpha);
+ }
+ }
+
+
+ Aabb playfieldBounds;
+ Aabb maximumBounds;
+
+ typedef std::vector<boost::shared_ptr<Scenery> > SceneryVector;
+ SceneryVector objects;
+};
+
+
+Scene::Scene(const std::string& name) :
+ // pass through
+ impl_(Scene::SceneImpl::retain(name), &Scene::SceneImpl::release) {}
+
+
+void Scene::draw(Scalar alpha)
+{
+ // pass through
+ impl_->draw(alpha);
+}
+
+
+/**
+ * Specialized search location for scene files. They can be found in the
+ * "scenes" subdirectory of any of the searched directories.
+ */
+
+std::string Scene::getPathToResource(const std::string& name)
+{
+ return Resource::getPathToResource("scenes/" + name + ".json");
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+