Implement leafbrushes cache

Fix bmodel leafbrushes (tank Spoike)
This commit is contained in:
Jonathan 2021-09-12 13:27:39 -04:00
parent 42cc946db1
commit ae02ff5393
1 changed files with 59 additions and 10 deletions

View File

@ -40,17 +40,57 @@ bool node_t::opaque() const {
return contents.is_structural_sky_or_solid(options.target_game); return contents.is_structural_sky_or_solid(options.target_game);
} }
// a simple tree structure used for leaf brush
// compression.
struct leafbrush_entry_t {
uint32_t offset;
std::map<uint32_t, leafbrush_entry_t> entries;
};
// per-entity
static struct { static struct {
uint32_t total_brushes, total_brush_sides; uint32_t total_brushes, total_brush_sides;
uint32_t total_leaf_brushes, unique_leaf_brushes; uint32_t total_leaf_brushes, unique_leaf_brushes;
std::map<uint32_t, leafbrush_entry_t> leaf_entries;
} brush_state; } brush_state;
static void ExportBrushList_r(const mapentity_t *entity, node_t *node) // running total
static uint32_t brush_offset;
static std::optional<uint32_t> FindLeafBrushesSpanOffset(const std::vector<uint32_t> &brushes) {
int32_t offset = 0;
const auto *map = &brush_state.leaf_entries;
decltype(brush_state.leaf_entries)::const_iterator it = map->find(brushes[offset]);
while (it != map->end()) {
if (++offset == brushes.size()) {
return it->second.offset;
}
map = &it->second.entries;
it = map->find(brushes[offset]);
}
return std::nullopt;
}
static void PopulateLeafBrushesSpan(const std::vector<uint32_t> &brushes, uint32_t offset) {
auto *map = &brush_state.leaf_entries;
for (auto &id : brushes) {
auto it = map->try_emplace(id, leafbrush_entry_t { offset });
map = &it.first->second.entries;
offset++;
}
}
static void ExportBrushList_r(const mapentity_t *entity, node_t *node, const uint32_t &brush_offset)
{ {
if (node->planenum == PLANENUM_LEAF) if (node->planenum == PLANENUM_LEAF)
{ {
if (node->contents.native) { if (node->contents.native) {
int32_t b_id = 0; uint32_t b_id = brush_offset;
std::vector<uint32_t> brushes; std::vector<uint32_t> brushes;
for (const brush_t *b = entity->brushes; b; b = b->next, b_id++) for (const brush_t *b = entity->brushes; b; b = b->next, b_id++)
@ -65,20 +105,27 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
brush_state.total_leaf_brushes += node->numleafbrushes; brush_state.total_leaf_brushes += node->numleafbrushes;
if (brushes.size()) { if (brushes.size()) {
auto span = FindLeafBrushesSpanOffset(brushes);
if (span.has_value()) {
node->firstleafbrush = *span;
} else {
node->firstleafbrush = map.exported_leafbrushes.size(); node->firstleafbrush = map.exported_leafbrushes.size();
PopulateLeafBrushesSpan(brushes, node->firstleafbrush);
map.exported_leafbrushes.insert(map.exported_leafbrushes.end(), brushes.begin(), brushes.end()); map.exported_leafbrushes.insert(map.exported_leafbrushes.end(), brushes.begin(), brushes.end());
brush_state.unique_leaf_brushes += node->numleafbrushes; brush_state.unique_leaf_brushes += node->numleafbrushes;
} }
} }
}
return; return;
} }
ExportBrushList_r(entity, node->children[0]); ExportBrushList_r(entity, node->children[0], brush_offset);
ExportBrushList_r(entity, node->children[1]); ExportBrushList_r(entity, node->children[1], brush_offset);
} }
static void ExportBrushList(const mapentity_t *entity, node_t *node) static void ExportBrushList(const mapentity_t *entity, node_t *node, uint32_t &brush_offset)
{ {
brush_state = { }; brush_state = { };
@ -143,7 +190,9 @@ static void ExportBrushList(const mapentity_t *entity, node_t *node)
brush_state.total_brushes++; brush_state.total_brushes++;
} }
ExportBrushList_r(entity, node); ExportBrushList_r(entity, node, brush_offset);
brush_offset += brush_state.total_brushes;
Message(msgStat, "%8u total brushes", brush_state.total_brushes); Message(msgStat, "%8u total brushes", brush_state.total_brushes);
Message(msgStat, "%8u total brush sides", brush_state.total_brush_sides); Message(msgStat, "%8u total brush sides", brush_state.total_brush_sides);
@ -364,7 +413,7 @@ ProcessEntity(mapentity_t *entity, const int hullnum)
if (options.target_game->id == GAME_QUAKE_II) { if (options.target_game->id == GAME_QUAKE_II) {
Message(msgProgress, "Calculating Brush List"); Message(msgProgress, "Calculating Brush List");
ExportBrushList(entity, nodes); ExportBrushList(entity, nodes, brush_offset);
} }
ExportDrawNodes(entity, nodes, firstface); ExportDrawNodes(entity, nodes, firstface);