summaryrefslogtreecommitdiffstats
path: root/Level.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Level.cpp')
-rw-r--r--Level.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/Level.cpp b/Level.cpp
new file mode 100644
index 0000000..2867ab9
--- /dev/null
+++ b/Level.cpp
@@ -0,0 +1,260 @@
+/*
+ * Level.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Level.h"
+#include "Texture.h"
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+
+#include <iostream>
+
+namespace Zoom {
+
+boost::shared_ptr<Level> Level::loadLevel(const std::string &filename) {
+ boost::shared_ptr<Level> level;
+
+ xmlDocPtr doc = xmlParseFile(("levels/"+filename).c_str());
+
+ if(doc) {
+ if(validateLevel(doc)) {
+ xmlNodePtr root = xmlDocGetRootElement(doc);
+ if(root && !xmlStrcmp(root->name, (xmlChar*)"level")) {
+ level = boost::shared_ptr<Level>(new Level);
+
+ for(xmlNodePtr node = root->children; node != 0; node = node->next) {
+ if(node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if(!xmlStrcmp(node->name, (xmlChar*)"info")) {
+ level->loadLevelInfo(node);
+ }
+ else if(!xmlStrcmp(node->name, (xmlChar*)"rooms")) {
+ level->loadRooms(node);
+ }
+ else if(!xmlStrcmp(node->name, (xmlChar*)"textures")) {
+ level->loadTextures(node);
+ }
+ }
+
+ for(std::list<Room>::iterator room = level->rooms.begin(); room != level->rooms.end(); ++room) {
+ for(std::list<BSPTree::TriangleRecord>::iterator wall = room->walls.begin(); wall != room->walls.end(); ++wall) {
+ boost::shared_ptr<WallData> wallData = boost::dynamic_pointer_cast<WallData>(wall->data);
+
+ if(!wallData->texture.empty()) {
+ std::map<std::string, unsigned>::iterator texture = level->textures.find(wallData->texture);
+
+ if(texture != level->textures.end())
+ wall->triangle.setTexture(texture->second);
+ }
+ }
+ }
+ }
+ }
+
+ xmlFreeDoc(doc);
+ }
+
+ xmlCleanupParser();
+
+ return level;
+}
+
+void Level::loadLevelInfo(xmlNodePtr infoNode) {
+ for(xmlNodePtr node = infoNode->children; node != 0; node = node->next) {
+ if(node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if(!xmlStrcmp(node->name, (xmlChar*)"name")) {
+ xmlChar *data = xmlNodeGetContent(node);
+ name = (char*)data;
+ xmlFree(data);
+ }
+ else if(!xmlStrcmp(node->name, (xmlChar*)"desc")) {
+ xmlChar *data = xmlNodeGetContent(node);
+ description = (char*)data;
+ xmlFree(data);
+ }
+ else if(!xmlStrcmp(node->name, (xmlChar*)"start")) {
+ startPoint = loadVector(node);
+ }
+ }
+}
+
+void Level::loadRooms(xmlNodePtr roomsNode) {
+ for(xmlNodePtr node = roomsNode->children; node != 0; node = node->next) {
+ if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"room")) {
+ loadRoom(node);
+ }
+ }
+}
+
+void Level::loadRoom(xmlNodePtr roomNode) {
+ rooms.push_back(Room());
+
+ xmlChar *data = xmlGetProp(roomNode, (xmlChar*)"id");
+ if(data) {
+ rooms.back().id = (char*)data;
+
+ xmlFree(data);
+ }
+
+ for(xmlNodePtr node = roomNode->children; node != 0; node = node->next) {
+ if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"triangle")) {
+ rooms.back().walls.push_back(loadWall(node));
+ }
+ }
+}
+
+void Level::loadTextures(xmlNodePtr texturesNode) {
+ for(xmlNodePtr node = texturesNode->children; node != 0; node = node->next) {
+ if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"texture")) {
+ std::string id, name;
+
+ xmlChar *data = xmlGetProp(node, (xmlChar*)"id");
+ if(data) {
+ id = (char*)data;
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node, (xmlChar*)"name");
+ if(data) {
+ name = (char*)data;
+ xmlFree(data);
+ }
+
+ if(!id.empty() && !name.empty()) {
+ unsigned texture = Texture::loadTexture(name);
+
+ if(texture) {
+ textures.insert(std::make_pair(id, texture));
+ }
+ }
+ }
+ }
+}
+
+BSPTree::TriangleRecord Level::loadWall(xmlNodePtr wallNode) {
+ boost::shared_ptr<WallData> wallData(new WallData);
+
+ BSPTree::TriangleRecord wall;
+ wall.data = wallData;
+
+
+ xmlChar *data = xmlGetProp(wallNode, (xmlChar*)"texture");
+ if(data) {
+ wallData->texture = (char*)data;
+ xmlFree(data);
+ }
+
+ int vertexNum = -1;
+
+ for(xmlNodePtr node = wallNode->children; node != 0; node = node->next) {
+ if(node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if(!xmlStrcmp(node->name, (xmlChar*)"vertex")) {
+ if(++vertexNum > 2)
+ break;
+
+ wall.triangle.setVertex(vertexNum, loadVector(node));
+ }
+ else if(!xmlStrcmp(node->name, (xmlChar*)"normal")) {
+ if(vertexNum < 0)
+ continue;
+
+ wall.triangle.setNormal(vertexNum, loadVector(node));
+ }
+ else if(!xmlStrcmp(node->name, (xmlChar*)"texcoords")) {
+ if(vertexNum < 0) continue;
+
+ data = xmlGetProp(node, (xmlChar*)"s");
+ if(data) {
+ wall.triangle.getTexCoords(vertexNum)[0] = atof((char*)data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node, (xmlChar*)"t");
+ if(data) {
+ wall.triangle.getTexCoords(vertexNum)[1] = atof((char*)data);
+ xmlFree(data);
+ }
+ }
+ }
+
+ vmml::vec3f normal = wall.triangle.computeNormal();
+
+ if(normal.squared_length() > 0) {
+ normal.normalize();
+
+ for(int i = 0; i < 3; ++i) {
+ if(wall.triangle.getNormal(i).squared_length() == 0)
+ wall.triangle.setNormal(i, normal);
+ }
+ }
+
+
+ return wall;
+}
+
+vmml::vec3f Level::loadVector(xmlNodePtr node) {
+ vmml::vec3f ret(vmml::vec3f::ZERO);
+
+ xmlChar *data = xmlGetProp(node, (xmlChar*)"x");
+ if(data) {
+ ret.x() = atof((char*)data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node, (xmlChar*)"y");
+ if(data) {
+ ret.y() = atof((char*)data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node, (xmlChar*)"z");
+ if(data) {
+ ret.z() = atof((char*)data);
+ xmlFree(data);
+ }
+
+ return ret;
+}
+
+bool Level::validateLevel(xmlDocPtr doc) {
+ bool ret = false;
+
+ xmlDtdPtr dtd = xmlParseDTD((xmlChar*)"-//libzoom//DTD level 0.1//EN", (xmlChar*)"levels/level.dtd");
+
+ if(dtd) {
+ xmlValidCtxtPtr validCtxt = xmlNewValidCtxt();
+
+ if(validCtxt) {
+ if(xmlValidateDtd(validCtxt, doc, dtd))
+ ret = true;
+
+ xmlFreeValidCtxt(validCtxt);
+ }
+
+ xmlFreeDtd(dtd);
+ }
+
+ return ret;
+}
+
+}