#include #include #include #include #include #include #include #include #include #include #include #include extern GLuint sphere; extern GLuint meditex_blue; extern float objrot; extern LIGHT *lights; extern int nLights; static int SortTextures(const void *t1, const void *t2) { return strcmp(((TEXTURE*)t1)->name, ((TEXTURE*)t2)->name); } static int SortRooms(const void *r1, const void *r2) { return strcmp(((ROOM*)r1)->id, ((ROOM*)r2)->id); } static void LoadTriangles(xmlNodePtr node, LEVEL *level, WALL* walls, int nWalls) { int i = 0, j; xmlNodePtr node2; xmlChar *data; TEXTURE tex, *texp; VECTOR v; for(; node != NULL; node = node->next) { if(node->type != XML_ELEMENT_NODE || xmlStrcmp(node->name, (xmlChar*)"triangle")) continue; walls[i].visible = 1; data = xmlGetProp(node, (xmlChar*)"visible"); if(data) { if(!xmlStrcmp(data, (xmlChar*)"false")) walls[i].visible = 0; xmlFree(data); } data = xmlGetProp(node, (xmlChar*)"texture"); if(data) { tex.name = (char*)data; texp = bsearch(&tex, level->textures, level->nTextures, sizeof(TEXTURE), SortTextures); if(texp) walls[i].texture = texp->id; xmlFree(data); } j = -1; for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type != XML_ELEMENT_NODE) continue; if(!xmlStrcmp(node2->name, (xmlChar*)"vertex")) { if(++j > 2) break; data = xmlGetProp(node2, (xmlChar*)"x"); if(data) { walls[i].vertices[j].x = atof((char*)data); xmlFree(data); } data = xmlGetProp(node2, (xmlChar*)"y"); if(data) { walls[i].vertices[j].y = atof((char*)data); xmlFree(data); } data = xmlGetProp(node2, (xmlChar*)"z"); if(data) { walls[i].vertices[j].z = atof((char*)data); xmlFree(data); } } else if(!xmlStrcmp(node2->name, (xmlChar*)"normal")) { if(j < 0) continue; data = xmlGetProp(node2, (xmlChar*)"x"); if(data) { walls[i].normals[j].x = atof((char*)data); xmlFree(data); } data = xmlGetProp(node2, (xmlChar*)"y"); if(data) { walls[i].normals[j].y = atof((char*)data); xmlFree(data); } data = xmlGetProp(node2, (xmlChar*)"z"); if(data) { walls[i].normals[j].z = atof((char*)data); xmlFree(data); } } else if(!xmlStrcmp(node2->name, (xmlChar*)"texcoords")) { if(j < 0) continue; data = xmlGetProp(node2, (xmlChar*)"s"); if(data) { walls[i].texcoords[j].s = atof((char*)data); xmlFree(data); } data = xmlGetProp(node2, (xmlChar*)"t"); if(data) { walls[i].texcoords[j].t = atof((char*)data); xmlFree(data); } } } v = VectorCross( VectorSub(walls[i].vertices[1], walls[i].vertices[0]), VectorSub(walls[i].vertices[2], walls[i].vertices[0]) ); if(VectorLengthSq(v) > 0.0) { walls[i].normal = VectorNormalize(v); for(j = 0; j < 3; j++) { if(VectorLengthSq(walls[i].normals[j]) == 0.0) walls[i].normals[j] = walls[i].normal; } } i++; } } LEVEL *LoadLevel(char *filename) { LEVEL *level; xmlDocPtr doc; xmlDtdPtr dtd; xmlValidCtxtPtr validCtxt; xmlNodePtr root, node, node2, rooms = NULL, gates = NULL; xmlChar *data; char *name; int i; ROOM room, *roomp; name = malloc(strlen(filename)+8); strcpy(name, "levels/"); strcat(name, filename); doc = xmlParseFile(name); free(name); if(!doc) return NULL; dtd = xmlParseDTD((xmlChar*)"-//libzoom//DTD level 0.1//EN", (xmlChar*)"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, (xmlChar*)"level")) { xmlFreeDoc(doc); xmlCleanupParser(); return NULL; } level = calloc(1, sizeof(LEVEL)); for(node = root->children; node != NULL; node = node->next) { if(node->type != XML_ELEMENT_NODE) continue; if(!xmlStrcmp(node->name, (xmlChar*)"info")) { level->info = calloc(1, sizeof(LEVELINFO)); for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type != XML_ELEMENT_NODE) continue; if(!xmlStrcmp(node2->name, (xmlChar*)"name")) { if(level->info->name != NULL) continue; data = xmlNodeGetContent(node2); level->info->name = strdup((char*)data); xmlFree(data); } else if(!xmlStrcmp(node2->name, (xmlChar*)"desc")) { if(level->info->desc != NULL) continue; data = xmlNodeGetContent(node2); level->info->desc = strdup((char*)data); xmlFree(data); } else if(!xmlStrcmp(node2->name, (xmlChar*)"start")) { data = xmlGetProp(node2, (xmlChar*)"x"); if(data) level->info->start.x = atof((char*)data); xmlFree(data); data = xmlGetProp(node2, (xmlChar*)"y"); if(data) level->info->start.y = atof((char*)data); xmlFree(data); data = xmlGetProp(node2, (xmlChar*)"z"); if(data) level->info->start.z = atof((char*)data); xmlFree(data); } } } else if(!xmlStrcmp(node->name, (xmlChar*)"rooms")) { if(rooms != NULL) continue; rooms = node; for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, (xmlChar*)"room")) level->nRooms++; } } else if(!xmlStrcmp(node->name, (xmlChar*)"gates")) { if(gates != NULL) continue; gates = node; node2 = node->children; for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, (xmlChar*)"gate")) level->nGates++; } } else if(!xmlStrcmp(node->name, (xmlChar*)"textures")) { if(level->textures != NULL) continue; for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, (xmlChar*)"texture")) level->nTextures++; } level->textures = calloc(level->nTextures, sizeof(TEXTURE)); i = 0; for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type != XML_ELEMENT_NODE || xmlStrcmp(node2->name, (xmlChar*)"texture")) continue; data = xmlGetProp(node2, (xmlChar*)"name"); if(data) { level->textures[i].id = LoadTexture((char*)data); xmlFree(data); } data = xmlGetProp(node2, (xmlChar*)"id"); if(data) { level->textures[i].name = strdup((char*)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 != NULL; node = node->next) { if(node->type != XML_ELEMENT_NODE || xmlStrcmp(node->name, (xmlChar*)"room")) continue; data = xmlGetProp(node, (xmlChar*)"id"); if(data) { level->rooms[i].id = strdup((char*)data); xmlFree(data); } for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, (xmlChar*)"triangle")) level->rooms[i].nWalls++; } level->rooms[i].walls = calloc(level->rooms[i].nWalls, sizeof(WALL)); LoadTriangles(node->children, level, level->rooms[i].walls, level->rooms[i].nWalls); i++; } qsort(level->rooms, level->nRooms, sizeof(ROOM), SortRooms); level->gates = calloc(level->nGates, sizeof(GATE)); i = 0; for(node = gates->children; node != NULL; node = node->next) { if(node->type != XML_ELEMENT_NODE || xmlStrcmp(node->name, (xmlChar*)"gate")) continue; data = xmlGetProp(node, (xmlChar*)"room1"); if(data) { room.id = (char*)data; roomp = bsearch(&room, level->rooms, level->nRooms, sizeof(ROOM), SortRooms); if(roomp) level->gates[i].room1 = roomp; xmlFree(data); } data = xmlGetProp(node, (xmlChar*)"room2"); if(data) { room.id = (char*)data; roomp = bsearch(&room, level->rooms, level->nRooms, sizeof(ROOM), SortRooms); if(roomp) level->gates[i].room2 = roomp; xmlFree(data); } for(node2 = node->children; node2 != NULL; node2 = node2->next) { if(node2->type == XML_ELEMENT_NODE && !xmlStrcmp(node2->name, (xmlChar*)"triangle")) level->gates[i].nWalls++; } level->gates[i].walls = calloc(level->gates[i].nWalls, sizeof(WALL)); LoadTriangles(node->children, level, level->gates[i].walls, level->gates[i].nWalls); 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; for(i = 0; i < room.nWalls; i++) { p->polygons[i].vertices[0] = room.walls[i].vertices[0]; p->polygons[i].vertices[1] = room.walls[i].vertices[1]; 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 = room.walls[i].texture; p->polygons[i].texcoords[0] = room.walls[i].texcoords[0]; p->polygons[i].texcoords[1] = room.walls[i].texcoords[1]; p->polygons[i].texcoords[2] = room.walls[i].texcoords[2]; } return p; } /*void DrawRoom(LEVEL *level, int nr) { int i, j; int r, g; GLfloat std_emission[] = {0.0, 0.0, 0.0, 1.0}; GLfloat medipak100_emission[] = {1.0, 0.0, 0.0, 1.0}; ROOM room = level->rooms[nr]; WALL t1, t2; VERTEX p1, p2; VECTOR v1, v2, n, v; float s, t, d; MATRIX transform; for(i = 0; i < room.nWalls; i++) RenderWallDepth(room.walls[i]); for(i = 0; i < nLights; i++) { glClear(GL_COLOR_BUFFER_BIT); for(j = 0; j < room.nWalls; j++) RenderWallLight(room.walls[j], lights[i]); glAccum(GL_ACCUM, 1.0/(nLights+1)); } glAccum(GL_RETURN, 1.0); //for(i = 0; i < room.nWalls; i++) // RenderWall(room.walls[i], level->textures); glColor3f(1.0/(nLights+1), 1.0/(nLights+1), 1.0/(nLights+1)); for(i = 0; i < room.nThings; i++) { if(!room.things[i].visible) continue; switch(room.things[i].type) { case THING_MEDIPAK100: glPushMatrix(); glBindTexture(GL_TEXTURE_2D, meditex_blue); glMaterialfv(GL_FRONT, GL_EMISSION, medipak100_emission); glTranslatef(room.things[i].pos.x, room.things[i].pos.y, room.things[i].pos.z); glRotatef(objrot*10, 0.0, 1.0, 0.0); glScalef(0.3, 0.3, 0.3); glCallList(sphere); glMaterialfv(GL_FRONT, GL_EMISSION, std_emission); glPopMatrix(); } } for(i = 0; i < room.nGates; i++) { if(room.gateinfo[i].state == STATE_CLOSED) { glBindTexture(GL_TEXTURE_2D, level->textures[room.gates[i].walls[0].texture]); glBegin(GL_TRIANGLES); glNormal3fv((GLfloat*)&room.gates[i].walls[0].normal); glTexCoord2fv((GLfloat*)&room.gates[i].walls[0].texcoords[0]); glVertex3fv((GLfloat*)&room.gates[i].walls[0].vertices[0]); glTexCoord2fv((GLfloat*)&room.gates[i].walls[0].texcoords[1]); glVertex3fv((GLfloat*)&room.gates[i].walls[0].vertices[1]); glTexCoord2fv((GLfloat*)&room.gates[i].walls[0].texcoords[2]); glVertex3fv((GLfloat*)&room.gates[i].walls[0].vertices[2]); glEnd(); glBindTexture(GL_TEXTURE_2D, level->textures[room.gates[i].walls[0].texture]); glBegin(GL_TRIANGLES); glNormal3fv((GLfloat*)&room.gates[i].walls[1].normal); glTexCoord2fv((GLfloat*)&room.gates[i].walls[1].texcoords[0]); glVertex3fv((GLfloat*)&room.gates[i].walls[1].vertices[0]); glTexCoord2fv((GLfloat*)&room.gates[i].walls[1].texcoords[1]); glVertex3fv((GLfloat*)&room.gates[i].walls[1].vertices[1]); glTexCoord2fv((GLfloat*)&room.gates[i].walls[1].texcoords[2]); glVertex3fv((GLfloat*)&room.gates[i].walls[1].vertices[2]); glEnd(); } else if(room.gateinfo[i].state == STATE_OPENING) { t1 = room.gates[i].walls[0]; t2 = room.gates[i].walls[1]; t1.vertices[2] = VectorAdd(VectorMul(t1.vertices[2], room.gateinfo[i].timer/1000.0), VectorMul(t1.vertices[1], 1 - (room.gateinfo[i].timer/1000.0))); t2.vertices[1] = t1.vertices[2]; t2.vertices[2] = VectorAdd(VectorMul(t2.vertices[2], room.gateinfo[i].timer/1000.0), VectorMul(t2.vertices[0], 1 - (room.gateinfo[i].timer/1000.0))); t1.texcoords[0].s = t1.texcoords[0].s * room.gateinfo[i].timer/1000.0 + t2.texcoords[2].s * (1 - room.gateinfo[i].timer/1000.0); t1.texcoords[0].t = t1.texcoords[0].t * room.gateinfo[i].timer/1000.0 + t2.texcoords[2].t * (1 - room.gateinfo[i].timer/1000.0); t1.texcoords[1].s = t1.texcoords[1].s * room.gateinfo[i].timer/1000.0 + t1.texcoords[2].s * (1 - room.gateinfo[i].timer/1000.0); t1.texcoords[1].t = t1.texcoords[1].t * room.gateinfo[i].timer/1000.0 + t1.texcoords[2].t * (1 - room.gateinfo[i].timer/1000.0); t2.texcoords[0] = t1.texcoords[0]; glBindTexture(GL_TEXTURE_2D, level->textures[t1.texture]); glBegin(GL_TRIANGLES); glNormal3fv((GLfloat*)&t1.normal); glTexCoord2fv((GLfloat*)&t1.texcoords[0]); glVertex3fv((GLfloat*)&t1.vertices[0]); glTexCoord2fv((GLfloat*)&t1.texcoords[1]); glVertex3fv((GLfloat*)&t1.vertices[1]); glTexCoord2fv((GLfloat*)&t1.texcoords[2]); glVertex3fv((GLfloat*)&t1.vertices[2]); glEnd(); glBindTexture(GL_TEXTURE_2D, level->textures[t2.texture]); glBegin(GL_TRIANGLES); glNormal3fv((GLfloat*)&t2.normal); glTexCoord2fv((GLfloat*)&t2.texcoords[0]); glVertex3fv((GLfloat*)&t2.vertices[0]); glTexCoord2fv((GLfloat*)&t2.texcoords[1]); glVertex3fv((GLfloat*)&t2.vertices[1]); glTexCoord2fv((GLfloat*)&t2.texcoords[2]); glVertex3fv((GLfloat*)&t2.vertices[2]); glEnd(); r = room.gates[i].room; g = room.gates[i].gate; t1 = room.gates[i].walls[0]; t2 = room.gates[i].walls[1]; p1 = room.gates[i].point; v1 = t1.normal; t1 = level->rooms[r].gates[g].walls[0]; t2 = level->rooms[r].gates[g].walls[1]; p2 = level->rooms[r].gates[g].point; v2 = VectorNeg(t1.normal); glPushMatrix(); transform = VectorMatrix(p1, v1, p2, v2); glMultMatrixf(transform.f); //DrawRoom(level, r); glPopMatrix(); } else if(room.gateinfo[i].state == STATE_CLOSING) { t1 = room.gates[i].walls[0]; t2 = room.gates[i].walls[1]; t1.vertices[2] = VectorAdd(VectorMul(t1.vertices[2], 1 - (room.gateinfo[i].timer/1000.0)), VectorMul(t1.vertices[1], room.gateinfo[i].timer/1000.0)); t2.vertices[1] = t1.vertices[2]; t2.vertices[2] = VectorAdd(VectorMul(t2.vertices[2], 1 - (room.gateinfo[i].timer/1000.0)), VectorMul(t2.vertices[0], room.gateinfo[i].timer/1000.0)); t1.texcoords[0].s = t1.texcoords[0].s * (1 - room.gateinfo[i].timer/1000.0) + t2.texcoords[2].s * room.gateinfo[i].timer/1000.0; t1.texcoords[0].t = t1.texcoords[0].t * (1 - room.gateinfo[i].timer/1000.0) + t2.texcoords[2].t * room.gateinfo[i].timer/1000.0; t1.texcoords[1].s = t1.texcoords[1].s * (1 - room.gateinfo[i].timer/1000.0) + t1.texcoords[2].s * room.gateinfo[i].timer/1000.0; t1.texcoords[1].t = t1.texcoords[1].t * (1 - room.gateinfo[i].timer/1000.0) + t1.texcoords[2].t * room.gateinfo[i].timer/1000.0; t2.texcoords[0] = t1.texcoords[0]; glBindTexture(GL_TEXTURE_2D, level->textures[t1.texture]); glBegin(GL_TRIANGLES); glNormal3fv((GLfloat*)&t1.normal); glTexCoord2fv((GLfloat*)&t1.texcoords[0]); glVertex3fv((GLfloat*)&t1.vertices[0]); glTexCoord2fv((GLfloat*)&t1.texcoords[1]); glVertex3fv((GLfloat*)&t1.vertices[1]); glTexCoord2fv((GLfloat*)&t1.texcoords[2]); glVertex3fv((GLfloat*)&t1.vertices[2]); glEnd(); glBindTexture(GL_TEXTURE_2D, level->textures[t2.texture]); glBegin(GL_TRIANGLES); glNormal3fv((GLfloat*)&t2.normal); glTexCoord2fv((GLfloat*)&t2.texcoords[0]); glVertex3fv((GLfloat*)&t2.vertices[0]); glTexCoord2fv((GLfloat*)&t2.texcoords[1]); glVertex3fv((GLfloat*)&t2.vertices[1]); glTexCoord2fv((GLfloat*)&t2.texcoords[2]); glVertex3fv((GLfloat*)&t2.vertices[2]); glEnd(); r = room.gates[i].room; g = room.gates[i].gate; t1 = room.gates[i].walls[0]; t2 = room.gates[i].walls[1]; p1 = room.gates[i].point; v1 = t1.normal; t1 = level->rooms[r].gates[g].walls[0]; t2 = level->rooms[r].gates[g].walls[1]; p2 = level->rooms[r].gates[g].point; v2 = VectorNeg(t1.normal); glPushMatrix(); transform = VectorMatrix(p1, v1, p2, v2); glMultMatrixf(transform.f); //DrawRoom(level, r); glPopMatrix(); } else { r = room.gates[i].room; g = room.gates[i].gate; t1 = room.gates[i].walls[0]; t2 = room.gates[i].walls[1]; p1 = room.gates[i].point; v1 = t1.normal; t1 = level->rooms[r].gates[g].walls[0]; t2 = level->rooms[r].gates[g].walls[1]; p2 = level->rooms[r].gates[g].point; v2 = VectorNeg(t1.normal); glPushMatrix(); transform = VectorMatrix(p1, v1, p2, v2); glMultMatrixf(transform.f); //DrawRoom(level, r); glPopMatrix(); } } }*/ void FreeLevel(LEVEL *level) { int i; if(level) { if(level->info) { if(level->info->name) free(level->info->name); if(level->info->desc) free(level->info->desc); free(level->info); } if(level->rooms) { for(i = 0; i < level->nRooms; i++) { if(level->rooms[i].walls) 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); }*/ if(level->rooms[i].id) free(level->rooms[i].id); } free(level->rooms); } if(level->gates) { for(i = 0; i < level->nGates; i++) { if(level->gates[i].walls) free(level->gates[i].walls); } free(level->gates); } if(level->textures) { for(i = 0; i < level->nTextures; i++) { if(level->textures[i].name) free(level->textures[i].name); } free(level->textures); } free(level); } }