summaryrefslogtreecommitdiffstats
path: root/level.c
diff options
context:
space:
mode:
authorneoraider <devnull@localhost>2007-05-14 19:38:01 +0200
committerneoraider <devnull@localhost>2007-05-14 19:38:01 +0200
commita5aa4b54e23d0793793384a6794cc543ea48ad34 (patch)
tree480f4686b8879347119803ac0973266216a5e6bc /level.c
parent4069752dbc64302b2fb64703644622cb2ec09eef (diff)
downloadlibzoom-a5aa4b54e23d0793793384a6794cc543ea48ad34.tar
libzoom-a5aa4b54e23d0793793384a6794cc543ea48ad34.zip
libzoom: XML level loader implemented.
zoom: Converted old test level to XML.
Diffstat (limited to 'level.c')
-rw-r--r--level.c370
1 files changed, 304 insertions, 66 deletions
diff --git a/level.c b/level.c
index e7b8343..0d22f64 100644
--- a/level.c
+++ b/level.c
@@ -7,6 +7,9 @@
#include <zoom/texture.h>
#include <zoom/level.h>
#include <zoom/light.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
extern GLuint sphere;
@@ -15,66 +18,281 @@ extern float objrot;
extern LIGHT *lights;
extern int nLights;
-int LoadLevel(char *filename, LEVEL *level) {
- FILE *file;
- LEVELHEADER levelheader;
- ROOMHEADER roomheader;
- int i, j;
- unsigned char c;
- unsigned char buffer[260];
-
- strcpy(buffer, "levels/");
- strcat(buffer, filename);
- file = fopen(buffer, "rb");
- if(!file) return 0;
-
- fread(&levelheader, sizeof(LEVELHEADER), 1, file);
- if(levelheader.l != 'L' || levelheader.f != 'F') {
- fclose(file);
- return 0;
- }
-
- level->nRooms = levelheader.nRooms;
- level->rooms = malloc(levelheader.nRooms * sizeof(ROOM));
-
- for(i = 0; i < levelheader.nRooms; i++) {
- fread(&roomheader, sizeof(ROOMHEADER), 1, file);
-
- level->rooms[i].nWalls = roomheader.nWalls;
- level->rooms[i].walls = malloc(roomheader.nWalls * sizeof(WALL));
- fread(level->rooms[i].walls, sizeof(WALL), roomheader.nWalls, file);
-
- level->rooms[i].nThings = roomheader.nThings;
- level->rooms[i].things = malloc(roomheader.nThings * sizeof(THING));
- fread(level->rooms[i].things, sizeof(THING), roomheader.nThings, file);
-
- level->rooms[i].nGates = roomheader.nGates;
- level->rooms[i].gates = malloc(roomheader.nGates * sizeof(GATE));
- fread(level->rooms[i].gates, sizeof(GATE), roomheader.nGates, file);
-
- level->rooms[i].gateinfo = malloc(roomheader.nGates * sizeof(GATEINFO));
- for(j = 0; j < level->rooms[i].nGates; j++) level->rooms[i].gateinfo[j].state = STATE_CLOSED;
- }
-
- level->nTextures = levelheader.nTextures;
- level->textures = malloc(levelheader.nTextures * sizeof(GLuint));
-
- for(i = 0; i < levelheader.nTextures; i++) {
- fread(&c, 1, 1, file);
- fread(buffer, c, 1, file);
- buffer[c] = 0;
- level->textures[i] = LoadTexture(buffer);
- }
-
- fclose(file);
- return 1;
+
+static int SortTextures(const void *t1, const void *t2) {
+ return strcmp(((TEXTURE*)t1)->name, ((TEXTURE*)t2)->name);
+}
+
+
+LEVEL *LoadLevel(char *filename) {
+ LEVEL *level;
+ xmlDocPtr doc;
+ xmlDtdPtr dtd;
+ xmlValidCtxtPtr validCtxt;
+ xmlNodePtr root, node, node2, node3, rooms = NULL;
+ xmlChar *data;
+ char *name;
+ int i, j, k;
+ VECTOR v;
+ TEXTURE tex;
+ TEXTURE *texp;
+
+
+ name = malloc(strlen(filename)+8);
+ strcpy(name, "levels/");
+ strcat(name, filename);
+
+ doc = xmlParseFile(name);
+
+ free(name);
+
+ if(!doc)
+ return NULL;
+
+ dtd = xmlParseDTD("-//libzoom//DTD level 0.1//EN", "levels/level.dtd");
+
+ if(!dtd) {
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+ return NULL;
+ }
+
+ validCtxt = xmlNewValidCtxt();
+
+ if(!validCtxt) {
+ xmlFreeDtd(dtd);
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+ return NULL;
+ }
+
+ if(!xmlValidateDtd(validCtxt, doc, dtd)) {
+ xmlFreeValidCtxt(validCtxt);
+ xmlFreeDtd(dtd);
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+ return NULL;
+ }
+
+ xmlFreeValidCtxt(validCtxt);
+ xmlFreeDtd(dtd);
+
+ root = xmlDocGetRootElement(doc);
+ if(!root || xmlStrcmp(root->name, "level")) {
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+ return NULL;
+ }
+
+ level = calloc(1, sizeof(LEVEL));
+
+ for(node = root->children; node = node->next; node != NULL) {
+ if(node->type != XML_ELEMENT_NODE) continue;
+
+ if(!xmlStrcmp(node->name, "info")) {
+ level->info = calloc(1, sizeof(LEVELINFO));
+
+ for(node2 = node->children; node2 = node2->next; node2 != NULL) {
+ if(node2->type != XML_ELEMENT_NODE) continue;
+
+ if(!xmlStrcmp(node2->name, "name")) {
+ if(level->info->name != NULL) continue;
+
+ data = xmlNodeGetContent(node2);
+ level->info->name = strdup(data);
+ xmlFree(data);
+ }
+ else if(!xmlStrcmp(node2->name, "desc")) {
+ if(level->info->desc != NULL) continue;
+
+ data = xmlNodeGetContent(node2);
+ level->info->desc = strdup(data);
+ xmlFree(data);
+ }
+ else if(!xmlStrcmp(node2->name, "start")) {
+ data = xmlGetProp(node2, "x");
+ if(data) level->info->start.x = atof(data);
+ xmlFree(data);
+
+ data = xmlGetProp(node2, "y");
+ if(data) level->info->start.y = atof(data);
+ xmlFree(data);
+
+ data = xmlGetProp(node2, "z");
+ if(data) level->info->start.z = atof(data);
+ xmlFree(data);
+ }
+ }
+ }
+ else if(!xmlStrcmp(node->name, "rooms")) {
+ if(rooms != NULL) continue;
+
+ rooms = node;
+
+ for(node2 = node->children; node2 = node2->next; node2 != NULL) {
+ if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, "room")) level->nRooms++;
+ }
+ }
+ else if(!xmlStrcmp(node->name, "textures")) {
+ if(level->textures != NULL) continue;
+
+ for(node2 = node->children; node2 = node2->next; node2 != NULL) {
+ if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, "texture")) level->nTextures++;
+ }
+
+ level->textures = calloc(level->nTextures, sizeof(TEXTURE));
+
+ i = 0;
+ for(node2 = node->children; node2 = node2->next; node2 != NULL) {
+ if(node2->type != XML_ELEMENT_NODE || xmlStrcmp(node2->name, "texture")) continue;
+
+ data = xmlGetProp(node2, "name");
+ if(data) {
+ level->textures[i].id = LoadTexture(data);
+
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node2, "id");
+ if(data) {
+ level->textures[i].name = strdup(data);
+
+ xmlFree(data);
+ }
+
+ i++;
+ }
+
+ qsort(level->textures, level->nTextures, sizeof(TEXTURE), SortTextures);
+ }
+ }
+
+ level->rooms = calloc(level->nRooms, sizeof(ROOM));
+
+ i = 0;
+ for(node = rooms->children; node = node->next; node != NULL) {
+ if(node->type != XML_ELEMENT_NODE || xmlStrcmp(node->name, "room")) continue;
+
+ for(node2 = node->children; node2 = node2->next; node2 != NULL) {
+ if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, "triangle")) level->rooms[i].nWalls++;
+ }
+
+ level->rooms[i].walls = calloc(level->rooms[i].nWalls, sizeof(WALL));
+
+ j = 0;
+ for(node2 = node->children; node2 = node2->next; node2 != NULL) {
+ if(node2->type != XML_ELEMENT_NODE || xmlStrcmp(node2->name, "triangle")) continue;
+
+ data = xmlGetProp(node2, "type");
+ if(data) {
+ if(!xmlStrcmp(data, "wall")) level->rooms[i].walls[j].type = TRIANGLE_WALL;
+ else if(!xmlStrcmp(data, "floor")) level->rooms[i].walls[j].type = TRIANGLE_FLOOR;
+ else level->rooms[i].walls[j].type = TRIANGLE_UNKNOWN;
+ xmlFree(data);
+ }
+
+ level->rooms[i].walls[j].visible = 1;
+ data = xmlGetProp(node2, "visible");
+ if(data) {
+ if(!xmlStrcmp(data, "false")) level->rooms[i].walls[j].visible = 0;
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node2, "texture");
+ if(data) {
+ tex.name = data;
+ texp = bsearch(&tex, level->textures, level->nTextures, sizeof(TEXTURE), SortTextures);
+
+ if(texp) level->rooms[i].walls[j].texture = texp->id;
+
+ xmlFree(data);
+ }
+
+ k = -1;
+ for(node3 = node2->children; node3 = node3->next; node3 != NULL) {
+ if(node3->type != XML_ELEMENT_NODE) continue;
+
+ if(!xmlStrcmp(node3->name, "vertex")) {
+ if(++k > 2) break;
+
+ data = xmlGetProp(node3, "x");
+ if(data) {
+ level->rooms[i].walls[j].vertices[k].x = atof(data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node3, "y");
+ if(data) {
+ level->rooms[i].walls[j].vertices[k].y = atof(data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node3, "z");
+ if(data) {
+ level->rooms[i].walls[j].vertices[k].z = atof(data);
+ xmlFree(data);
+ }
+ }
+ else if(!xmlStrcmp(node3->name, "normal")) {
+ if(k < 0) continue;
+
+ data = xmlGetProp(node3, "x");
+ if(data) {
+ level->rooms[i].walls[j].normals[k].x = atof(data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node3, "y");
+ if(data) {
+ level->rooms[i].walls[j].normals[k].y = atof(data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node3, "z");
+ if(data) {
+ level->rooms[i].walls[j].normals[k].z = atof(data);
+ xmlFree(data);
+ }
+ }
+ else if(!xmlStrcmp(node3->name, "texcoords")) {
+ if(k < 0) continue;
+
+ data = xmlGetProp(node3, "s");
+ if(data) {
+ level->rooms[i].walls[j].texcoords[k].s = atof(data);
+ xmlFree(data);
+ }
+
+ data = xmlGetProp(node3, "t");
+ if(data) {
+ level->rooms[i].walls[j].texcoords[k].t = atof(data);
+ xmlFree(data);
+ }
+ }
+ }
+ v = VectorCross(
+ VectorSub(level->rooms[i].walls[j].vertices[1], level->rooms[i].walls[j].vertices[0]),
+ VectorSub(level->rooms[i].walls[j].vertices[2], level->rooms[i].walls[j].vertices[0])
+ );
+ if(VectorLengthSq(v)) level->rooms[i].walls[j].normal = VectorNormalize(v);
+
+ j++;
+ }
+
+ i++;
+ }
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+
+ return level;
}
POLYGON_LIST *DrawRoom(LEVEL *level, int nr) {
ROOM room = level->rooms[nr];
POLYGON_LIST *p;
int i;
-
+
p = malloc(sizeof(POLYGON_LIST)+sizeof(POLYGON)*room.nWalls);
p->nPolygons = room.nWalls;
@@ -84,8 +302,11 @@ POLYGON_LIST *DrawRoom(LEVEL *level, int nr) {
p->polygons[i].vertices[2] = room.walls[i].vertices[2];
p->polygons[i].normal = room.walls[i].normal;
+ p->polygons[i].normals[0] = room.walls[i].normals[0];
+ p->polygons[i].normals[1] = room.walls[i].normals[1];
+ p->polygons[i].normals[2] = room.walls[i].normals[2];
- p->polygons[i].texture = level->textures[room.walls[i].texture];
+ p->polygons[i].texture = room.walls[i].texture;
p->polygons[i].texcoords[0] = room.walls[i].texcoords[0];
p->polygons[i].texcoords[1] = room.walls[i].texcoords[1];
@@ -334,15 +555,32 @@ POLYGON_LIST *DrawRoom(LEVEL *level, int nr) {
void FreeLevel(LEVEL *level) {
int i;
- if(level->nRooms) {
- for(i = 0; i < level->nRooms; i++) {
- if(level->rooms[i].nWalls) free(level->rooms[i].walls);
- if(level->rooms[i].nThings) free(level->rooms[i].things);
- if(level->rooms[i].nGates) {
- free(level->rooms[i].gates);
- free(level->rooms[i].gateinfo);
- }
- }
- free(level->rooms);
- }
+ if(level) {
+ if(level->info) {
+ free(level->info->name);
+ free(level->info->desc);
+ free(level->info);
+ }
+
+ if(level->nRooms) {
+ for(i = 0; i < level->nRooms; i++) {
+ if(level->rooms[i].nWalls) free(level->rooms[i].walls);
+ if(level->rooms[i].nThings) free(level->rooms[i].things);
+ if(level->rooms[i].nGates) {
+ free(level->rooms[i].gates);
+ free(level->rooms[i].gateinfo);
+ }
+ }
+ free(level->rooms);
+ }
+
+ if(level->nTextures) {
+ for(i = 0; i < level->nTextures; i++)
+ free(level->textures[i].name);
+
+ free(level->textures);
+ }
+
+ free(level);
+ }
}