From 035653e94a3d74b8f18c993034199d7cd08a895a Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Fri, 21 Jan 2011 14:41:35 +0000 Subject: Support structures for complex entity collision, renamed sv_arrysize cvar to mem_vertex. --- src/model/Makefile.am | 2 + src/model/collisionmesh.cc | 76 +++++++++++++++++++++++ src/model/collisionmesh.h | 102 +++++++++++++++++++++++++++++++ src/model/mapfile.cc | 146 +++++++++++++++++++++++++++++---------------- src/model/mapfile.h | 2 + src/model/material.cc | 9 ++- src/model/material.h | 2 +- src/model/model.cc | 9 ++- src/model/model.h | 9 +++ src/model/vertexarray.cc | 50 ++++++++-------- src/model/vertexarray.h | 35 ++++++----- 11 files changed, 344 insertions(+), 98 deletions(-) create mode 100644 src/model/collisionmesh.cc create mode 100644 src/model/collisionmesh.h (limited to 'src/model') diff --git a/src/model/Makefile.am b/src/model/Makefile.am index 3d9d7c0..cba5c48 100644 --- a/src/model/Makefile.am +++ b/src/model/Makefile.am @@ -5,6 +5,7 @@ INCLUDES = -I$(top_srcdir)/src noinst_LTLIBRARIES = libmodel.la noinst_HEADERS = \ asefile.h \ + collisionmesh.h \ face.h \ fragment.h \ mapfile.h \ @@ -18,6 +19,7 @@ noinst_HEADERS = \ libmodel_la_SOURCES = \ asefile.cc \ + collisionmesh.cc \ face.cc \ fragment.cc \ mapfile.cc \ diff --git a/src/model/collisionmesh.cc b/src/model/collisionmesh.cc new file mode 100644 index 0000000..616ee0d --- /dev/null +++ b/src/model/collisionmesh.cc @@ -0,0 +1,76 @@ +/* + model/collisionmesh.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "sys/sys.h" +#include "model/collisionmesh.h" + +namespace model { + +CollisionMesh::Registry CollisionMesh::collisionmesh_registry; +bool CollisionMesh::collisionmesh_initialized = false; + +void CollisionMesh::init() +{ + clear(); + collisionmesh_initialized = true; +} + +void CollisionMesh::shutdown() +{ + clear(); + collisionmesh_initialized = false; +} + +void CollisionMesh::add(CollisionMesh *collisionmesh) +{ + collisionmesh_registry[collisionmesh->name()] = collisionmesh; +} + +void CollisionMesh::clear() +{ + con_debug << " clearing collision meshes" << std::endl; + + for (Registry::iterator i = collisionmesh_registry.begin(); i != collisionmesh_registry.end(); ++i) { + delete(*i).second; + } + + collisionmesh_registry.clear(); +} + +CollisionMesh *CollisionMesh::find(const std::string &name) +{ + for (Registry::iterator i = collisionmesh_registry.begin(); i != collisionmesh_registry.end(); ++i) { + if ((*i).first.compare(name) == 0) + return (*i).second; + } + + return 0; +} + +CollisionMesh::CollisionMesh(const std::string &name) : + collisionmesh_name(name) +{ + collisionmesh_size = 0; + // btTriangleMesh (bool use32bitIndices=true, bool use4componentVertices=true) + collisionmesh_triangles = new btTriangleMesh(true, false); +} + +CollisionMesh::~CollisionMesh() +{ + delete collisionmesh_triangles; +} + +void CollisionMesh::add_triangle(const math::Vector3f & v0, const math::Vector3f & v1, const math::Vector3f & v2) +{ + collisionmesh_triangles->addTriangle( + to_btVector3(v0), + to_btVector3(v1), + to_btVector3(v1) + ); + collisionmesh_size += 1; +} + +} // namespace model diff --git a/src/model/collisionmesh.h b/src/model/collisionmesh.h new file mode 100644 index 0000000..9efd21a --- /dev/null +++ b/src/model/collisionmesh.h @@ -0,0 +1,102 @@ +/* + model/collisionmesh.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_MODEL_COLLISIONMESH_H__ +#define __INCLUDED_MODEL_COLLISIONMESH_H__ + +#include "math/mathlib.h" + +#include "BulletCollision/CollisionShapes/btTriangleMesh.h" + +#include +#include + +namespace model +{ + +class CollisionMesh +{ +public: + + /// type definition for the material registry + typedef std::map Registry; + + CollisionMesh(const std::string &name); + + ~CollisionMesh(); + + /* ---- inspectors ----------------------------------------- */ + + inline const std::string &name() const { + return collisionmesh_name; + } + + /** + * @brief the number of triangles in the collision mesh + */ + inline size_t size() const { + return collisionmesh_size; + } + + static bool initialized() { + return collisionmesh_initialized; + } + + /** + * @brief the bullet triangle mesh object + */ + inline btTriangleMesh *triangles() { + return collisionmesh_triangles; + } + + /* ---- mutators ------------------------------------------- */ + + /** + * @brief add a triangle to the collision mesh + */ + void add_triangle(const math::Vector3f & v0, const math::Vector3f & v1, const math::Vector3f & v2); + + /* ---- static ----------------------------------------------------- */ + + /** + * @brief initialize collisionmesh registry + */ + static void init(); + + /** + * @brief shutdown collisionmesh registry + */ + static void shutdown(); + + /** + * @brief clear collisionmesh registry + */ + static void clear(); + + /** + * @brief find a collisionmesh in the registry + */ + static CollisionMesh *find(const std::string &name); + + /** + * @brief add a collisionmesh to the registry + */ + static void add(CollisionMesh *collisionmesh); + +private: + + /// the materials registry + static Registry collisionmesh_registry; + static bool collisionmesh_initialized; + + std::string collisionmesh_name; + size_t collisionmesh_size; + btTriangleMesh *collisionmesh_triangles; +}; + +} // namespace model + +#endif // __INCLUDED_MODEL_COLLISIONMESH_H__ diff --git a/src/model/mapfile.cc b/src/model/mapfile.cc index 5e18a0d..bfe19c0 100644 --- a/src/model/mapfile.cc +++ b/src/model/mapfile.cc @@ -7,6 +7,7 @@ #include "auxiliary/functions.h" #include "filesystem/filesystem.h" #include "math/mathlib.h" +#include "model/collisionmesh.h" #include "model/mapfile.h" #include "model/material.h" #include "model/model.h" @@ -147,6 +148,8 @@ MapFile::MapFile() map_brushes = 0; map_faces = 0; map_faces_detail = 0; + + map_load_clip = false; in_patchdef = false; warning_q2brush = false; @@ -924,32 +927,36 @@ void MapFile::make_brushface(Face *face) Vector3f face_normal(face->normal()* -1); face_normal.normalize(); - // split polygon into quads - while (vl.size() > 3) { - std::vector::iterator v0 = vl.begin(); - std::vector::reverse_iterator vn = vl.rbegin(); - std::vector::reverse_iterator vn1 = vl.rbegin(); - ++vn1; - std::vector::reverse_iterator vn2 = vl.rbegin(); - ++vn2; - ++vn2; - - Quad *quad = new Quad(*(*vn2) * SCALE, *(*vn1) * SCALE, *(*vn) * SCALE, *(*v0) * SCALE, face_normal, face->detail()); - primitives->add_quad(quad); + // clip faces have to be triangulated and can not be split into quads + if (!(face->material()->flags() & Material::Clip)) { + + // split polygon into quads + while (vl.size() > 3) { + std::vector::iterator v0 = vl.begin(); + std::vector::reverse_iterator vn = vl.rbegin(); + std::vector::reverse_iterator vn1 = vl.rbegin(); + ++vn1; + std::vector::reverse_iterator vn2 = vl.rbegin(); + ++vn2; + ++vn2; + + Quad *quad = new Quad(*(*vn2) * SCALE, *(*vn1) * SCALE, *(*vn) * SCALE, *(*v0) * SCALE, face_normal, face->detail()); + primitives->add_quad(quad); + + if (face->material()->flags() & Material::Texture) { + quad->t0().assign(map_texture_coords(face, *(*vn2))); + quad->t1().assign(map_texture_coords(face, *(*vn1))); + quad->t2().assign(map_texture_coords(face, *(*vn))); + quad->t3().assign(map_texture_coords(face, *(*v0))); + } - if (face->material()->flags() & Material::Texture) { - quad->t0().assign(map_texture_coords(face, *(*vn2))); - quad->t1().assign(map_texture_coords(face, *(*vn1))); - quad->t2().assign(map_texture_coords(face, *(*vn))); - quad->t3().assign(map_texture_coords(face, *(*v0))); + delete(*vn); + delete(*vn1); + vl.pop_back(); + vl.pop_back(); } - - delete(*vn); - delete(*vn1); - vl.pop_back(); - vl.pop_back(); } - + // split polygon into triangles while (vl.size() > 2) { std::vector::iterator v0 = vl.begin(); @@ -965,11 +972,12 @@ void MapFile::make_brushface(Face *face) triangle->t1().assign(map_texture_coords(face, *(*vn))); triangle->t2().assign(map_texture_coords(face, *(*v0))); } + delete(*vn); vl.pop_back(); } } else { - con_warn << name() << " unresolved face at line " << line() << std::endl; + con_warn << name() << " unresolved brush face at line " << line() << std::endl; } // clean up the vertex list @@ -1170,38 +1178,47 @@ void MapFile::load_fragmentgroup(Model *model, const FragmentGroup::Type class_t // store triangles if (primitives->triangles().size()) { - Fragment *fragment = new Fragment(Fragment::Triangles, primitives->material()); - - // add structural triangles to the fragment - for (Primitives::Triangles::iterator tris_it = primitives->triangles().begin(); tris_it != primitives->triangles().end(); tris_it++) { - Triangle *triangle = (*tris_it); - if (!triangle->detail()) { - size_t count = 0; - count += fragment->add_vertex(triangle->v0() - translation, triangle->normal(), triangle->t0(), false); - count += fragment->add_vertex(triangle->v1() - translation, triangle->normal(), triangle->t1(), false); - count += fragment->add_vertex(triangle->v2() - translation, triangle->normal(), triangle->t2(), false); - if (count == 3) - model->model_tris_count++; + if (!(primitives->material()->flags() & Material::Clip)) { + Fragment *fragment = new Fragment(Fragment::Triangles, primitives->material()); + + // add structural triangles to the fragment + for (Primitives::Triangles::iterator tris_it = primitives->triangles().begin(); tris_it != primitives->triangles().end(); tris_it++) { + Triangle *triangle = (*tris_it); + if (!triangle->detail()) { + size_t count = 0; + count += fragment->add_vertex(triangle->v0() - translation, triangle->normal(), triangle->t0(), false); + count += fragment->add_vertex(triangle->v1() - translation, triangle->normal(), triangle->t1(), false); + count += fragment->add_vertex(triangle->v2() - translation, triangle->normal(), triangle->t2(), false); + if (count == 3) + model->model_tris_count++; + } } - } - // add detail triangles to the fragment - for (Primitives::Triangles::iterator tris_it = primitives->triangles().begin(); tris_it != primitives->triangles().end(); tris_it++) { - Triangle *triangle = (*tris_it); - if (triangle->detail()) { - size_t count = 0; - count += fragment->add_vertex(triangle->v0() - translation, triangle->normal(), triangle->t0(), true); - count += fragment->add_vertex(triangle->v1() - translation, triangle->normal(), triangle->t1(), true); - count += fragment->add_vertex(triangle->v2() - translation, triangle->normal(), triangle->t2(), true); - if (count == 3) { - model->model_tris_count++; - model->model_tris_detail_count++; + // add detail triangles to the fragment + for (Primitives::Triangles::iterator tris_it = primitives->triangles().begin(); tris_it != primitives->triangles().end(); tris_it++) { + Triangle *triangle = (*tris_it); + if (triangle->detail()) { + size_t count = 0; + count += fragment->add_vertex(triangle->v0() - translation, triangle->normal(), triangle->t0(), true); + count += fragment->add_vertex(triangle->v1() - translation, triangle->normal(), triangle->t1(), true); + count += fragment->add_vertex(triangle->v2() - translation, triangle->normal(), triangle->t2(), true); + if (count == 3) { + model->model_tris_count++; + model->model_tris_detail_count++; + } } } - } - // add the fragment to the group - group->add_fragment(fragment); + // add the fragment to the group + group->add_fragment(fragment); + + } else if (map_load_clip) { + // clip materials are loaded into the CollisionArray + for (Primitives::Triangles::iterator tris_it = primitives->triangles().begin(); tris_it != primitives->triangles().end(); tris_it++) { + Triangle *triangle = (*tris_it); + model->collisionmesh()->add_triangle(triangle->v0(), triangle->v1(), triangle->v2()); + } + } } // store quads @@ -1309,9 +1326,23 @@ Model * MapFile::load(std::string const &name) unsigned int u; float r, s; std::string str; + + // load clip into collision mesh + // if the model has been loaded before (e.g. on r_restart), the collision mesh won't be reloaded + // submodel clip will not be imported + model->set_collisionmesh(CollisionMesh::find(name)); + + if (CollisionMesh::initialized() && !model->collisionmesh()) { + mapfile.map_load_clip = true; + + // create a collision mesh instance for the model + model->set_collisionmesh(new CollisionMesh(name)); + + } else { + mapfile.map_load_clip = false; + } while (mapfile.getline()) { - if (mapfile.got_classname("worldspawn")) { mapfile.clear_bbox(); @@ -1861,6 +1892,17 @@ Model * MapFile::load(std::string const &name) model->model_tris_detail_count << "/" << model->model_tris_count << " detail/tris " << model->model_quad_detail_count << "/" << model->model_quad_count << " detail/quads" << std::endl; + if (mapfile.map_load_clip) { + if (!model->collisionmesh()->size()) { + // delete empty collision meshes + delete model->collisionmesh(); + model->set_collisionmesh(0); + } else { + // add the collision mesh to the registry + CollisionMesh::add(model->collisionmesh()); + con_debug << " " << mapfile.name() << " " << model->collisionmesh()->size() << " collision triangles" << std::endl; + } + } return model; } diff --git a/src/model/mapfile.h b/src/model/mapfile.h index 5e4bfd8..ed63ad2 100644 --- a/src/model/mapfile.h +++ b/src/model/mapfile.h @@ -181,6 +181,8 @@ private: bool last_read_was_key; bool last_read_was_classname; bool last_read_was_classend; + + bool map_load_clip; unsigned int map_brushes; unsigned int map_faces; diff --git a/src/model/material.cc b/src/model/material.cc index 6baf4f9..2cacf42 100644 --- a/src/model/material.cc +++ b/src/model/material.cc @@ -188,15 +188,20 @@ void Material::load_shader(const std::string &shadername) material->set_flags(Tertiary); } else if (firstword.compare("ignore") == 0) { material->set_flags(Ignore); + } else if (firstword.compare("clip") == 0) { + material->set_flags(Clip); } else if (firstword.compare("qer_editorimage") == 0) { + // keyword qer_editorimage is ignored continue; } else if (firstword.compare("qer_trans") == 0) { + // keyword qer_trans is ignored + continue; + } else if (firstword.compare("surfaceparm") == 0) { + // keyword surfaceparm is ignored continue; } else if (firstword.compare("texture") == 0) { - // texture name should not contain spaces if (linestream >> firstword) { - // remove extension if (firstword[firstword.size()-4] == '.') { firstword.erase(firstword.size() - 4); diff --git a/src/model/material.h b/src/model/material.h index 44470e5..3c0ccf1 100644 --- a/src/model/material.h +++ b/src/model/material.h @@ -24,7 +24,7 @@ public: typedef void(* LoaderFuncPtr)(Material *); /// surface flags - enum SurfaceFlags { None = 0, Primary = 1, Secondary = 2, Tertiary = 3, Bright = 4, Engine = 8, Environment = 16, Texture = 32, Ignore = 64}; + enum SurfaceFlags { None = 0, Primary = 1, Secondary = 2, Tertiary = 3, Bright = 4, Engine = 8, Environment = 16, Texture = 32, Ignore = 64, Clip = 128}; /// type definition for the material registry typedef std::map Registry; diff --git a/src/model/model.cc b/src/model/model.cc index fb33bd0..d1805df 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -1,5 +1,5 @@ /* - render/model.h + render/model.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ @@ -29,6 +29,8 @@ Model::Model(const std::string & name) : model_tris_count = 0; model_quad_detail_count = 0; model_quad_count = 0; + + model_collisionmesh = 0; } Model::~Model() @@ -70,6 +72,11 @@ Model::~Model() model_sounds.clear(); } +void Model::set_collisionmesh(CollisionMesh *collisionmesh) +{ model_collisionmesh = collisionmesh; + +} + void Model::set_origin(const math::Vector3f &origin) { model_origin.assign(origin); diff --git a/src/model/model.h b/src/model/model.h index d3973c9..8e3d82d 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -13,6 +13,7 @@ #include "math/mathlib.h" +#include "model/collisionmesh.h" #include "model/tags.h" #include "model/fragment.h" @@ -75,6 +76,10 @@ public: return model_groups; } + inline CollisionMesh *collisionmesh() { + return model_collisionmesh; + } + /// list of model light tags inline Lights & lights() { return model_lights; @@ -145,6 +150,9 @@ public: /// set model radius void set_radius(const float radius); + /// set model collision mesh + void set_collisionmesh(CollisionMesh *collisionmesh); + /// set model origin void set_origin(const math::Vector3f &origin); @@ -198,6 +206,7 @@ private: Groups model_groups; float model_radius; static Registry model_registry; + CollisionMesh *model_collisionmesh; }; } diff --git a/src/model/vertexarray.cc b/src/model/vertexarray.cc index d06b976..881e266 100644 --- a/src/model/vertexarray.cc +++ b/src/model/vertexarray.cc @@ -14,37 +14,39 @@ namespace model { -VertexArray *VertexArray::vertex_instance = 0 ; +VertexArray *VertexArray::vertexarray_instance = 0 ; VertexArray::VertexArray(size_t size) { - vertex_instance = this; + assert(size > 0); + + vertexarray_instance = this; - vertex_size = size * 1024 * 1024; // megabytes - vertex_size = vertex_size / sizeof(float); // sizeof float + vertexarray_size = size * 1024 * 1024; // megabytes + vertexarray_size = vertexarray_size / sizeof(float); // sizeof float - vertex_data = (float *) malloc(vertex_size * sizeof(float)); + vertexarray_data = (float *) malloc(vertexarray_size * sizeof(float)); con_print << "^BInitializing vertex array..." << std::endl; - con_print << " " << (vertex_size * sizeof(float)) / (1024 * 1024) << " Mb allocated" << std::endl; + con_print << " " << (vertexarray_size * sizeof(float)) / (1024 * 1024) << " Mb allocated" << std::endl; clear(); } VertexArray::~VertexArray() { - free(vertex_data); + free(vertexarray_data); - vertex_instance = 0 ; + vertexarray_instance = 0 ; } void VertexArray::clear() { - vertex_dirty = true; - vertex_index = 0; - vertex_overflow = false; + vertexarray_dirty = true; + vertexarray_index = 0; + vertexarray_overflow = false; - memset(vertex_data, 0, sizeof(vertex_data)); + memset(vertexarray_data, 0, sizeof(vertexarray_data)); add_sphere(); } @@ -106,10 +108,10 @@ void VertexArray::add_sphere() size_t VertexArray::add_vertex(math::Vector3f const &v, math::Vector3f const &n, float tex_x, float tex_y) { - if (vertex_index + 8 >= vertex_size) { - if (!vertex_overflow) { + if (vertexarray_index + 8 >= vertexarray_size) { + if (!vertexarray_overflow) { con_warn << "VertexArray overflow!" << std::endl; - vertex_overflow = true; + vertexarray_overflow = true; } return 0; } @@ -117,19 +119,19 @@ size_t VertexArray::add_vertex(math::Vector3f const &v, math::Vector3f const &n, // GL_T2F_N3F_V3F // texture coordinates - vertex_data[vertex_index] = tex_x; - vertex_data[vertex_index+1] = tex_y; + vertexarray_data[vertexarray_index] = tex_x; + vertexarray_data[vertexarray_index+1] = tex_y; for (int i = 0; i < 3; i ++) { // normal - vertex_data[vertex_index+2+i] = n[i]; + vertexarray_data[vertexarray_index+2+i] = n[i]; // vertex coordinates - vertex_data[vertex_index+5+i] = v[i]; + vertexarray_data[vertexarray_index+5+i] = v[i]; } - vertex_index += 8; + vertexarray_index += 8; - vertex_dirty = true; + vertexarray_dirty = true; return 1; } @@ -138,9 +140,9 @@ void VertexArray::info() { const size_t mbfl = 1024 * 1024 / sizeof(float); con_print << " vertex array " - << vertex_index / mbfl << "/" << vertex_size / mbfl << "Mib " - << vertex_index / 8 << "/" << vertex_size / 8 << " verts " - << "^B" << vertex_index * 100 / vertex_size << "%^N used" << std::endl; + << vertexarray_index / mbfl << "/" << vertexarray_size / mbfl << "Mib " + << vertexarray_index / 8 << "/" << vertexarray_size / 8 << " verts " + << "^B" << vertexarray_index * 100 / vertexarray_size << "%^N used" << std::endl; } } diff --git a/src/model/vertexarray.h b/src/model/vertexarray.h index 9a71811..1474c67 100644 --- a/src/model/vertexarray.h +++ b/src/model/vertexarray.h @@ -15,7 +15,7 @@ namespace model // number of segments in a sphere circle, must be uneven const int SPHERESEGMENTS = 65; -/// global vertex array +/// global geometry vertex array /** a VertexArray acts like a stack of model vertices, it has no knowledge of what it is holding */ class VertexArray @@ -35,51 +35,50 @@ public: /// true when the array is full inline bool overflow() const { - return vertex_overflow; + return vertexarray_overflow; } /// return true if the vertex data has changed and needs to uploaded to video memory inline bool dirty() const { - return vertex_dirty; + return vertexarray_dirty; } /// pointer to model vertices, sequential in GL_T2F_N3F_V3F format inline const float *ptr() const { - return vertex_data; + return vertexarray_data; } /// size of the vertex array in number of floats (for a single array) inline size_t size() const { - return vertex_size; + return vertexarray_size; } /// number of allocated floats inline size_t index() const { - return vertex_index; + return vertexarray_index; } inline void set_dirty(const bool dirty = true) { - vertex_dirty = dirty; + vertexarray_dirty = dirty; } static inline VertexArray *instance() { - return vertex_instance; + return vertexarray_instance; } private: - /// model vertices, sequential in GL_T2F_N3F_V3F format - float *vertex_data; - - size_t vertex_index; - size_t vertex_size; - void add_sphere(); + + size_t vertexarray_index; + size_t vertexarray_size; + + /// model vertices, sequential in GL_T2F_N3F_V3F format + float *vertexarray_data; - static VertexArray *vertex_instance; - - bool vertex_overflow; + bool vertexarray_overflow; + bool vertexarray_dirty; - bool vertex_dirty; + static VertexArray *vertexarray_instance; }; } -- cgit v1.2.3