Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2008-05-04 22:30:49 +0000
committerStijn Buys <ingar@osirion.org>2008-05-04 22:30:49 +0000
commit7218e3bd4616d4706090ec47d72845a2bb89c6a3 (patch)
treecbf3fdb0dddf573edff89b50af22e8a84690cf00 /src/model/mapfile.cc
parent33e45d8052b385aa8b1fce68122c8d11f50e7e42 (diff)
split map reading from models
Diffstat (limited to 'src/model/mapfile.cc')
-rw-r--r--src/model/mapfile.cc546
1 files changed, 546 insertions, 0 deletions
diff --git a/src/model/mapfile.cc b/src/model/mapfile.cc
new file mode 100644
index 0000000..6252886
--- /dev/null
+++ b/src/model/mapfile.cc
@@ -0,0 +1,546 @@
+/*
+ filesystem/mapfile.cc
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include "filesystem/filesystem.h"
+#include "math/mathlib.h"
+#include "model/mapfile.h"
+#include "model/vertexarray.h"
+#include "sys/sys.h"
+
+#include <sstream>
+#include <string>
+
+namespace model {
+
+const float MAX_BOUNDS = 16384;
+const float MIN_DELTA = 10e-10;
+
+MapFile::MapFile() {}
+
+MapFile::~MapFile() {}
+
+bool MapFile::open(std::string const & name) {
+
+ last_read_was_classname = false;
+ last_read_was_key = false;
+ key_current = "";
+ value_current = "";
+ classname_current = "";
+ line_number = 0;
+ parse_level = 0;
+ brushes = 0;
+
+ mapfile_name.assign("maps/");
+ mapfile_name.append(name);
+ mapfile_name.append(".map");
+
+ filesystem::File *f = filesystem::open(mapfile_name.c_str());
+ if (!f) {
+ con_warn << "Could not open " << mapfile_name << std::endl;
+ return false;
+ }
+
+ std::string fn = f->path();
+ fn.append(f->name());
+ filesystem::close(f);
+
+ mapfile_ifs.open(fn.c_str());
+ if (!mapfile_ifs.is_open()) {
+ con_warn << "Could not stream " << fn << "!\n";
+ return false;
+ }
+
+ return true;
+}
+
+
+bool MapFile::got_classname() const {
+ return last_read_was_classname;
+}
+
+bool MapFile::got_classname(const char * classnamelabel) const {
+ return (last_read_was_classname && (classname_current.compare(classnamelabel) == 0));
+}
+
+bool MapFile::getline() {
+ using math::Vector3f;
+
+ char data[1024];
+
+ last_read_was_classname = false;
+ last_read_was_key = false;
+
+ key_current = "";
+ value_current = "";
+
+ if (!mapfile_ifs.is_open())
+ return false;
+
+ if (mapfile_ifs.getline(data, 1023)) {
+ line_number++;
+ std::istringstream linestream(data);
+ std::string firstword;
+
+ if (linestream >> firstword) {
+ if (!firstword.size()) {
+ return true;
+
+ } else if (firstword == "//") {
+ return true;
+
+ } else if (firstword == "{") {
+ parse_level++;
+
+ } else if (firstword == "}") {
+ if ((parse_level == 2) && (classname_current == "worldspawn")) {
+ // brush
+ if (VertexArray::instance()) {
+ // for every face
+ for (std::vector<Plane *>::iterator face = planes.begin(); face != planes.end(); face++) {
+ make_brushface((*face));
+ }
+
+ // clean planes
+ for (std::vector<Plane *>::iterator it = planes.begin(); it != planes.end(); it++) {
+ delete(*it);
+ }
+ planes.clear();
+
+ brushes++;
+ }
+ value_current.clear();
+ }
+ parse_level--;
+
+ } else if (parse_level == 1) {
+
+ if (firstword == "\"classname\"") {
+ classname_current.clear();
+
+ if (linestream >> classname_current) {
+ if (classname_current.size() > 2) {
+ classname_current.erase(0,1);
+ classname_current.erase(classname_current.size()-1, 1);
+ last_read_was_classname = true;
+ } else {
+ classname_current.clear();
+ }
+ }
+
+ } else if ((firstword.size() > 2) && (firstword[0] == '\"') && (firstword[firstword.size()-1] == '\"')) {
+
+ key_current.assign(firstword);
+ key_current.erase(0,1);
+ key_current.erase(key_current.size()-1, 1);
+
+ value_current.clear();
+ char c;
+ while ((linestream.get(c)) && (c != '"'));
+ while ((linestream.get(c)) && (c != '"'))
+ value_current += c;
+
+ last_read_was_key = true;
+ }
+
+ } else if (parse_level == 2) {
+
+ if ((firstword == "(") && (classname_current == "worldspawn")) {
+ // brush plane
+ if (VertexArray::instance()) {
+ Vector3f p1, p2, p3;
+ std::string tmp;
+ std::string texture;
+ int n = 0;
+
+ linestream >> p1;
+ linestream >> tmp; // )
+ linestream >> tmp; // (
+ linestream >> p2;
+ linestream >> tmp; // )
+ linestream >> tmp; // (
+ linestream >> p3;
+ linestream >> tmp; // )
+ linestream >> texture;
+
+ // 5 numbers (texture alignment?)
+ for (int i=0; i < 5; i++)
+ linestream >> tmp;
+
+ // surface flags ?
+ if (!(linestream >> n))
+ n = 0;
+
+ Plane *plane = new Plane(p1, p2, p3);
+ plane->texture() = texture;
+ if (n > 0)
+ plane->detail() = true;
+ planes.push_back(plane);
+ }
+ value_current.clear();
+ }
+ }
+ }
+ } else {
+
+ return false;
+ }
+
+ return true;
+}
+
+void MapFile::make_brushface(Plane *face)
+{
+ using math::Vector3f;
+
+ // ignore caulk
+ if (face->texture() == "common/caulk") {
+ return;
+ }
+
+ // FIXME clip should be parsed as collision blocks
+ if (face->texture() == "common/clip") {
+ return;
+ }
+
+ // using suggestions from
+ // http://www.flipcode.com/archives/Level_Editing.shtml
+
+ // vertex list
+ std::vector<math::Vector3f *> vl;
+
+ // calculate initial vertices on the bounding box
+
+ // check if the face is x-axis oriented
+ if ((fabsf(face->normal().x) >= fabsf(face->normal().y)) && (fabsf(face->normal().x) >= fabsf(face->normal().z))) {
+
+ if (face->normal().x >= 0) {
+ vl.push_back(new math::Vector3f(0, -MAX_BOUNDS, -MAX_BOUNDS));
+ vl.push_back(new math::Vector3f(0, -MAX_BOUNDS, MAX_BOUNDS));
+ vl.push_back(new math::Vector3f(0, MAX_BOUNDS, MAX_BOUNDS));
+ vl.push_back(new math::Vector3f(0, MAX_BOUNDS, -MAX_BOUNDS));
+ } else {
+ vl.push_back(new math::Vector3f(0, MAX_BOUNDS, -MAX_BOUNDS));
+ vl.push_back(new math::Vector3f(0, MAX_BOUNDS, MAX_BOUNDS));
+ vl.push_back(new math::Vector3f(0, -MAX_BOUNDS, MAX_BOUNDS));
+ vl.push_back(new math::Vector3f(0, -MAX_BOUNDS, -MAX_BOUNDS));
+ }
+ // calculate the x coordinate of each face vertex
+ for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) {
+ (*it)->x = (-face->d() -
+ face->normal().z * (*it)->z -
+ face->normal().y * (*it)->y) /
+ face->normal().x;
+ }
+ }
+
+ // check if the face is y-axis oriented
+ else if ((fabsf(face->normal().y) >= fabsf(face->normal().x)) && (fabsf(face->normal().y) >= fabsf(face->normal().z))) {
+
+ if (face->normal().y >= 0) {
+ vl.push_back(new Vector3f(MAX_BOUNDS, 0, -MAX_BOUNDS));
+ vl.push_back(new Vector3f(MAX_BOUNDS, 0, MAX_BOUNDS));
+ vl.push_back(new Vector3f(-MAX_BOUNDS, 0, MAX_BOUNDS));
+ vl.push_back(new Vector3f(-MAX_BOUNDS, 0, -MAX_BOUNDS));
+ } else {
+ vl.push_back(new Vector3f(-MAX_BOUNDS, 0, -MAX_BOUNDS));
+ vl.push_back(new Vector3f(-MAX_BOUNDS, 0, MAX_BOUNDS));
+ vl.push_back(new Vector3f(MAX_BOUNDS, 0, MAX_BOUNDS));
+ vl.push_back(new Vector3f(MAX_BOUNDS, 0, -MAX_BOUNDS));
+ }
+
+ // calculate the x coordinate of each face vertex
+ for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) {
+ (*it)->y = (-face->d() -
+ face->normal().z * (*it)->z -
+ face->normal().x * (*it)->x) /
+ face->normal().y;
+ }
+ }
+
+ // face must be z-axis oriented
+ else {
+
+ if (face->normal().z >= 0) {
+ vl.push_back(new Vector3f(-MAX_BOUNDS, -MAX_BOUNDS, 0));
+ vl.push_back(new Vector3f(-MAX_BOUNDS, MAX_BOUNDS, 0));
+ vl.push_back(new Vector3f(MAX_BOUNDS, MAX_BOUNDS, 0));
+ vl.push_back(new Vector3f(MAX_BOUNDS, -MAX_BOUNDS, 0));
+ } else {
+ vl.push_back(new Vector3f(MAX_BOUNDS, -MAX_BOUNDS, 0));
+ vl.push_back(new Vector3f(MAX_BOUNDS, MAX_BOUNDS, 0));
+ vl.push_back(new Vector3f(-MAX_BOUNDS, MAX_BOUNDS, 0));
+ vl.push_back(new Vector3f(-MAX_BOUNDS, -MAX_BOUNDS, 0));
+ }
+
+ // calculate the x coordinate of each face vertex
+ for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) {
+ (*it)->z = (-face->d() -
+ face->normal().x * (*it)->x -
+ face->normal().y * (*it)->y) /
+ face->normal().z;
+ }
+ }
+
+
+ // intersect the face with every plane
+ for (std::vector<Plane *>::iterator pit = planes.begin(); pit != planes.end(); pit++) {
+ Plane *plane = (*pit);
+ if (plane == face) {
+ continue;
+ }
+
+ Vector3f fn = crossproduct(face->point(1)-face->point(0), face->point(2)-face->point(0));
+ Vector3f pn = crossproduct(plane->point(1)-plane->point(0), plane->point(2)-plane->point(0));
+
+ Vector3f t = crossproduct(fn, pn);
+ if ((t.x == 0) && (t.y == 0) && (t.z == 0)) {
+ continue;
+ }
+
+ // intersect face with plane
+ for (int i=0; vl.size() - i > 0; i++) {
+
+ Vector3f v(*vl.at(i));
+
+ Vector3f next;
+ if (vl.size() - i > 1) {
+ next = *vl.at(i+1);
+ } else {
+ next = *vl.front();
+ }
+
+ Vector3f prev;
+ if (i > 0) {
+ prev = *vl.at(i-1);
+ } else {
+ prev = *vl.back();
+ }
+
+ if ((v.x*plane->normal().x + v.y*plane->normal().y + v.z*plane->normal().z +plane->d()) < MIN_DELTA) {
+
+ // find current
+ std::vector<Vector3f *>::iterator vit = vl.begin();
+ while ((*vit) != vl.at(i)) {
+ vit++;
+ }
+
+ // check if prev - v intersects with plane
+ if ((prev.x*plane->normal().x + prev.y*plane->normal().y + prev.z*plane->normal().z + plane->d()) > -MIN_DELTA) {
+
+ // calculate intersection
+ float t1 = -plane->normal().x * prev.x - plane->normal().y * prev.y - plane->normal().z * prev.z -plane->d();
+ float t2 = (plane->normal().x * v.x - plane->normal().x * prev.x +
+ plane->normal().y * v.y - plane->normal().y * prev.y +
+ plane->normal().z * v.z - plane->normal().z * prev.z);
+
+ Vector3f *s = new Vector3f;
+
+ if (t2 == 0) {
+ *s = v;
+ } else {
+ for (int j = 0; j < 3; j++)
+ (*s)[j] = prev [j] + t1 * (v[j] - prev[j]) / t2;
+ }
+
+ vit = vl.insert(vit,s);
+ vit++;
+ i++;
+ }
+
+ // check if next - v intersects with plane
+ if ((next.x*plane->normal().x + next.y*plane->normal().y + next.z*plane->normal().z + plane->d()) > -MIN_DELTA) {
+
+ // calculate intersection
+ float t1 = -plane->normal().x * v.x - plane->normal().y * v.y - plane->normal().z * v.z -plane->d();
+ float t2 = (plane->normal().x * next.x - plane->normal().x * v.x +
+ plane->normal().y * next.y - plane->normal().y * v.y +
+ plane->normal().z * next.z - plane->normal().z * v.z);
+ //cout << "next t2 " << t2 << std::endl;
+ Vector3f *s = new Vector3f;
+
+ if (t2 == 0) {
+ *s = v;
+ } else {
+ for (int j = 0; j < 3; j++)
+ (*s)[j] = v [j] + t1 * (next[j] - v[j]) / t2;
+ }
+
+ vit = vl.insert(vit,s);
+ vit++;
+ i++;
+ }
+
+ // erase
+ delete *vit;
+ vl.erase(vit);
+ i--;
+ }
+
+ }
+ }
+
+ if (vl.size() > 2) {
+
+ math::Color *color = 0;
+ if (face->texture() == "colors/white") {
+ color = new math::Color(1, 1, 1);
+ } else if (face->texture() == "colors/grey90") {
+ color = new math::Color(0.9, 0.9, 0.9);
+ } else if (face->texture() == "colors/grey75") {
+ color = new math::Color(0.75, 0.75, 0.75);
+ } else if (face->texture() == "colors/grey50") {
+ color = new math::Color(0.5, 0.5, 0.5);
+ } else if (face->texture() == "colors/grey25") {
+ color = new math::Color(0.25, 0.25, 0.25);
+ } else if (face->texture() == "colors/black") {
+ color = new math::Color(0, 0, 0);
+ } else if (face->texture() == "common/entity") {
+ color = 0;
+ } else
+ // unknown textures get hot pink
+ color = new math::Color(1.0f, 0.0, 1.0f);
+
+ // calculate bounding box
+ for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) {
+
+ *(*it) *= SCALE;
+
+ for (int i=0; i < 3; i++) {
+ if (class_maxbbox[i] < (*(*it))[i])
+ class_maxbbox[i] = (*(*it))[i];
+
+ if (class_minbbox[i] > (*(*it))[i])
+ class_minbbox[i] = (*(*it))[i];
+ }
+ }
+
+ // split face into triangles
+ while (vl.size() >2 ) {
+ std::vector<Vector3f *>::iterator v0 = vl.begin();
+ std::vector<Vector3f *>::reverse_iterator vn = vl.rbegin();
+ std::vector<Vector3f *>::reverse_iterator vn1 = vl.rbegin();
+ ++vn1;
+
+ Vector3f n(face->normal()*-1);
+ n.normalize();
+
+ if (!color) {
+ // evertices will be added to the VertexArray after normal vertices
+ Triangle *triangle = new Triangle(*(*vn1), *(*vn), *(*v0), n, 0, face->detail());
+ class_etris.push_back(triangle);
+ } else {
+ Triangle *triangle = new Triangle(*(*vn1), *(*vn), *(*v0), n, color, face->detail());
+ class_tris.push_back(triangle);
+ }
+
+ delete (*vn);
+ vl.pop_back();
+ }
+ if (color) delete color;
+ } else {
+ con_debug << "Unresolved face!\n";
+ }
+
+ // clean up the vertex list
+ for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) {
+ delete(*it);
+ }
+
+ vl.clear();
+}
+
+bool MapFile::got_key_string(const char * keylabel, std::string & valuestring) {
+ if (last_read_was_key && (key_current.compare(keylabel) == 0 )) {
+ valuestring.assign(value_current);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MapFile::got_key_vector3f(const char * keylabel, math::Vector3f & v) {
+ if (last_read_was_key && (key_current.compare(keylabel) == 0 )) {
+ std::istringstream is(value_current);
+ float x, y, z;
+ if ((is >> x) && (is >> y) && (is >> z)) {
+ v = math::Vector3f(x,y,z);
+ } else {
+ v= math::Vector3f();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MapFile::got_key_float(const char * keylabel, float & f) {
+ if (last_read_was_key && (key_current.compare(keylabel) == 0 )) {
+ std::istringstream is(value_current);
+ if (!(is >> f)) {
+ f = 0;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MapFile::got_key_int(const char * keylabel, unsigned int & u)
+{
+ if (last_read_was_key && (key_current.compare(keylabel) == 0 )) {
+ std::istringstream is(value_current);
+ if (!(is >> u)) {
+ u = 0;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MapFile::got_key(const char * keylabel) {
+ return (last_read_was_key && (key_current.compare(keylabel) == 0 ));
+}
+
+bool MapFile::got_key_angle(const char * keylabel, float & f) {
+ if (last_read_was_key && (key_current.compare(keylabel) == 0 )) {
+ std::istringstream is(value_current);
+ if ((is >> f)) {
+ f = math::degrees360f(f);
+ } else {
+ f = 0;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MapFile::got_key_color(const char * keylabel, math::Color & color) {
+ if (last_read_was_key && (key_current.compare(keylabel) == 0 )) {
+ std::istringstream is(value_current);
+ float r, g, b;
+ if ((is >> r) && (is >> g) && (is >> b)) {
+ if ((r > 1) || (g > 1) || (b > 1)) {
+ r /= 255; g /= 255; b /= 255;
+ }
+ color = math::Color(r, g, b);
+ } else {
+ color = math::Color();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void MapFile::close()
+{
+ mapfile_ifs.close();
+}
+
+} // namespace filesystem
+