Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a202151
feat: IW3 `.d3dbsp` dumper
michaeloliverx Jun 8, 2026
e6dbd17
wip: checkpoint progress on bsp loading
michaeloliverx Jun 9, 2026
e6b1425
fix: remove linker consumed map entities from entityString
michaeloliverx Jun 9, 2026
d5e045c
fix: load d3dbsp primary lights
michaeloliverx Jun 9, 2026
e16fe29
feat: load d3dbsp dynamic model entities
michaeloliverx Jun 9, 2026
89cce69
fix: preserve d3dbsp leaf records from OAT-built fastfiles
michaeloliverx Jun 9, 2026
5ed889b
fix(iw3): recover d3dbsp leafbrush ranges for OAT-built fastfiles
michaeloliverx Jun 9, 2026
b15f911
fix: improve IW3 d3dbsp clipmap collision parity
michaeloliverx Jun 10, 2026
75133c4
fix: merge d3dbsp lightmaps like linker_pc
michaeloliverx Jun 10, 2026
af6baa6
fix: preserve d3dbsp gndLt only for lit static models
michaeloliverx Jun 10, 2026
5c0f089
fix: write d3dbsp model collision ranges as u32
michaeloliverx Jun 10, 2026
bbe9e37
fix: populate d3dbsp GfxWorld runtime buffers
michaeloliverx Jun 10, 2026
15bdb5d
fix: runtime GfxPortal/cell portal reconstruction from the raw BSP po…
michaeloliverx Jun 10, 2026
c2277c7
fix: populate d3dbsp static model visibility
michaeloliverx Jun 10, 2026
ac5a5a3
fix: assign d3dbsp static model reflection probes
michaeloliverx Jun 10, 2026
fb003f3
fix: match linker d3dbsp gfxworld derived data
michaeloliverx Jun 10, 2026
06421af
fix: improve d3dbsp static model aabb tree generation
michaeloliverx Jun 10, 2026
b43dd03
fix: canonicalize d3dbsp model tri soup starts
michaeloliverx Jun 10, 2026
39d9099
fix: reproduce d3dbsp lightmap falloff overlays
michaeloliverx Jun 10, 2026
b8b9ab9
fix(: normalize placeholder d3dbsp reflection probes
michaeloliverx Jun 10, 2026
a9e43af
fix: match linker bsp unit vector packing
michaeloliverx Jun 11, 2026
1fb183e
fix: match linker draw index ordering for d3dbsp
michaeloliverx Jun 11, 2026
8cb9be0
fix: apply magic portal vertex coords for d3dbsp
michaeloliverx Jun 11, 2026
f331e16
fix: match linker_pc BSP surface material sorting
michaeloliverx Jun 11, 2026
6c9ef1f
fix: match linker static model entity transforms
michaeloliverx Jun 11, 2026
e6c9fb5
fix(iw3): match linker_pc d3dbsp world output
michaeloliverx Jun 11, 2026
2c8185a
chore: clean up `BuildCellHeader`
michaeloliverx Jun 17, 2026
1719034
refactor: add `RawBytes` write helper
michaeloliverx Jun 17, 2026
aee563b
refactor: add `WriteAt` helper
michaeloliverx Jun 17, 2026
ffa649e
refactor: use `std::expected` for entity parsing
michaeloliverx Jun 17, 2026
303fc9e
refactor: use `std::expected` style everywhere for error results
michaeloliverx Jun 17, 2026
0823717
fix: hugely speed up IW3 d3dbsp decal surface detection
michaeloliverx Jun 17, 2026
8a74753
refactor: move outdoor image name to constant
michaeloliverx Jun 17, 2026
3ff6a7b
chore: run clang-format
michaeloliverx Jun 17, 2026
91cc746
fix: dump IW3 dyn_model entities from BSPs
michaeloliverx Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions src/ObjCommon/Game/IW3/Maps/D3DBspCommonIW3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#pragma once

#include <array>
#include <cstddef>
#include <cstdint>

namespace IW3::d3dbsp
{
inline constexpr std::array<char, 4> BSP_MAGIC{'I', 'B', 'S', 'P'};
inline constexpr uint32_t BSP_VERSION = 22u;
inline constexpr uint32_t RUNTIME_MATERIAL_CONTENT_MASK = 0xdffffffbu;
inline constexpr uint32_t RAW_BSP_BRUSH_CONTENT_MARKER = 0x20000000u;

// IW3 v22 stores primary lights as DiskPrimaryLight records. The linker
// converts these to runtime ComPrimaryLight records and derives
// cosHalfFovExpanded while loading.
inline constexpr size_t RAW_PRIMARY_LIGHT_SIZE = 128uz;

// Synthesized from cod4map/linker_pc/Radiant loader usage. IW3 v22 stores
// some render geometry twice: layered data in the low lump range and simple
// data in the later lump range.
enum class LumpType : uint32_t
{
LUMP_MATERIALS = 0,
LUMP_LIGHTMAPS = 1,
LUMP_LIGHTGRID_ENTRIES = 2,
LUMP_LIGHTGRID_COLORS = 3,
LUMP_PLANES = 4,
LUMP_BRUSHSIDES = 5,
LUMP_BRUSHSIDE_EDGE_COUNTS = 6,
LUMP_BRUSHEDGES = 7,
LUMP_BRUSHES = 8,

// Layered world geometry. LUMP_VERTEX_LAYER_DATA is the extra payload
// paired with LUMP_LAYERED_VERTS.
LUMP_LAYERED_TRI_SOUPS = 9,
LUMP_LAYERED_VERTS = 10,
LUMP_LAYERED_INDICES = 11,
LUMP_CULLGROUPS = 12,
LUMP_CULLGROUP_INDICES = 13,

LUMP_OBSOLETE_1 = 14,
LUMP_OBSOLETE_2 = 15,
LUMP_OBSOLETE_3 = 16,
LUMP_OBSOLETE_4 = 17,
LUMP_OBSOLETE_5 = 18,
LUMP_PORTALVERTS = 19,
LUMP_OBSOLETE_6 = 20,
LUMP_UINDS = 21,
LUMP_BRUSHVERTSCOUNTS = 22,
LUMP_BRUSHVERTS = 23,
LUMP_LAYERED_AABBTREES = 24,
LUMP_CELLS = 25,
LUMP_PORTALS = 26,
LUMP_NODES = 27,
LUMP_LEAFS = 28,
LUMP_LEAFBRUSHES = 29,
LUMP_LEAFSURFACES = 30,
LUMP_COLLISIONVERTS = 31,
LUMP_COLLISIONTRIS = 32,
LUMP_COLLISION_EDGE_WALKABLE = 33,
LUMP_COLLISIONBORDERS = 34,
LUMP_COLLISIONPARTITIONS = 35,
LUMP_COLLISIONAABBS = 36,
LUMP_MODELS = 37,
LUMP_VISIBILITY = 38, // Optional PVS data; loaders can fall back when it is absent.
LUMP_ENTITIES = 39, // Raw entity text consumed by linker and MapEnts.
LUMP_PATHCONNECTIONS = 40, // SP path data; absent for MP maps.
LUMP_REFLECTION_PROBES = 41,
LUMP_VERTEX_LAYER_DATA = 42,
LUMP_PRIMARY_LIGHTS = 43,
LUMP_LIGHTGRID_HEADER = 44,
LUMP_LIGHTGRID_ROWS = 45,
LUMP_OBSOLETE_10 = 46,

// Simple/non-layered world geometry. IW3 v22 keeps this alongside the
// layered set so the linker/Radiant can choose the appropriate path.
LUMP_SIMPLE_TRI_SOUPS = 47,
LUMP_SIMPLE_VERTS = 48,
LUMP_SIMPLE_INDICES = 49,
LUMP_SIMPLE_CULLGROUPS = 50,
LUMP_SIMPLE_AABBTREES = 51,
LUMP_LIGHT_REGION_COUNTS = 52,
LUMP_LIGHT_REGION_HULLS = 53,
LUMP_LIGHT_REGION_AXES = 54,
};

// Matches the stock raw BSP loader's TrisType enum. IW3 v22 can contain
// both layered and unlayered render geometry; linker_pc/Radiant select one
// path before loading surfaces, verts, indices, cull groups, and AABB trees.
enum class TrisType : uint32_t
{
TRIS_TYPE_LAYERED = 0,
TRIS_TYPE_SIMPLE = 1,
TRIS_TYPE_COUNT = 2,
};

// IW3 v22 d3dbsp files use this order in the stock tools output.
inline constexpr std::array LUMP_WRITE_ORDER{
LumpType::LUMP_MATERIALS,
LumpType::LUMP_LIGHTMAPS,
LumpType::LUMP_LIGHTGRID_HEADER,
LumpType::LUMP_LIGHTGRID_ROWS,
LumpType::LUMP_LIGHTGRID_ENTRIES,
LumpType::LUMP_LIGHTGRID_COLORS,
LumpType::LUMP_PLANES,
LumpType::LUMP_BRUSHSIDES,
LumpType::LUMP_BRUSHSIDE_EDGE_COUNTS,
LumpType::LUMP_BRUSHEDGES,
LumpType::LUMP_BRUSHES,
LumpType::LUMP_LAYERED_TRI_SOUPS,
LumpType::LUMP_LAYERED_VERTS,
LumpType::LUMP_VERTEX_LAYER_DATA,
LumpType::LUMP_LAYERED_INDICES,
LumpType::LUMP_CULLGROUPS,
LumpType::LUMP_CULLGROUP_INDICES,
LumpType::LUMP_PORTALVERTS,
LumpType::LUMP_LAYERED_AABBTREES,
LumpType::LUMP_CELLS,
LumpType::LUMP_PORTALS,
LumpType::LUMP_NODES,
LumpType::LUMP_LEAFS,
LumpType::LUMP_LEAFBRUSHES,
LumpType::LUMP_LEAFSURFACES,
LumpType::LUMP_COLLISIONVERTS,
LumpType::LUMP_COLLISIONTRIS,
LumpType::LUMP_COLLISION_EDGE_WALKABLE,
LumpType::LUMP_COLLISIONBORDERS,
LumpType::LUMP_COLLISIONPARTITIONS,
LumpType::LUMP_COLLISIONAABBS,
LumpType::LUMP_MODELS,
LumpType::LUMP_VISIBILITY,
LumpType::LUMP_ENTITIES,
LumpType::LUMP_PRIMARY_LIGHTS,
LumpType::LUMP_LIGHT_REGION_COUNTS,
LumpType::LUMP_LIGHT_REGION_HULLS,
LumpType::LUMP_LIGHT_REGION_AXES,
LumpType::LUMP_SIMPLE_TRI_SOUPS,
LumpType::LUMP_SIMPLE_VERTS,
LumpType::LUMP_SIMPLE_INDICES,
LumpType::LUMP_SIMPLE_CULLGROUPS,
LumpType::LUMP_SIMPLE_AABBTREES,
LumpType::LUMP_PATHCONNECTIONS,
LumpType::LUMP_REFLECTION_PROBES,
};
} // namespace IW3::d3dbsp
16 changes: 16 additions & 0 deletions src/ObjLoading/Game/IW3/Maps/D3DBspAssetCreationStateIW3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "D3DBspAssetCreationStateIW3.h"

#include <utility>

using namespace IW3::d3dbsp;

const LoadResult& AssetCreationState::Load(const std::string& assetName, ISearchPath& searchPath)
{
const auto existingEntry = m_cache.find(assetName);
if (existingEntry != m_cache.end())
return existingEntry->second;

auto result = LoadFromSearchPath(assetName, searchPath);
const auto insertResult = m_cache.emplace(assetName, std::move(result));
return insertResult.first->second;
}
19 changes: 19 additions & 0 deletions src/ObjLoading/Game/IW3/Maps/D3DBspAssetCreationStateIW3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "Asset/IZoneAssetCreationState.h"
#include "D3DBspReaderIW3.h"

#include <string>
#include <unordered_map>

namespace IW3::d3dbsp
{
class AssetCreationState final : public IZoneAssetCreationState
{
public:
[[nodiscard]] const LoadResult& Load(const std::string& assetName, ISearchPath& searchPath);

private:
std::unordered_map<std::string, LoadResult> m_cache;
};
} // namespace IW3::d3dbsp
Loading
Loading