diff options
author | Stijn Buys <ingar@osirion.org> | 2008-03-02 12:23:48 +0000 |
---|---|---|
committer | Stijn Buys <ingar@osirion.org> | 2008-03-02 12:23:48 +0000 |
commit | 81787e9004377016236865e95b95707ed6cf1d0b (patch) | |
tree | b8a7bd0d51f97848ad98ec8c8f5e424de910df32 /src/render | |
parent | 1d45d8ecb4633f07a0ff163255dbedc3c3a72ac8 (diff) |
initial (buggy) support for .map models
Diffstat (limited to 'src/render')
-rw-r--r-- | src/render/Makefile.am | 5 | ||||
-rw-r--r-- | src/render/face.cc | 43 | ||||
-rw-r--r-- | src/render/face.h | 39 | ||||
-rw-r--r-- | src/render/model.cc | 386 | ||||
-rw-r--r-- | src/render/model.h | 61 | ||||
-rw-r--r-- | src/render/render.cc | 5 |
6 files changed, 537 insertions, 2 deletions
diff --git a/src/render/Makefile.am b/src/render/Makefile.am index 183ab41..656ae26 100644 --- a/src/render/Makefile.am +++ b/src/render/Makefile.am @@ -3,5 +3,6 @@ METASOURCES = AUTO noinst_LTLIBRARIES = librender.la librender_la_LDFLAGS = -avoid-version -no-undefined @GL_LIBS@ librender_la_LIBADD = $(top_builddir)/src/math/libmath.la -librender_la_SOURCES = box.cc gl.cc render.cc sphere.cc text.cc tga.cc -noinst_HEADERS = box.h gl.h render.h sphere.h text.h tga.h +librender_la_SOURCES = box.cc face.cc gl.cc model.cc render.cc sphere.cc \ + text.cc tga.cc +noinst_HEADERS = box.h face.h gl.h model.h render.h sphere.h text.h tga.h diff --git a/src/render/face.cc b/src/render/face.cc new file mode 100644 index 0000000..cd69b4e --- /dev/null +++ b/src/render/face.cc @@ -0,0 +1,43 @@ +/* + render/face.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "render/face.h" +#include "render/gl.h" + +namespace render { + +Face::Face(math::Vector3f const & normal) : + face_normal(normal) +{ + face_normal.normalize(); +} + +Face::~Face() +{ + for (std::vector<math::Vector3f *>::iterator it = face_vertex.begin(); it != face_vertex.end(); it++) { + delete (*it); + } + + face_vertex.clear(); +} + +void Face::add_vertex(math::Vector3f const & vertex) +{ + math::Vector3f *v = new math::Vector3f(vertex); + + face_vertex.push_back(v); +} + +void Face::draw() +{ + gl::begin(gl::LineLoop); + for (std::vector<math::Vector3f *>::iterator it = face_vertex.begin(); it != face_vertex.end(); it++) { + gl::vertex(*(*it)); + } + gl::end(); +} + +} diff --git a/src/render/face.h b/src/render/face.h new file mode 100644 index 0000000..d44b1d0 --- /dev/null +++ b/src/render/face.h @@ -0,0 +1,39 @@ +/* + render/face.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_RENDER_FACE_H__ +#define __INCLUDED_RENDER_FACE_H__ + +#include <vector> + +#include "math/mathlib.h" + +namespace render { + +/// one face (polygon) of a model +class Face { +public: + Face(math::Vector3f const & normal); + ~Face(); + + /// the normal of this face + inline math::Vector3f const & normal() const { return face_normal; }; + + /// add a vertex to the face + void add_vertex(math::Vector3f const &vertex); + + /// draw the polygon + void draw(); + +private: + math::Vector3f face_normal; + std::vector<math::Vector3f *> face_vertex; +}; + +} + +#endif // __INCLUDED_RENDER_FACE_H__ + diff --git a/src/render/model.cc b/src/render/model.cc new file mode 100644 index 0000000..f048b7f --- /dev/null +++ b/src/render/model.cc @@ -0,0 +1,386 @@ +/* + render/model.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include <iostream> +#include <string> +#include <fstream> +#include <iomanip> +#include <sstream> +#include <vector> +#include <list> + +#include "render/model.h" +#include "render/gl.h" +#include "filesystem/filesystem.h" + +namespace render +{ + +const float MAX_BOUNDS = 8192; +const float delta = 10e-8; + +std::map<std::string, Model*> Model::registry; + +Model::Model(std::string const & name) : + model_name(name) +{ + model_scale = 1.0f / 64.0f; + + std::string fn("maps/"); + fn.append(name); + fn.append(".map"); + filesystem::File *f = filesystem::open(fn.c_str()); + + if (!f) { + return; + } + + fn = f->path(); + fn.append(f->name()); + filesystem::close(f); + + std::ifstream ifs(fn.c_str()); + if (!ifs.is_open()) { + con_warn << "Could not stream " << fn << "!\n"; + return; + } + con_debug << "Reading " << fn << "\n"; + + // --------- the actual reading + using math::Vector3f; + using math::Plane3f; + + std::vector<Plane3f *> planes; + std::string classname; + unsigned int level = 0; + char data[1024]; + + while (ifs) { + ifs.getline(data, 1023); + std::istringstream linestream(data); + std::string firstword; + + if (linestream >> firstword) { + if (firstword == "//") { + //cout << " COMMENT!" << std::endl; + continue; + } else if (firstword == "{") { + level ++; + //cout << " LEVEL +" << level << std::endl; + } else if (firstword == "}") { + //cout << " LEVEL -" << level << std::endl; + if ((level == 2) && (classname == "worldspawn")) { + //cout << "brush with " << planes.size() << " faces" << std::endl; + + // for every face + std::vector<Vector3f *>points; + for (std::vector<Plane3f *>::iterator face = planes.begin(); face != planes.end(); face++) { + make_face((*face), planes); + } + + // clean planes + for (std::vector<Plane3f *>::iterator it = planes.begin(); it != planes.end(); it++) { + delete (*it); + } + planes.clear(); + } + level--; + } else if (firstword == "\"classname\"") { + classname.clear(); + if (linestream >> classname) { + if (classname.size() > 2) { + classname.erase(0,1); + classname.erase(classname.size()-1, 1); + linestream >> classname; + //cout << " CLASS '" << classname << "'" << std::endl; + } else + classname.clear(); + } else { + //cout << " EMPTY CLASS" << std::endl; + } + } else if (firstword == "(") { + if ((level == 2) && (classname == "worldspawn")) { + //cout << " BRUSH PLANE" << std::endl; + Vector3f p1; + Vector3f p2; + Vector3f p3; + std::string tmp; + std::string texture; + + linestream >> p1; + linestream >> tmp; // ) + linestream >> tmp; // ( + linestream >> p2; + linestream >> tmp; // ) + linestream >> tmp; // ( + linestream >> p3; + linestream >> tmp; // ) + linestream >> texture; + + //cout << data << std::endl; + //cout << "(" << p1 << ") (" << p2 << ") (" << p3 << ") " << texture << std::endl; + + Plane3f *plane = new Plane3f(p1, p2, p3); + planes.push_back(plane); + //cout << "normal " << plane->normal() << std::endl; + } else { + //cout << " UNKNOWN line for '" << classname << "' level " << level << std::endl; + } + } + } + } + + ifs.close(); + + con_debug << "Loaded model " << name << " with " << model_face.size() << " polygons\n"; +} + +Model::~Model() +{ + // delete all faces + for (std::list<Face *>::iterator fit = model_face.begin(); fit != model_face.end(); fit++) { + delete(*fit); + } + + model_face.clear(); +} + +void Model::make_face(math::Plane3f *face, std::vector<math::Plane3f *> & planes) +{ + using math::Vector3f; + using math::Plane3f; + + //cout << "Face with normal " << face->normal() << endl; + std::vector<math::Vector3f *> vl; + + // inital vertexes + + // 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)) ) { + //cout << " x oriented" << std::endl; + 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)) ) { + //cout << " y oriented" << std::endl; + 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 { + //cout << " z oriented" << std::endl; + 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<Plane3f *>::iterator pit = planes.begin(); pit != planes.end(); pit++) { + Plane3f *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; + } + + //cout << " intersecting with plane with normal " << plane->normal() << std::endl; + // using suggestions from + // http://www.flipcode.com/archives/Level_Editing.shtml + + // 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) { + //cout << " -- at " << i+1 << std::endl; + next = *vl.at(i+1); + } else { + next = *vl.front(); + } + + Vector3f prev; + if (i > 0) { + //cout << " -- at " << i-1 << std::endl; + prev = *vl.at(i-1); + } else { + prev = *vl.back(); + } + + //cout << " vertex " << i << " prev " << prev << " v " << v << " next " << next << std::endl; + if ((v.x*plane->normal().x + v.y*plane->normal().y + v.y*plane->normal().y + v.z*plane->normal().z +plane->d()) < -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.y*plane->normal().y + prev.z*plane->normal().z + plane->d()) > 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); + //cout << "prev t2 " << t2 << std::endl; + 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; + } + + //cout << " added " << *s << std::endl; + 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.y*plane->normal().y + next.z*plane->normal().z + plane->d()) > delta ) { + // calculate intersection + + // calculate intersection + float t1 = -plane->normal().x * next.x - plane->normal().y * next.y - plane->normal().z * next.z -plane->d(); + float t2 = (plane->normal().x * v.x - plane->normal().x * next.x + + plane->normal().y * v.y - plane->normal().y * next.y + + plane->normal().z * v.z - plane->normal().z * next.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] = next [j] + t1 * ( v[j] - next[j]) / t2; + } + + //cout << " added " << *s << std::endl; + vit = vl.insert(vit,s); + vit++; + i++; + } + + // erase + delete *vit; + vl.erase(vit); + i--; + } + + } + } + + if (vl.size() > 2) { + Vector3f n = face->normal(); + n.normalize(); + Face *mf = new Face(n); + + for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) { + mf->add_vertex(*(*it)); + } + + //con_debug << "adding face\n"; + add_face(mf); + } + + for (std::vector<Vector3f *>::iterator it = vl.begin(); it != vl.end(); it++) { + delete (*it); + } + + vl.clear(); + +} + +void Model::add_face(Face *face) +{ + model_face.push_back(face); +} + +void Model::draw() +{ + gl::scale(model_scale, model_scale, model_scale); + + // draw all faces + for (std::list<Face *>::iterator fit = model_face.begin(); fit != model_face.end(); fit++) { + (*fit)->draw(); + } + +} + +Model *Model::find(std::string const & name) +{ + std::map<std::string, Model*>::iterator it = registry.find(name); + if (it == registry.end()) + return 0; + else + return (*it).second; +} + +Model *Model::get(std::string const & name) +{ + Model *model = find(name); + if (!model) { + model = new Model(name); + registry[model->name()] = model; + } + return model; +} + +void Model::clear() +{ + // delete all models in the registry + for (std::map<std::string, Model*>::iterator mit = registry.begin(); mit != registry.end(); mit++) { + delete (*mit).second; + } + registry.clear(); +} + +} diff --git a/src/render/model.h b/src/render/model.h new file mode 100644 index 0000000..ab6207e --- /dev/null +++ b/src/render/model.h @@ -0,0 +1,61 @@ +/* + render/model.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_RENDER_MODEL_H__ +#define __INCLUDED_RENDER_MODEL_H__ + +#include <map> +#include <list> + +#include "render/face.h" +#include "math/plane3f.h" + +namespace render { + +/// a 3D model contains a list of faces +class Model +{ +public: + /// load a model from disk + Model(std::string const & name); + ~Model(); + + /// the name of the model + inline std::string const & name() const { return model_name; } + + void add_face(Face *face); + + /// the Model registry + static std::map<std::string, Model*> registry; + + /// draw the model + void draw(); + +/* ---- static functions for the Model registry -------------------- */ + + /// get name model, returns 0 if not found + static Model *find(std::string const & name); + + /// get named model from the registry and load it if necessary + static Model *get(std::string const & name); + + /// clear the Model registry + static void clear(); + +private: + void make_face(math::Plane3f *face, std::vector<math::Plane3f *> & planes); + + std::list<Face *> model_face; + std::string model_name; + + float model_scale; + +}; + +} + +#endif // __INCLUDED_RENDER_MODEL_H__ + diff --git a/src/render/render.cc b/src/render/render.cc index fce3b6a..87f7424 100644 --- a/src/render/render.cc +++ b/src/render/render.cc @@ -6,6 +6,7 @@ // project headers #include "render/render.h" +#include "render/model.h" #include "core/core.h" #include "sys/sys.h" @@ -31,11 +32,15 @@ void init() con_error << "Essential file bitmaps/conchars.tga missing" << std::endl; core::application()->shutdown(); } + + Model::clear(); } void shutdown() { con_print << "Shutting down renderer..." << std::endl; + + Model::clear(); } } |