261 lines
6.7 KiB
C++
261 lines
6.7 KiB
C++
![]() |
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
}
|