X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FScene.cc;h=ccfd4f934060b605ad5de663c9e62bf84414c9e0;hp=f4dd1c0e3f9597bdd7505ed236bd3d91591fc40c;hb=f72400af4fa3e7b54dab154b5a2b6503a6f9af18;hpb=c2321281bf12a7efaedde930422c7ddbc92080d4 diff --git a/src/Moof/Scene.cc b/src/Moof/Scene.cc index f4dd1c0..ccfd4f9 100644 --- a/src/Moof/Scene.cc +++ b/src/Moof/Scene.cc @@ -32,9 +32,8 @@ #include "Aabb.hh" #include "Camera.hh" -#include "Cullable.hh" #include "Deserializer.hh" -#include "Drawable.hh" +#include "Entity.hh" #include "Math.hh" #include "Mippleton.hh" #include "OpenGL.hh" @@ -46,448 +45,532 @@ namespace Mf { -class Scene::SceneImpl : public Mippleton +class Scene::Impl : public Mippleton { - class Scenery : public Drawable, public Cullable + class Quad : public Entity { 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) + Quad(const Vector3 vertices[4], const std::string& texture, + Tilemap::Index tileIndex) : + tilemap_(texture), + detail_(0), + blending_(false), + fog_(false) { - std::map rootObj; - - if (root->get(rootObj)) + for (int i = 0, num = 0; i < 4; ++i) { - std::map::iterator it; - - if ((it = rootObj.find("width")) != rootObj.end()) + for (int j = 0; j < 3; ++j, ++num) { - (*it).second->get(width); - } - if ((it = rootObj.find("tiles")) != rootObj.end()) - { - std::vector theTiles; - - if ((*it).second->get(theTiles)) - { - std::vector::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 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; - } - } + vertices_[num] = vertices[i][j]; } } - } - - 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) + if (!tilemap_.getTileCoords(tileIndex, texCoords_)) { - 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(); - } - } + std::cerr << "no coords for tile's texture" << std::endl; } - glPopMatrix(); + aabb_.encloseVertices(vertices, 4); + sphere_.point = aabb_.getCenter(); + sphere_.radius = (aabb_.min - sphere_.point).length(); } - bool isVisible(const Camera& cam) + void setDetail(long detail) { - return true; + detail_ = detail; } - private: - long width, height; - std::vector > indices; - }; + void setBlending(bool blending) + { + blending_ = blending; + } - class Billboard : public Scenery - { - public: - Billboard(const Matrix4& transform, const std::string& textureName, - SerializablePtr root) : - Scenery(transform, textureName), - index(0) + void setFog(bool fog) { - std::map rootObj; + fog_ = fog; + } - if (root->get(rootObj)) + void draw(Scalar alpha = 0.0) const + { + if (blending_) { - std::map::iterator it; + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - if ((it = rootObj.find("tile")) != rootObj.end()) - { - long value; - if ((*it).second->get(value)) - { - index = Tilemap::Index(value); - } - } + if (fog_) + { + glEnable(GL_FOG); + glFogi(GL_FOG_MODE, GL_LINEAR); } - image.getTileCoords(index, texCoords); - } + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + tilemap_.bind(); - void draw(Scalar alpha) - { - glPushMatrix(); - glMultMatrixf(transformation.data()); + glVertexPointer(3, GL_SCALAR, 0, vertices_); + glTexCoordPointer(2, GL_SCALAR, 0, texCoords_); - 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(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisable(GL_BLEND); + glDisable(GL_FOG); } - bool isVisible(const Camera& cam) + bool isVisible(const Camera& cam) const { - return false; + return sphere_.isVisible(cam); } private: - Tilemap::Index index; - Scalar texCoords[8]; + Scalar vertices_[12]; + Scalar texCoords_[8]; + + Tilemap tilemap_; + + long detail_; + bool blending_; + bool fog_; }; - static bool loadBox(Aabb& theBox, SerializablePtr obj) + static void loadBox(Aabb& theBox, SerializableP obj) { - std::vector numbers; + Serializable::Array numbers; - if (obj->get(numbers)) + if (obj->get(numbers) && numbers.size() == 6) { - if (numbers.size() == 6) - { - double num; - - if (numbers[0]->getNumber(num)) - { - - } - } + 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 false; } public: - SceneImpl(const std::string& name) : - Mippleton(name) + Impl(const std::string& name) : + Mippleton(name) { loadFromFile(); } - void loadInstructions(SerializablePtr root) + void loadInstructions(SerializableP root) { - std::vector rootObj; + Serializable::Array rootObj; + Serializable::Array::iterator it; - if (root->get(rootObj)) + if (!root->get(rootObj)) { - std::vector::iterator it; + std::cerr << "error loading scene instructions" << std::endl; + return; + } - Matrix4 transform; - std::string texture; + Matrix4 transform; + std::string texture; - for (it = rootObj.begin(); it != rootObj.end(); it++) - { - std::string instruction; + for (it = rootObj.begin(); it != rootObj.end(); ++it) + { + std::string instruction; - if ((*it)->get(instruction)) + if ((*it)->get(instruction)) + { + if (instruction == "reset_transform") { - if (instruction == "reset_transform") - { - transform.identity(); - //std::cout << "===================RESET=====================" << std::endl; - } - else if (instruction == "translate") + transform.identity(); + } + else if (instruction == "translate") + { + Serializable::Array values; + + ++it; + if ((*it)->get(values)) { - std::vector values; + Vector3 vec; - it++; - if ((*it)->get(values)) + for (size_t i = 0; i < values.size(); ++i) { - Vector3 vec; + Serializable::Float value; - for (size_t i = 0; i < values.size(); i++) + if (values[i]->getNumber(value)) { - double value; - - if (values[i]->getNumber(value)) - { - vec[i] = value; - } + vec[i] = value; } - - Matrix4 translation; - cml::matrix_translation(translation, vec); - transform = translation * transform; - //std::cout << "TRANSLATE\t" << vec << std::endl - //<< transform << std::endl; } + + Matrix4 translation; + cml::matrix_translation(translation, vec); + transform = translation * transform; } - else if (instruction == "scale") - { - std::vector values; + } + else if (instruction == "scale") + { + Serializable::Array values; - it++; - if ((*it)->get(values)) + ++it; + if ((*it)->get(values)) + { + if (values.size() == 1) { - if (values.size() == 1) - { - double value = 1.0; + Serializable::Float value = 1.0; - values[0]->getNumber(value); + 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) + 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) { - Vector3 vec; + Serializable::Float value; - for (size_t i = 0; i < values.size(); i++) + if (values[i]->getNumber(value)) { - double value; - - if (values[i]->getNumber(value)) - { - vec[i] = 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; } + + Matrix4 scaling; + cml::matrix_scale(scaling, vec); + transform = scaling * transform; } } - else if (instruction == "rotate") - { - std::vector values; + } + else if (instruction == "rotate") + { + Serializable::Array values; - it++; - if ((*it)->get(values)) + ++it; + if ((*it)->get(values)) + { + if (values.size() == 2) { - if (values.size() == 2) - { - std::string axis; - size_t axisIndex = 0; - double value = 0.0; + std::string axis; + size_t index = 0; + Serializable::Float 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); - } + if (values[0]->get(axis)) + { + if (axis == "x") index = 0; + else if (axis == "y") index = 1; + else if (axis == "z") index = 2; - 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; + 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") - { - //std::cout << "TILEMAP\t" << texture<< std::endl; - //std::cout << transform << std::endl; - - it++; - TilePanel* tilePanel = new TilePanel(transform, texture, - *it); - boost::shared_ptr 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 sceneItem(billboard); - objects.push_back(sceneItem); - } + } + else if (instruction == "texture") + { + ++it; + (*it)->get(texture); + } + else if (instruction == "tilemap") + { + ++it; + loadTilemap(*it, transform, texture); + } + else if (instruction == "billboard") + { + ++it; + loadBillboard(*it, transform, texture); } } } } - void loadFromFile() + void loadTilemap(SerializableP root, const Matrix4& transform, + const std::string& texture) { - std::string filePath = Scene::getPathToResource(getName()); + Serializable::Map rootObj; + Serializable::Map::iterator it; - Deserializer deserializer(filePath, true); + if (!root->get(rootObj)) + { + std::cerr << "error loading scene tilemap object" << std::endl; + return; + } - SerializablePtr root = deserializer.deserialize(); + long width = 1; + long height = 1; + std::vector< std::vector > indices; - if (root) + if ((it = rootObj.find("width")) != rootObj.end()) { - std::map rootObj; + (*it).second->get(width); + } + else + { + std::cerr << "width is a required field of a tilemap" << std::endl; + return; + } + + Serializable::Array tiles; - if (root->get(rootObj)) + if ((it = rootObj.find("tiles")) != rootObj.end() && + (*it).second->get(tiles) && + tiles.size() % width == 0) + { + Serializable::Array::iterator jt; + int w, h; + + height = tiles.size() / 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 + + for (h = height - 1, jt = tiles.begin(); jt != tiles.end(); --h) { - std::map::iterator it; + std::vector row; - if ((it = rootObj.find("playfield_bounds")) != rootObj.end()) + for (w = 0; w < width && jt != tiles.end(); ++w, ++jt) { - loadBox(playfieldBounds, (*it).second); - } - if ((it = rootObj.find("maximum_bounds")) != rootObj.end()) - { - loadBox(maximumBounds, (*it).second); + Serializable::Integer index; + + if ((*jt)->get(index)) + { + row.push_back(Tilemap::Index(index)); + } } - if ((it = rootObj.find("instructions")) != rootObj.end()) + + indices[h] = row; + } + } + else + { + std::cerr << "error loading tiles from tilemap object" << std::endl; + return; + } + + 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); + } + } + } + + void loadBillboard(SerializableP root, const Matrix4& transform, + const std::string& texture) + { + Serializable::Map rootObj; + Serializable::Map::iterator it; + + Tilemap::Index index = 0; + long width = 1; + bool blending = false; + bool fog = false; + + if (root->get(rootObj)) + { + if ((it = rootObj.find("tile")) != rootObj.end()) + { + Serializable::Integer value; + if ((*it).second->get(value)) { - loadInstructions((*it).second); + index = Tilemap::Index(value); } } + + if ((it = rootObj.find("u_scale")) != rootObj.end()) + { + (*it).second->get(width); + } + + if ((it = rootObj.find("blend")) != rootObj.end()) + { + (*it).second->get(blending); + } + + if ((it = rootObj.find("fog")) != rootObj.end()) + { + (*it).second->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, index); + quad->setBlending(blending); + quad->setFog(fog); + + boost::shared_ptr quadPtr(quad); + + octree->insert(quadPtr); } } - void draw(Scalar alpha) + void loadFromFile() { - SceneryVector::iterator it; + std::string filePath = Scene::getPath(getName()); + + Deserializer deserializer(filePath, true); + SerializableP root = deserializer.deserialize(); + + Serializable::Map rootObj; + Serializable::Map::iterator it; + + if (!root || !root->get(rootObj)) + { + std::cerr << "error loading scene file" << std::endl; + return; + } + + 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 + { + std::cerr << "maximum bounds required in scene" << std::endl; + return; + } - for (it = objects.begin(); it != objects.end(); it++) + // create the tree to store the quads + octree = Octree::alloc(maximumBounds); + + if ((it = rootObj.find("instructions")) != rootObj.end()) { - //std::cout << "draw object"; - (*it)->draw(alpha); + loadInstructions((*it).second); } + + octree->sort(); + } + + + void draw(Scalar alpha, const Camera& cam) const + { + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + octree->drawIfVisible(alpha, cam); + + //glDisableClientState(GL_VERTEX_ARRAY); + //glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + //Texture::resetBind(); + //glColor3f(0.0f, 1.0f, 0.0f); + //playfieldBounds.draw(); + //glColor3f(0.0f, 0.0f, 1.0f); + //maximumBounds.draw(); + + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } Aabb playfieldBounds; Aabb maximumBounds; - typedef std::vector > SceneryVector; - SceneryVector objects; + OctreeP octree; }; Scene::Scene(const std::string& name) : // pass through - impl_(Scene::SceneImpl::retain(name), &Scene::SceneImpl::release) {} + impl_(Scene::Impl::getInstance(name)) {} -void Scene::draw(Scalar alpha) +void Scene::draw(Scalar alpha, const Camera& cam) const { // pass through - impl_->draw(alpha); + impl_->draw(alpha, cam); } +void Scene::refresh() +{ + //impl_->objects.clear(); + impl_->loadFromFile(); +} + + +OctreeP Scene::getOctree() const +{ + // pass through + return impl_->octree; +} /** * 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) +std::string Scene::getPath(const std::string& name) { - return Resource::getPathToResource("scenes/" + name + ".json"); + return Resource::getPath("scenes/" + name + ".json"); }