Skip to content

Commit

Permalink
[#88] refactor(Mesh): speed up world mesh parsing
Browse files Browse the repository at this point in the history
This commit moves the allocation of many small vectors within `zenkit::Polygon` into a two larger vectors inside `zenkit::Mesh`, reducing the number of small allocation made.

Doing this leads to a 25% performance boost (from 193ms to 144ms) on my laptop running Fedora 40 on an Intel Core i7-11800H.
  • Loading branch information
lmichaelis committed May 11, 2024
1 parent 89af81c commit 1f88732
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 15 deletions.
6 changes: 4 additions & 2 deletions include/zenkit/Mesh.hh
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ namespace zenkit {
int32_t lightmap;
PolygonFlagSet flags;

std::vector<uint32_t> vertices;
std::vector<uint32_t> features;
size_t index_count;
size_t index_offset;
};

/// \brief Represents a *ZenGin* basic mesh.
Expand Down Expand Up @@ -161,6 +161,8 @@ namespace zenkit {
std::vector<LightMap> lightmaps {};

std::vector<Polygon> geometry {};
std::vector<uint32_t> polygon_vertex_indices;
std::vector<uint32_t> polygon_feature_indices;

/// \brief A list of polygons of this mesh.
PolygonList polygons {};
Expand Down
36 changes: 23 additions & 13 deletions src/Mesh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ namespace zenkit {
auto poly_count = c->read_uint();
this->geometry.resize(poly_count);

// At least 3 indices per polygon (triangulated).
this->polygon_vertex_indices.reserve(poly_count * 3);
this->polygon_feature_indices.reserve(poly_count * 3);
uint32_t index_offset = 0;

for (std::uint32_t i = 0; i < poly_count; ++i) {
this->geometry[i].material = c->read_ushort();
this->geometry[i].lightmap = c->read_short();
Expand Down Expand Up @@ -133,9 +138,14 @@ namespace zenkit {
auto has_wide_indices = (version == MESH_VERSION_G2) || force_wide_indices;

for (int32_t j = 0; j < vertex_count; ++j) {
this->geometry[i].vertices.push_back(has_wide_indices ? c->read_uint() : c->read_ushort());
this->geometry[i].features.push_back(c->read_uint());
this->polygon_vertex_indices.push_back(has_wide_indices ? c->read_uint()
: c->read_ushort());
this->polygon_feature_indices.push_back(c->read_uint());
}

this->geometry[i].index_count = vertex_count;
this->geometry[i].index_offset = index_offset;
index_offset += vertex_count;
}

break;
Expand Down Expand Up @@ -205,22 +215,22 @@ namespace zenkit {
}

auto& polygon = this->geometry[i];
if (polygon.vertices.size() < 3 || polygon.flags.is_portal || polygon.flags.is_ghost_occluder ||
if (polygon.index_count < 3 || polygon.flags.is_portal || polygon.flags.is_ghost_occluder ||
polygon.flags.is_outdoor) {
continue;
}

auto a = 1u;

// NOTE(lmichaelis): This unpacks triangle fans
for (auto b = 2u; b < polygon.vertices.size(); ++b) {
auto root = 0u;
this->polygons.vertex_indices.push_back(polygon.vertices[root]);
this->polygons.vertex_indices.push_back(polygon.vertices[a]);
this->polygons.vertex_indices.push_back(polygon.vertices[b]);
this->polygons.feature_indices.push_back(polygon.features[root]);
this->polygons.feature_indices.push_back(polygon.features[a]);
this->polygons.feature_indices.push_back(polygon.features[b]);
for (auto b = 2u; b < polygon.index_count; ++b) {
auto root = polygon.index_offset;
this->polygons.vertex_indices.push_back(polygon_vertex_indices[root]);
this->polygons.vertex_indices.push_back(polygon_vertex_indices[root + a]);
this->polygons.vertex_indices.push_back(polygon_vertex_indices[root + b]);
this->polygons.feature_indices.push_back(polygon_feature_indices[root]);
this->polygons.feature_indices.push_back(polygon_feature_indices[root + a]);
this->polygons.feature_indices.push_back(polygon_feature_indices[root + b]);
this->polygons.material_indices.push_back(polygon.material);
this->polygons.lightmap_indices.push_back(polygon.lightmap);
this->polygons.flags.push_back(polygon.flags);
Expand Down Expand Up @@ -297,8 +307,8 @@ namespace zenkit {
c->write_short(flags.sector_index);
}

c->write_ubyte(poly.vertices.size());
for (auto i = 0u; i < poly.vertices.size(); ++i) {
c->write_ubyte(poly.index_count);
for (auto i = 0u; i < poly.index_count; ++i) {
if (version == GameVersion::GOTHIC_1) {
c->write_ushort(this->polygons.vertex_indices[i]);
c->write_uint(this->polygons.feature_indices[i]);
Expand Down

0 comments on commit 1f88732

Please sign in to comment.