2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-12-07 11:47:48 +00:00

chore: mixed code improvements

This commit is contained in:
Jan Laupetin
2025-11-04 22:52:34 +00:00
parent b754be5a68
commit 30e63186f3
21 changed files with 270 additions and 250 deletions

View File

@@ -3,12 +3,13 @@
#include "Game/T6/T6.h" #include "Game/T6/T6.h"
#include "Utils/Logging/Log.h" #include "Utils/Logging/Log.h"
#include <cstdint>
#include <string> #include <string>
#include <vector> #include <vector>
namespace BSP namespace BSP
{ {
enum BSPMaterialType enum class BSPMaterialType : std::uint8_t
{ {
MATERIAL_TYPE_COLOUR, MATERIAL_TYPE_COLOUR,
MATERIAL_TYPE_TEXTURE, MATERIAL_TYPE_TEXTURE,
@@ -33,9 +34,9 @@ namespace BSP
struct BSPSurface struct BSPSurface
{ {
BSPMaterial material; BSPMaterial material;
int triCount; unsigned triCount;
int indexOfFirstVertex; unsigned indexOfFirstVertex;
int indexOfFirstIndex; unsigned indexOfFirstIndex;
}; };
struct BSPWorld struct BSPWorld
@@ -58,7 +59,7 @@ namespace BSP
// These values are hardcoded ingame and will break the map if they are changed // These values are hardcoded ingame and will break the map if they are changed
namespace BSPGameConstants namespace BSPGameConstants
{ {
constexpr unsigned int MAX_COLLISION_VERTS = UINT16_MAX; constexpr unsigned int MAX_COLLISION_VERTS = std::numeric_limits<std::uint16_t>::max();
constexpr size_t MAX_AABB_TREE_CHILDREN = 128; constexpr size_t MAX_AABB_TREE_CHILDREN = 128;

View File

@@ -2,7 +2,7 @@
namespace BSP namespace BSP
{ {
constexpr int MAX_NODE_SIZE = 512; // maximum size a BSP node can be before it becomes a leaf constexpr auto MAX_NODE_SIZE = 512u; // maximum size a BSP node can be before it becomes a leaf
BSPObject::BSPObject( BSPObject::BSPObject(
const float xMin, const float yMin, const float zMin, const float xMax, const float yMax, const float zMax, const int objPartitionIndex) const float xMin, const float yMin, const float zMin, const float xMax, const float yMax, const float zMax, const int objPartitionIndex)
@@ -16,17 +16,17 @@ namespace BSP
partitionIndex = objPartitionIndex; partitionIndex = objPartitionIndex;
} }
void BSPLeaf::addObject(std::shared_ptr<BSPObject> object) void BSPLeaf::AddObject(std::shared_ptr<BSPObject> object)
{ {
objectList.emplace_back(std::move(object)); objectList.emplace_back(std::move(object));
} }
BSPObject* BSPLeaf::getObject(const size_t index) const BSPObject* BSPLeaf::GetObject(const size_t index) const
{ {
return objectList.at(index).get(); return objectList.at(index).get();
} }
size_t BSPLeaf::getObjectCount() const size_t BSPLeaf::GetObjectCount() const
{ {
return objectList.size(); return objectList.size();
} }
@@ -39,17 +39,17 @@ namespace BSP
distance = nodeDistance; distance = nodeDistance;
} }
PlaneSide BSPNode::objectIsInFront(const BSPObject& object) const PlaneSide BSPNode::ObjectIsInFront(const BSPObject& object) const
{ {
float minCoord, maxCoord; float minCoord, maxCoord;
// Select the relevant coordinate based on the plane's axis // Select the relevant coordinate based on the plane's axis
if (axis == AXIS_X) if (axis == PlaneAxis::AXIS_X)
{ {
minCoord = object.min.x; minCoord = object.min.x;
maxCoord = object.max.x; maxCoord = object.max.x;
} }
else if (axis == AXIS_Y) else if (axis == PlaneAxis::AXIS_Y)
{ {
minCoord = object.min.y; minCoord = object.min.y;
maxCoord = object.max.y; maxCoord = object.max.y;
@@ -63,15 +63,15 @@ namespace BSP
// Compare with the plane's distance // Compare with the plane's distance
if (maxCoord < distance) if (maxCoord < distance)
{ {
return SIDE_BACK; // Object is entirely on the negative side return PlaneSide::SIDE_BACK; // Object is entirely on the negative side
} }
else if (minCoord > distance) else if (minCoord > distance)
{ {
return SIDE_FRONT; // Object is entirely on the positive side return PlaneSide::SIDE_FRONT; // Object is entirely on the positive side
} }
else else
{ {
return SIDE_INTERSECTS; return PlaneSide::SIDE_INTERSECTS;
} }
} }
@@ -84,10 +84,11 @@ namespace BSP
max.y = yMax; max.y = yMax;
max.z = zMax; max.z = zMax;
level = treeLevel; level = treeLevel;
splitTree();
SplitTree();
} }
void BSPTree::splitTree() void BSPTree::SplitTree()
{ {
std::unique_ptr<BSPTree> front; std::unique_ptr<BSPTree> front;
std::unique_ptr<BSPTree> back; std::unique_ptr<BSPTree> back;
@@ -101,7 +102,7 @@ namespace BSP
back = std::make_unique<BSPTree>(min.x, min.y, min.z, halfLength, max.y, max.z, level + 1); back = std::make_unique<BSPTree>(min.x, min.y, min.z, halfLength, max.y, max.z, level + 1);
isLeaf = false; isLeaf = false;
node = std::make_unique<BSPNode>(std::move(front), std::move(back), AXIS_X, halfLength); node = std::make_unique<BSPNode>(std::move(front), std::move(back), PlaneAxis::AXIS_X, halfLength);
leaf = nullptr; leaf = nullptr;
} }
else if (max.y - min.y > MAX_NODE_SIZE) else if (max.y - min.y > MAX_NODE_SIZE)
@@ -112,7 +113,7 @@ namespace BSP
back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, halfLength, max.z, level + 1); back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, halfLength, max.z, level + 1);
isLeaf = false; isLeaf = false;
node = std::make_unique<BSPNode>(std::move(front), std::move(back), AXIS_Y, halfLength); node = std::make_unique<BSPNode>(std::move(front), std::move(back), PlaneAxis::AXIS_Y, halfLength);
leaf = nullptr; leaf = nullptr;
} }
else if (max.z - min.z > MAX_NODE_SIZE) else if (max.z - min.z > MAX_NODE_SIZE)
@@ -123,7 +124,7 @@ namespace BSP
back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, max.y, halfLength, level + 1); back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, max.y, halfLength, level + 1);
isLeaf = false; isLeaf = false;
node = std::make_unique<BSPNode>(std::move(front), std::move(back), AXIS_Z, halfLength); node = std::make_unique<BSPNode>(std::move(front), std::move(back), PlaneAxis::AXIS_Z, halfLength);
leaf = nullptr; leaf = nullptr;
} }
else else
@@ -134,27 +135,28 @@ namespace BSP
} }
} }
void BSPTree::addObjectToTree(std::shared_ptr<BSPObject> object) const void BSPTree::AddObjectToTree(std::shared_ptr<BSPObject> object) const
{ {
if (isLeaf) if (isLeaf)
{ {
leaf->addObject(std::move(object)); leaf->AddObject(std::move(object));
} }
else else
{ {
const auto side = node->objectIsInFront(*object); const auto side = node->ObjectIsInFront(*object);
if (side == SIDE_FRONT)
if (side == PlaneSide::SIDE_FRONT)
{ {
node->front->addObjectToTree(std::move(object)); node->front->AddObjectToTree(std::move(object));
} }
else if (side == SIDE_BACK) else if (side == PlaneSide::SIDE_BACK)
{ {
node->back->addObjectToTree(std::move(object)); node->back->AddObjectToTree(std::move(object));
} }
else // intersects else // intersects
{ {
node->front->addObjectToTree(object); node->front->AddObjectToTree(object);
node->back->addObjectToTree(object); node->back->AddObjectToTree(object);
} }
} }
} }

View File

@@ -2,16 +2,18 @@
#include "BSP.h" #include "BSP.h"
#include <cstdint>
namespace BSP namespace BSP
{ {
enum PlaneAxis enum class PlaneAxis : std::uint8_t
{ {
AXIS_X, AXIS_X,
AXIS_Y, AXIS_Y,
AXIS_Z AXIS_Z
}; };
enum PlaneSide enum class PlaneSide : std::uint8_t
{ {
SIDE_FRONT, SIDE_FRONT,
SIDE_BACK, SIDE_BACK,
@@ -21,21 +23,21 @@ namespace BSP
class BSPObject class BSPObject
{ {
public: public:
BSPObject(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex);
T6::vec3_t min; T6::vec3_t min;
T6::vec3_t max; T6::vec3_t max;
int partitionIndex; // index of the partition the object is contained in int partitionIndex; // index of the partition the object is contained in
BSPObject(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex);
}; };
class BSPLeaf class BSPLeaf
{ {
public: public:
std::vector<std::shared_ptr<BSPObject>> objectList; void AddObject(std::shared_ptr<BSPObject> object);
[[nodiscard]] BSPObject* GetObject(size_t index) const;
[[nodiscard]] size_t GetObjectCount() const;
void addObject(std::shared_ptr<BSPObject> object); std::vector<std::shared_ptr<BSPObject>> objectList;
[[nodiscard]] BSPObject* getObject(size_t index) const;
[[nodiscard]] size_t getObjectCount() const;
}; };
class BSPTree; class BSPTree;
@@ -43,19 +45,24 @@ namespace BSP
class BSPNode class BSPNode
{ {
public: public:
BSPNode(std::unique_ptr<BSPTree> frontTree, std::unique_ptr<BSPTree> backTree, PlaneAxis nodeAxis, float nodeDistance);
[[nodiscard]] PlaneSide ObjectIsInFront(const BSPObject& object) const;
std::unique_ptr<BSPTree> front; std::unique_ptr<BSPTree> front;
std::unique_ptr<BSPTree> back; std::unique_ptr<BSPTree> back;
PlaneAxis axis; // axis that the split plane is on PlaneAxis axis; // axis that the split plane is on
float distance; // distance from the origin (0, 0, 0) to the plane float distance; // distance from the origin (0, 0, 0) to the plane
BSPNode(std::unique_ptr<BSPTree> frontTree, std::unique_ptr<BSPTree> backTree, PlaneAxis nodeAxis, float nodeDistance);
[[nodiscard]] PlaneSide objectIsInFront(const BSPObject& object) const;
}; };
class BSPTree class BSPTree
{ {
public: public:
BSPTree(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int treeLevel);
void SplitTree();
void AddObjectToTree(std::shared_ptr<BSPObject> object) const;
bool isLeaf; bool isLeaf;
std::unique_ptr<BSPLeaf> leaf; std::unique_ptr<BSPLeaf> leaf;
std::unique_ptr<BSPNode> node; std::unique_ptr<BSPNode> node;
@@ -63,9 +70,5 @@ namespace BSP
int level; // level in the BSP tree int level; // level in the BSP tree
T6::vec3_t min; T6::vec3_t min;
T6::vec3_t max; T6::vec3_t max;
BSPTree(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int treeLevel);
void splitTree();
void addObjectToTree(std::shared_ptr<BSPObject> object) const;
}; };
} // namespace BSP } // namespace BSP

View File

@@ -2,14 +2,16 @@
#include "BSPUtil.h" #include "BSPUtil.h"
#include <cassert>
#include <format> #include <format>
#include <limits>
#include <ufbx.h> #include <ufbx.h>
using namespace BSP; using namespace BSP;
namespace namespace
{ {
void addFBXMeshToWorld( void AddFBXMeshToWorld(
ufbx_node* node, std::vector<BSPSurface>& surfaceVec, std::vector<BSPVertex>& vertexVec, std::vector<uint16_t>& indexVec, bool& hasTangentSpace) ufbx_node* node, std::vector<BSPSurface>& surfaceVec, std::vector<BSPVertex>& vertexVec, std::vector<uint16_t>& indexVec, bool& hasTangentSpace)
{ {
ufbx_mesh* mesh = node->mesh; ufbx_mesh* mesh = node->mesh;
@@ -17,7 +19,7 @@ namespace
assert(node->attrib_type == UFBX_ELEMENT_MESH); assert(node->attrib_type == UFBX_ELEMENT_MESH);
if (mesh->instances.count != 1) if (mesh->instances.count != 1)
con::warn("mesh {} has {} instances, only the 1st instace will be used.", node->name.data, mesh->instances.count); con::warn("mesh {} has {} instances, only the 1st instance will be used.", node->name.data, mesh->instances.count);
if (mesh->num_triangles == 0) if (mesh->num_triangles == 0)
{ {
@@ -33,9 +35,9 @@ namespace
for (size_t k = 0; k < mesh->num_indices; k++) for (size_t k = 0; k < mesh->num_indices; k++)
{ {
if (mesh->vertex_indices[k] > UINT16_MAX) if (mesh->vertex_indices[k] > std::numeric_limits<std::uint16_t>::max())
{ {
con::warn("ignoring mesh {}, it has more than {} indices.", node->name.data, UINT16_MAX); con::warn("ignoring mesh {}, it has more than {} indices.", node->name.data, std::numeric_limits<std::uint16_t>::max());
return; return;
} }
} }
@@ -61,18 +63,18 @@ namespace
BSPSurface surface; BSPSurface surface;
size_t partTriangleNum = meshPart.num_triangles; size_t partTriangleNum = meshPart.num_triangles;
surface.triCount = static_cast<int>(partTriangleNum); surface.triCount = static_cast<unsigned>(partTriangleNum);
surface.indexOfFirstVertex = static_cast<int>(vertexVec.size()); surface.indexOfFirstVertex = static_cast<unsigned>(vertexVec.size());
surface.indexOfFirstIndex = static_cast<int>(indexVec.size()); surface.indexOfFirstIndex = static_cast<unsigned>(indexVec.size());
if (mesh->materials.count == 0) if (mesh->materials.count == 0)
{ {
surface.material.materialType = MATERIAL_TYPE_EMPTY; surface.material.materialType = BSPMaterialType::MATERIAL_TYPE_EMPTY;
surface.material.materialName = ""; surface.material.materialName = "";
} }
else else
{ {
surface.material.materialType = MATERIAL_TYPE_TEXTURE; surface.material.materialType = BSPMaterialType::MATERIAL_TYPE_TEXTURE;
surface.material.materialName = mesh->materials.data[meshPart.index]->name.data; surface.material.materialName = mesh->materials.data[meshPart.index]->name.data;
} }
@@ -84,9 +86,9 @@ namespace
ufbx_face* face = &mesh->faces.data[faceIndex]; ufbx_face* face = &mesh->faces.data[faceIndex];
// Triangulate the face into the indices vector // Triangulate the face into the indices vector
uint32_t triangluatedTriCount = ufbx_triangulate_face(tempIndices.data(), tempIndices.size(), mesh, *face); uint32_t triangulatedTriCount = ufbx_triangulate_face(tempIndices.data(), tempIndices.size(), mesh, *face);
for (uint32_t idxOfIndex = 0; idxOfIndex < triangluatedTriCount * 3; idxOfIndex++) for (uint32_t idxOfIndex = 0; idxOfIndex < triangulatedTriCount * 3; idxOfIndex++)
{ {
BSPVertex vertex; BSPVertex vertex;
uint32_t index = tempIndices[idxOfIndex]; uint32_t index = tempIndices[idxOfIndex];
@@ -98,7 +100,8 @@ namespace
blenderCoords.z = static_cast<float>(transformedPos.z); blenderCoords.z = static_cast<float>(transformedPos.z);
vertex.pos = ConvertToBO2Coords(blenderCoords); vertex.pos = ConvertToBO2Coords(blenderCoords);
if (surface.material.materialType == MATERIAL_TYPE_TEXTURE || surface.material.materialType == MATERIAL_TYPE_EMPTY) if (surface.material.materialType == BSPMaterialType::MATERIAL_TYPE_TEXTURE
|| surface.material.materialType == BSPMaterialType::MATERIAL_TYPE_EMPTY)
{ {
vertex.color.x = 1.0f; vertex.color.x = 1.0f;
vertex.color.y = 1.0f; vertex.color.y = 1.0f;
@@ -171,7 +174,7 @@ namespace
} }
} }
void loadWorldData(const ufbx_scene& scene, BSPData& bsp, const bool isGfxData) void LoadWorldData(const ufbx_scene& scene, BSPData& bsp, const bool isGfxData)
{ {
bool hasTangentSpace = true; bool hasTangentSpace = true;
for (ufbx_node* node : scene.nodes) for (ufbx_node* node : scene.nodes)
@@ -179,9 +182,9 @@ namespace
if (node->attrib_type == UFBX_ELEMENT_MESH) if (node->attrib_type == UFBX_ELEMENT_MESH)
{ {
if (isGfxData) if (isGfxData)
addFBXMeshToWorld(node, bsp.gfxWorld.surfaces, bsp.gfxWorld.vertices, bsp.gfxWorld.indices, hasTangentSpace); AddFBXMeshToWorld(node, bsp.gfxWorld.surfaces, bsp.gfxWorld.vertices, bsp.gfxWorld.indices, hasTangentSpace);
else else
addFBXMeshToWorld(node, bsp.colWorld.surfaces, bsp.colWorld.vertices, bsp.colWorld.indices, hasTangentSpace); AddFBXMeshToWorld(node, bsp.colWorld.surfaces, bsp.colWorld.vertices, bsp.colWorld.indices, hasTangentSpace);
} }
else else
{ {
@@ -196,19 +199,18 @@ namespace
namespace BSP namespace BSP
{ {
std::unique_ptr<BSPData> createBSPData(const std::string& mapName, ISearchPath& searchPath) std::unique_ptr<BSPData> CreateBSPData(const std::string& mapName, ISearchPath& searchPath)
{ {
std::string gfxFbxFileName = "map_gfx.fbx"; const auto gfxFbxPath = GetFileNameForBSPAsset("map_gfx.fbx");
std::string gfxFbxPath = GetFileNameForBSPAsset(gfxFbxFileName); const auto gfxFile = searchPath.Open(gfxFbxPath);
auto gfxFile = searchPath.Open(gfxFbxPath);
if (!gfxFile.IsOpen()) if (!gfxFile.IsOpen())
{ {
con::error("Failed to open map gfx fbx file: {}", gfxFbxPath); con::error("Failed to open map gfx fbx file: {}", gfxFbxPath);
return nullptr; return nullptr;
} }
std::unique_ptr<char> gfxMapData(new char[static_cast<size_t>(gfxFile.m_length)]); std::vector<char> gfxMapData(static_cast<size_t>(gfxFile.m_length));
gfxFile.m_stream->read(gfxMapData.get(), gfxFile.m_length); gfxFile.m_stream->read(gfxMapData.data(), gfxFile.m_length);
if (gfxFile.m_stream->gcount() != gfxFile.m_length) if (gfxFile.m_stream->gcount() != gfxFile.m_length)
{ {
con::error("Read error of gfx fbx file: {}", gfxFbxPath); con::error("Read error of gfx fbx file: {}", gfxFbxPath);
@@ -220,7 +222,7 @@ namespace BSP
optsGfx.target_axes = ufbx_axes_right_handed_y_up; optsGfx.target_axes = ufbx_axes_right_handed_y_up;
optsGfx.generate_missing_normals = true; optsGfx.generate_missing_normals = true;
optsGfx.allow_missing_vertex_position = false; optsGfx.allow_missing_vertex_position = false;
ufbx_scene* gfxScene = ufbx_load_memory(gfxMapData.get(), static_cast<size_t>(gfxFile.m_length), &optsGfx, &errorGfx); ufbx_scene* gfxScene = ufbx_load_memory(gfxMapData.data(), static_cast<size_t>(gfxFile.m_length), &optsGfx, &errorGfx);
if (!gfxScene) if (!gfxScene)
{ {
con::error("Failed to load map gfx fbx file: {}", errorGfx.description.data); con::error("Failed to load map gfx fbx file: {}", errorGfx.description.data);
@@ -228,19 +230,18 @@ namespace BSP
} }
ufbx_scene* colScene; ufbx_scene* colScene;
std::string colFbxFileName = "map_col.fbx"; const auto colFbxPath = GetFileNameForBSPAsset("map_col.fbx");
const auto colFbxPath = GetFileNameForBSPAsset(colFbxFileName);
const auto colFile = searchPath.Open(colFbxPath); const auto colFile = searchPath.Open(colFbxPath);
if (!colFile.IsOpen()) if (!colFile.IsOpen())
{ {
con::warn("Failed to open map collison fbx file: {}. map gfx will be used for collision instead.", colFbxPath); con::warn("Failed to open map collision fbx file: {}. map gfx will be used for collision instead.", colFbxPath);
colScene = gfxScene; colScene = gfxScene;
} }
else else
{ {
std::unique_ptr<char> colMapData(new char[static_cast<size_t>(colFile.m_length)]); std::vector<char> colMapData(static_cast<size_t>(colFile.m_length));
colFile.m_stream->seekg(0); colFile.m_stream->seekg(0);
colFile.m_stream->read(colMapData.get(), colFile.m_length); colFile.m_stream->read(colMapData.data(), colFile.m_length);
if (colFile.m_stream->gcount() != colFile.m_length) if (colFile.m_stream->gcount() != colFile.m_length)
{ {
con::error("Read error of collision fbx file: {}", colFbxPath); con::error("Read error of collision fbx file: {}", colFbxPath);
@@ -252,7 +253,7 @@ namespace BSP
optsCol.target_axes = ufbx_axes_right_handed_y_up; optsCol.target_axes = ufbx_axes_right_handed_y_up;
optsCol.generate_missing_normals = true; optsCol.generate_missing_normals = true;
optsCol.allow_missing_vertex_position = false; optsCol.allow_missing_vertex_position = false;
colScene = ufbx_load_memory(colMapData.get(), static_cast<size_t>(colFile.m_length), &optsCol, &errorCol); colScene = ufbx_load_memory(colMapData.data(), static_cast<size_t>(colFile.m_length), &optsCol, &errorCol);
if (!colScene) if (!colScene)
{ {
con::error("Failed to load map collision fbx file: {}", errorCol.description.data); con::error("Failed to load map collision fbx file: {}", errorCol.description.data);
@@ -265,8 +266,8 @@ namespace BSP
bsp->name = mapName; bsp->name = mapName;
bsp->bspName = std::format("maps/mp/{}.d3dbsp", mapName); bsp->bspName = std::format("maps/mp/{}.d3dbsp", mapName);
loadWorldData(*gfxScene, *bsp, true); LoadWorldData(*gfxScene, *bsp, true);
loadWorldData(*colScene, *bsp, false); LoadWorldData(*colScene, *bsp, false);
ufbx_free_scene(gfxScene); ufbx_free_scene(gfxScene);
if (gfxScene != colScene) if (gfxScene != colScene)

View File

@@ -5,5 +5,5 @@
namespace BSP namespace BSP
{ {
std::unique_ptr<BSPData> createBSPData(const std::string& mapName, ISearchPath& searchPath); std::unique_ptr<BSPData> CreateBSPData(const std::string& mapName, ISearchPath& searchPath);
}; // namespace BSP }; // namespace BSP

View File

@@ -92,12 +92,12 @@ namespace BSP
const auto yRadians = angles->y * conversionValue; const auto yRadians = angles->y * conversionValue;
const auto zRadians = angles->z * conversionValue; const auto zRadians = angles->z * conversionValue;
const auto cosX = cos(xRadians); const auto cosX = std::cos(xRadians);
const auto sinX = sin(xRadians); const auto sinX = std::sin(xRadians);
const auto cosY = cos(yRadians); const auto cosY = std::cos(yRadians);
const auto sinY = sin(yRadians); const auto sinY = std::sin(yRadians);
const auto cosZ = cos(zRadians); const auto cosZ = std::cos(zRadians);
const auto sinZ = sin(zRadians); const auto sinZ = std::sin(zRadians);
axis[0].x = cosX * cosY; axis[0].x = cosX * cosY;
axis[0].y = cosX * sinY; axis[0].y = cosX * sinY;

View File

@@ -13,7 +13,7 @@ using namespace T6;
namespace BSP namespace BSP
{ {
void BSPLinker::addEmptyFootstepTableAsset(const std::string& assetName) const void BSPLinker::AddEmptyFootstepTableAsset(const std::string& assetName) const
{ {
if (assetName.empty()) if (assetName.empty())
return; return;
@@ -25,30 +25,30 @@ namespace BSP
m_context.AddAsset<AssetFootstepTable>(assetName, footstepTable); m_context.AddAsset<AssetFootstepTable>(assetName, footstepTable);
} }
bool BSPLinker::addDefaultRequiredAssets(const BSPData& bsp) const bool BSPLinker::AddDefaultRequiredAssets(const BSPData& bsp) const
{ {
if (m_context.LoadDependency<AssetScript>(std::format("maps/mp/{}.gsc", bsp.name)) == nullptr) if (!m_context.LoadDependency<AssetScript>(std::format("maps/mp/{}.gsc", bsp.name)))
return false; return false;
if (m_context.LoadDependency<AssetScript>(std::format("maps/mp/{}_amb.gsc", bsp.name)) == nullptr) if (!m_context.LoadDependency<AssetScript>(std::format("maps/mp/{}_amb.gsc", bsp.name)))
return false; return false;
if (m_context.LoadDependency<AssetScript>(std::format("maps/mp/{}_fx.gsc", bsp.name)) == nullptr) if (!m_context.LoadDependency<AssetScript>(std::format("maps/mp/{}_fx.gsc", bsp.name)))
return false; return false;
if (m_context.LoadDependency<AssetScript>(std::format("clientscripts/mp/{}.csc", bsp.name)) == nullptr) if (!m_context.LoadDependency<AssetScript>(std::format("clientscripts/mp/{}.csc", bsp.name)))
return false; return false;
if (m_context.LoadDependency<AssetScript>(std::format("clientscripts/mp/{}_amb.csc", bsp.name)) == nullptr) if (!m_context.LoadDependency<AssetScript>(std::format("clientscripts/mp/{}_amb.csc", bsp.name)))
return false; return false;
if (m_context.LoadDependency<AssetScript>(std::format("clientscripts/mp/{}_fx.csc", bsp.name)) == nullptr) if (!m_context.LoadDependency<AssetScript>(std::format("clientscripts/mp/{}_fx.csc", bsp.name)))
return false; return false;
addEmptyFootstepTableAsset("default_1st_person"); AddEmptyFootstepTableAsset("default_1st_person");
addEmptyFootstepTableAsset("default_3rd_person"); AddEmptyFootstepTableAsset("default_3rd_person");
addEmptyFootstepTableAsset("default_1st_person_quiet"); AddEmptyFootstepTableAsset("default_1st_person_quiet");
addEmptyFootstepTableAsset("default_3rd_person_quiet"); AddEmptyFootstepTableAsset("default_3rd_person_quiet");
addEmptyFootstepTableAsset("default_3rd_person_loud"); AddEmptyFootstepTableAsset("default_3rd_person_loud");
addEmptyFootstepTableAsset("default_ai"); AddEmptyFootstepTableAsset("default_ai");
if (m_context.LoadDependency<AssetRawFile>("animtrees/fxanim_props.atr") == nullptr) if (!m_context.LoadDependency<AssetRawFile>("animtrees/fxanim_props.atr"))
return false; return false;
return true; return true;
@@ -61,9 +61,9 @@ namespace BSP
{ {
} }
bool BSPLinker::linkBSP(const BSPData& bsp) const bool BSPLinker::LinkBSP(const BSPData& bsp) const
{ {
if (!addDefaultRequiredAssets(bsp)) if (!AddDefaultRequiredAssets(bsp))
return false; return false;
ComWorldLinker comWorldLinker(m_memory, m_search_path, m_context); ComWorldLinker comWorldLinker(m_memory, m_search_path, m_context);
@@ -73,32 +73,32 @@ namespace BSP
MapEntsLinker mapEntsLinker(m_memory, m_search_path, m_context); MapEntsLinker mapEntsLinker(m_memory, m_search_path, m_context);
SkinnedVertsLinker skinnedVertsLinker(m_memory, m_search_path, m_context); SkinnedVertsLinker skinnedVertsLinker(m_memory, m_search_path, m_context);
auto* comWorld = comWorldLinker.linkComWorld(bsp); auto* comWorld = comWorldLinker.LinkComWorld(bsp);
if (comWorld == nullptr) if (comWorld == nullptr)
return false; return false;
m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld); m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld);
auto* mapEnts = mapEntsLinker.linkMapEnts(bsp); auto* mapEnts = mapEntsLinker.LinkMapEnts(bsp);
if (mapEnts == nullptr) if (mapEnts == nullptr)
return false; return false;
m_context.AddAsset<AssetMapEnts>(mapEnts->name, mapEnts); m_context.AddAsset<AssetMapEnts>(mapEnts->name, mapEnts);
auto* gameWorldMp = gameWorldMpLinker.linkGameWorldMp(bsp); auto* gameWorldMp = gameWorldMpLinker.LinkGameWorldMp(bsp);
if (gameWorldMp == nullptr) if (gameWorldMp == nullptr)
return false; return false;
m_context.AddAsset<AssetGameWorldMp>(gameWorldMp->name, gameWorldMp); m_context.AddAsset<AssetGameWorldMp>(gameWorldMp->name, gameWorldMp);
auto* skinnedVerts = skinnedVertsLinker.linkSkinnedVerts(bsp); auto* skinnedVerts = skinnedVertsLinker.LinkSkinnedVerts(bsp);
if (skinnedVerts == nullptr) if (skinnedVerts == nullptr)
return false; return false;
m_context.AddAsset<AssetSkinnedVerts>(skinnedVerts->name, skinnedVerts); m_context.AddAsset<AssetSkinnedVerts>(skinnedVerts->name, skinnedVerts);
auto* gfxWorld = gfxWorldLinker.linkGfxWorld(bsp); // requires mapents asset auto* gfxWorld = gfxWorldLinker.LinkGfxWorld(bsp); // requires mapents asset
if (gfxWorld == nullptr) if (gfxWorld == nullptr)
return false; return false;
m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld); m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld);
auto* clipMap = clipMapLinker.linkClipMap(bsp); // requires gfxworld and mapents asset auto* clipMap = clipMapLinker.LinkClipMap(bsp); // requires gfxworld and mapents asset
if (clipMap == nullptr) if (clipMap == nullptr)
return false; return false;
m_context.AddAsset<AssetClipMap>(clipMap->name, clipMap); m_context.AddAsset<AssetClipMap>(clipMap->name, clipMap);

View File

@@ -12,11 +12,11 @@ namespace BSP
public: public:
BSPLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); BSPLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] bool linkBSP(const BSPData& bsp) const; [[nodiscard]] bool LinkBSP(const BSPData& bsp) const;
private: private:
void addEmptyFootstepTableAsset(const std::string& assetName) const; void AddEmptyFootstepTableAsset(const std::string& assetName) const;
[[nodiscard]] bool addDefaultRequiredAssets(const BSPData& bsp) const; [[nodiscard]] bool AddDefaultRequiredAssets(const BSPData& bsp) const;
MemoryManager& m_memory; MemoryManager& m_memory;
ISearchPath& m_search_path; ISearchPath& m_search_path;

View File

@@ -2,6 +2,7 @@
#include "Game/T6/BSP/BSPUtil.h" #include "Game/T6/BSP/BSPUtil.h"
#include <algorithm>
#include <cassert> #include <cassert>
using namespace T6; using namespace T6;
@@ -15,9 +16,9 @@ namespace BSP
{ {
} }
void ClipMapLinker::loadDynEnts(clipMap_t& clipMap) const void ClipMapLinker::LoadDynEnts(clipMap_t& clipMap) const
{ {
int dynEntCount = 0; uint16_t dynEntCount = 0;
clipMap.originalDynEntCount = dynEntCount; clipMap.originalDynEntCount = dynEntCount;
clipMap.dynEntCount[0] = clipMap.originalDynEntCount + 256; // the game allocs 256 empty dynents, as they may be used ingame clipMap.dynEntCount[0] = clipMap.originalDynEntCount + 256; // the game allocs 256 empty dynents, as they may be used ingame
clipMap.dynEntCount[1] = 0; clipMap.dynEntCount[1] = 0;
@@ -42,7 +43,7 @@ namespace BSP
clipMap.dynEntDefList[1] = nullptr; clipMap.dynEntDefList[1] = nullptr;
} }
void ClipMapLinker::loadVisibility(clipMap_t& clipMap) const void ClipMapLinker::LoadVisibility(clipMap_t& clipMap) const
{ {
// Only use one visbility cluster for the entire map // Only use one visbility cluster for the entire map
clipMap.numClusters = 1; clipMap.numClusters = 1;
@@ -53,7 +54,7 @@ namespace BSP
memset(clipMap.visibility, 0xFF, clipMap.clusterBytes); memset(clipMap.visibility, 0xFF, clipMap.clusterBytes);
} }
void ClipMapLinker::loadBoxData(clipMap_t& clipMap) const void ClipMapLinker::LoadBoxData(clipMap_t& clipMap) const
{ {
// box_model and box_brush are what are used by game traces as "temporary" collision when // box_model and box_brush are what are used by game traces as "temporary" collision when
// no brush or model is specified to do the trace with. // no brush or model is specified to do the trace with.
@@ -114,7 +115,7 @@ namespace BSP
clipMap.box_brush->verts = nullptr; clipMap.box_brush->verts = nullptr;
} }
void ClipMapLinker::loadRopesAndConstraints(clipMap_t& clipMap) const void ClipMapLinker::LoadRopesAndConstraints(clipMap_t& clipMap) const
{ {
clipMap.num_constraints = 0; // max 511 clipMap.num_constraints = 0; // max 511
clipMap.constraints = nullptr; clipMap.constraints = nullptr;
@@ -124,7 +125,7 @@ namespace BSP
clipMap.ropes = m_memory.Alloc<rope_t>(clipMap.max_ropes); clipMap.ropes = m_memory.Alloc<rope_t>(clipMap.max_ropes);
} }
void ClipMapLinker::loadSubModelCollision(clipMap_t& clipMap, const BSPData& bsp) const void ClipMapLinker::LoadSubModelCollision(clipMap_t& clipMap, const BSPData& bsp) const
{ {
// Submodels are used for the world and map ent collision (triggers, bomb zones, etc) // Submodels are used for the world and map ent collision (triggers, bomb zones, etc)
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(bsp.bspName); auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(bsp.bspName);
@@ -163,7 +164,7 @@ namespace BSP
clipMap.cmodels[0].info = nullptr; // always set to 0 clipMap.cmodels[0].info = nullptr; // always set to 0
} }
void ClipMapLinker::loadXModelCollision(clipMap_t& clipMap) const void ClipMapLinker::LoadXModelCollision(clipMap_t& clipMap) const
{ {
// Right now XModels aren't supported // Right now XModels aren't supported
clipMap.numStaticModels = 0; clipMap.numStaticModels = 0;
@@ -213,11 +214,11 @@ namespace BSP
*/ */
} }
void ClipMapLinker::addAABBTreeFromLeaf(clipMap_t& clipMap, const BSPTree& tree, size_t& outParentCount, size_t& outParentStartIndex) void ClipMapLinker::AddAABBTreeFromLeaf(clipMap_t& clipMap, const BSPTree& tree, size_t& outParentCount, size_t& outParentStartIndex)
{ {
assert(tree.isLeaf); assert(tree.isLeaf);
size_t leafObjectCount = tree.leaf->getObjectCount(); size_t leafObjectCount = tree.leaf->GetObjectCount();
assert(leafObjectCount > 0); assert(leafObjectCount > 0);
highestLeafObjectCount = std::max(leafObjectCount, highestLeafObjectCount); highestLeafObjectCount = std::max(leafObjectCount, highestLeafObjectCount);
@@ -246,7 +247,7 @@ namespace BSP
vec3_t parentMaxs; vec3_t parentMaxs;
for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++) for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++)
{ {
int partitionIndex = tree.leaf->getObject(addedObjectCount + objectIdx)->partitionIndex; int partitionIndex = tree.leaf->GetObject(addedObjectCount + objectIdx)->partitionIndex;
CollisionPartition* partition = &clipMap.partitions[partitionIndex]; CollisionPartition* partition = &clipMap.partitions[partitionIndex];
for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++) for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++)
{ {
@@ -276,7 +277,7 @@ namespace BSP
// add child AABBs // add child AABBs
for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++) for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++)
{ {
int partitionIndex = tree.leaf->getObject(addedObjectCount + objectIdx)->partitionIndex; int partitionIndex = tree.leaf->GetObject(addedObjectCount + objectIdx)->partitionIndex;
CollisionPartition* partition = &clipMap.partitions[partitionIndex]; CollisionPartition* partition = &clipMap.partitions[partitionIndex];
vec3_t childMins; vec3_t childMins;
vec3_t childMaxs; vec3_t childMaxs;
@@ -295,7 +296,7 @@ namespace BSP
UpdateAABBWithPoint(vert, childMins, childMaxs); UpdateAABBWithPoint(vert, childMins, childMaxs);
} }
CollisionAabbTree childAABBTree; CollisionAabbTree childAABBTree{};
childAABBTree.materialIndex = 0; // always use the first material childAABBTree.materialIndex = 0; // always use the first material
childAABBTree.childCount = 0; childAABBTree.childCount = 0;
childAABBTree.u.partitionIndex = partitionIndex; childAABBTree.u.partitionIndex = partitionIndex;
@@ -311,15 +312,21 @@ namespace BSP
outParentStartIndex = parentAABBArrayIndex; outParentStartIndex = parentAABBArrayIndex;
} }
constexpr vec3_t normalX = {1.0f, 0.0f, 0.0f}; constexpr vec3_t normalX = {
constexpr vec3_t normalY = {0.0f, 1.0f, 0.0f}; {.x = 1.0f, .y = 0.0f, .z = 0.0f}
constexpr vec3_t normalZ = {0.0f, 0.0f, 1.0f}; };
constexpr vec3_t normalY = {
{.x = 0.0f, .y = 1.0f, .z = 0.0f}
};
constexpr vec3_t normalZ = {
{.x = 0.0f, .y = 0.0f, .z = 1.0f}
};
// returns the index of the node/leaf parsed by the function // returns the index of the node/leaf parsed by the function
// Nodes are indexed by their index in the node array // Nodes are indexed by their index in the node array
// Leafs are indexed by (-1 - <leaf index>) // Leafs are indexed by (-1 - <leaf index>)
// See https://developer.valvesoftware.com/wiki/BSP_(Source) // See https://developer.valvesoftware.com/wiki/BSP_(Source)
int16_t ClipMapLinker::loadBSPNode(clipMap_t& clipMap, const BSPTree& tree) int16_t ClipMapLinker::LoadBSPNode(clipMap_t& clipMap, const BSPTree& tree)
{ {
if (tree.isLeaf) if (tree.isLeaf)
{ {
@@ -338,11 +345,11 @@ namespace BSP
leaf.maxs.z = 0.0f; leaf.maxs.z = 0.0f;
leaf.leafBrushNode = 0; leaf.leafBrushNode = 0;
if (tree.leaf->getObjectCount() > 0) if (tree.leaf->GetObjectCount() > 0)
{ {
size_t parentCount = 0; size_t parentCount = 0;
size_t parentStartIndex = 0; size_t parentStartIndex = 0;
addAABBTreeFromLeaf(clipMap, tree, parentCount, parentStartIndex); AddAABBTreeFromLeaf(clipMap, tree, parentCount, parentStartIndex);
leaf.collAabbCount = static_cast<uint16_t>(parentCount); leaf.collAabbCount = static_cast<uint16_t>(parentCount);
leaf.firstCollAabbIndex = static_cast<uint16_t>(parentStartIndex); leaf.firstCollAabbIndex = static_cast<uint16_t>(parentStartIndex);
} }
@@ -361,18 +368,20 @@ namespace BSP
{ {
cplane_s plane; cplane_s plane;
plane.dist = tree.node->distance; plane.dist = tree.node->distance;
if (tree.node->axis == AXIS_X) if (tree.node->axis == PlaneAxis::AXIS_X)
{ {
plane.normal = normalX; plane.normal = normalX;
plane.type = 0; plane.type = 0;
} }
else if (tree.node->axis == AXIS_Y) else if (tree.node->axis == PlaneAxis::AXIS_Y)
{ {
plane.normal = normalY; plane.normal = normalY;
plane.type = 1; plane.type = 1;
} }
else // tree->node->axis == AXIS_Z else
{ {
assert(tree.node->axis == PlaneAxis::AXIS_Z);
plane.normal = normalZ; plane.normal = normalZ;
plane.type = 2; plane.type = 2;
} }
@@ -390,14 +399,14 @@ namespace BSP
planeVec.emplace_back(plane); planeVec.emplace_back(plane);
// The recursion of adding the children through loadBSPNode means the parent node needs to be added before the chilren are loaded // The recursion of adding the children through LoadBSPNode means the parent node needs to be added before the children are loaded
size_t nodeIndex = nodeVec.size(); size_t nodeIndex = nodeVec.size();
nodeVec.emplace_back(); nodeVec.emplace_back();
cNode_t node; cNode_t node;
node.plane = nullptr; // initalised after the BSP tree has been loaded node.plane = nullptr; // initialised after the BSP tree has been loaded
node.children[0] = loadBSPNode(clipMap, *tree.node->front); node.children[0] = LoadBSPNode(clipMap, *tree.node->front);
node.children[1] = loadBSPNode(clipMap, *tree.node->back); node.children[1] = LoadBSPNode(clipMap, *tree.node->back);
nodeVec.at(nodeIndex) = node; nodeVec.at(nodeIndex) = node;
@@ -405,14 +414,14 @@ namespace BSP
} }
} }
void ClipMapLinker::loadBSPTree(clipMap_t& clipMap, const BSPData& bsp) void ClipMapLinker::LoadBSPTree(clipMap_t& clipMap, const BSPData& bsp)
{ {
vec3_t worldMins; vec3_t worldMins;
vec3_t worldMaxs; vec3_t worldMaxs;
for (unsigned int vertIdx = 0; vertIdx < clipMap.vertCount; vertIdx++) for (unsigned int vertIdx = 0; vertIdx < clipMap.vertCount; vertIdx++)
{ {
vec3_t vertex = clipMap.verts[vertIdx]; vec3_t vertex = clipMap.verts[vertIdx];
// initalise AABB with the first vertex // initialise AABB with the first vertex
if (vertIdx == 0) if (vertIdx == 0)
{ {
worldMins = vertex; worldMins = vertex;
@@ -442,11 +451,11 @@ namespace BSP
} }
auto currObject = auto currObject =
std::make_shared<BSPObject>(partitionMins.x, partitionMins.y, partitionMins.z, partitionMaxs.x, partitionMaxs.y, partitionMaxs.z, partitionIdx); std::make_shared<BSPObject>(partitionMins.x, partitionMins.y, partitionMins.z, partitionMaxs.x, partitionMaxs.y, partitionMaxs.z, partitionIdx);
tree->addObjectToTree(std::move(currObject)); tree->AddObjectToTree(std::move(currObject));
} }
// load planes, nodes, leafs, and AABB trees // load planes, nodes, leafs, and AABB trees
loadBSPNode(clipMap, *tree); LoadBSPNode(clipMap, *tree);
clipMap.info.planeCount = static_cast<int>(planeVec.size()); clipMap.info.planeCount = static_cast<int>(planeVec.size());
clipMap.info.planes = m_memory.Alloc<cplane_s>(planeVec.size()); clipMap.info.planes = m_memory.Alloc<cplane_s>(planeVec.size());
@@ -471,7 +480,7 @@ namespace BSP
con::info("Highest leaf object count: {}", highestLeafObjectCount); con::info("Highest leaf object count: {}", highestLeafObjectCount);
} }
bool ClipMapLinker::loadPartitions(clipMap_t& clipMap, const BSPData& bsp) const bool ClipMapLinker::LoadPartitions(clipMap_t& clipMap, const BSPData& bsp) const
{ {
// due to tris using uint16_t as the type for indexing the vert array, // due to tris using uint16_t as the type for indexing the vert array,
// any vertex count over the uint16_t max means the vertices above the uint16_t max can't be indexed // any vertex count over the uint16_t max means the vertices above the uint16_t max can't be indexed
@@ -493,9 +502,9 @@ namespace BSP
{ {
const auto indexOfFirstIndex = surface.indexOfFirstIndex; const auto indexOfFirstIndex = surface.indexOfFirstIndex;
const auto indexOfFirstVertex = surface.indexOfFirstVertex; const auto indexOfFirstVertex = surface.indexOfFirstVertex;
for (auto indexIdx = 0; indexIdx < surface.triCount * 3; indexIdx++) for (auto indexIdx = 0u; indexIdx < surface.triCount * 3; indexIdx++)
{ {
auto triIndex = bsp.colWorld.indices[indexOfFirstIndex + indexIdx] + indexOfFirstVertex; auto triIndex = static_cast<uint16_t>(bsp.colWorld.indices[indexOfFirstIndex + indexIdx] + indexOfFirstVertex);
triIndexVec.emplace_back(triIndex); triIndexVec.emplace_back(triIndex);
} }
} }
@@ -513,12 +522,11 @@ namespace BSP
// one for each surface causes physics bugs, as the entire bounding box is considered solid instead of the surface itself (for some reason). // one for each surface causes physics bugs, as the entire bounding box is considered solid instead of the surface itself (for some reason).
// so a partition is made for each triangle which removes the physics bugs but likely makes the game run slower // so a partition is made for each triangle which removes the physics bugs but likely makes the game run slower
const auto indexOfFirstTri = surface.indexOfFirstIndex / 3; const auto indexOfFirstTri = surface.indexOfFirstIndex / 3;
const auto indexOfFirstVertex = surface.indexOfFirstVertex; for (auto triIdx = 0u; triIdx < surface.triCount; triIdx++)
for (auto triIdx = 0; triIdx < surface.triCount; triIdx++)
{ {
CollisionPartition partition; CollisionPartition partition;
partition.triCount = 1; partition.triCount = 1;
partition.firstTri = indexOfFirstTri + triIdx; partition.firstTri = static_cast<int>(indexOfFirstTri + triIdx);
partition.nuinds = 3; partition.nuinds = 3;
partition.fuind = static_cast<int>(uniqueIndicesVec.size()); partition.fuind = static_cast<int>(uniqueIndicesVec.size());
@@ -583,7 +591,7 @@ namespace BSP
*/ */
} }
bool ClipMapLinker::loadWorldCollision(clipMap_t& clipMap, const BSPData& bsp) bool ClipMapLinker::LoadWorldCollision(clipMap_t& clipMap, const BSPData& bsp)
{ {
// No support for brushes, only tris right now // No support for brushes, only tris right now
clipMap.info.numBrushSides = 0; clipMap.info.numBrushSides = 0;
@@ -600,15 +608,15 @@ namespace BSP
clipMap.info.brushContents = nullptr; clipMap.info.brushContents = nullptr;
// load verts, tris, uinds and partitions // load verts, tris, uinds and partitions
if (!loadPartitions(clipMap, bsp)) if (!LoadPartitions(clipMap, bsp))
return false; return false;
loadBSPTree(clipMap, bsp); LoadBSPTree(clipMap, bsp);
return true; return true;
} }
clipMap_t* ClipMapLinker::linkClipMap(const BSPData& bsp) clipMap_t* ClipMapLinker::LinkClipMap(const BSPData& bsp)
{ {
clipMap_t* clipMap = m_memory.Alloc<clipMap_t>(); clipMap_t* clipMap = m_memory.Alloc<clipMap_t>();
clipMap->name = m_memory.Dup(bsp.bspName.c_str()); clipMap->name = m_memory.Dup(bsp.bspName.c_str());
@@ -622,17 +630,17 @@ namespace BSP
assert(mapEntsAsset != nullptr); assert(mapEntsAsset != nullptr);
clipMap->mapEnts = mapEntsAsset->Asset(); clipMap->mapEnts = mapEntsAsset->Asset();
loadBoxData(*clipMap); LoadBoxData(*clipMap);
loadVisibility(*clipMap); LoadVisibility(*clipMap);
loadRopesAndConstraints(*clipMap); LoadRopesAndConstraints(*clipMap);
loadSubModelCollision(*clipMap, bsp); LoadSubModelCollision(*clipMap, bsp);
loadDynEnts(*clipMap); LoadDynEnts(*clipMap);
loadXModelCollision(*clipMap); LoadXModelCollision(*clipMap);
// Clipmap materials define the properties of a material (bullet penetration, no collision, water, etc) // Clipmap materials define the properties of a material (bullet penetration, no collision, water, etc)
// Right now there is no way to define properties per material so only one material is used // Right now there is no way to define properties per material so only one material is used
@@ -648,7 +656,7 @@ namespace BSP
clipMap->triEdgeIsWalkable = new char[walkableEdgeSize]; clipMap->triEdgeIsWalkable = new char[walkableEdgeSize];
memset(clipMap->triEdgeIsWalkable, 1, walkableEdgeSize * sizeof(char)); memset(clipMap->triEdgeIsWalkable, 1, walkableEdgeSize * sizeof(char));
if (!loadWorldCollision(*clipMap, bsp)) if (!LoadWorldCollision(*clipMap, bsp))
return nullptr; return nullptr;
return clipMap; return clipMap;

View File

@@ -13,30 +13,30 @@ namespace BSP
public: public:
ClipMapLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); ClipMapLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] T6::clipMap_t* linkClipMap(const BSPData& bsp); [[nodiscard]] T6::clipMap_t* LinkClipMap(const BSPData& bsp);
private: private:
void LoadBoxData(T6::clipMap_t& clipMap) const;
void LoadVisibility(T6::clipMap_t& clipMap) const;
void LoadDynEnts(T6::clipMap_t& clipMap) const;
void LoadRopesAndConstraints(T6::clipMap_t& clipMap) const;
void LoadSubModelCollision(T6::clipMap_t& clipMap, const BSPData& bsp) const;
void LoadXModelCollision(T6::clipMap_t& clipMap) const;
void AddAABBTreeFromLeaf(T6::clipMap_t& clipMap, const BSPTree& tree, size_t& outParentCount, size_t& outParentStartIndex);
int16_t LoadBSPNode(T6::clipMap_t& clipMap, const BSPTree& tree);
void LoadBSPTree(T6::clipMap_t& clipMap, const BSPData& bsp);
bool LoadPartitions(T6::clipMap_t& clipMap, const BSPData& bsp) const;
bool LoadWorldCollision(T6::clipMap_t& clipMap, const BSPData& bsp);
MemoryManager& m_memory; MemoryManager& m_memory;
ISearchPath& m_search_path; ISearchPath& m_search_path;
AssetCreationContext& m_context; AssetCreationContext& m_context;
void loadBoxData(T6::clipMap_t& clipMap) const;
void loadVisibility(T6::clipMap_t& clipMap) const;
void loadDynEnts(T6::clipMap_t& clipMap) const;
void loadRopesAndConstraints(T6::clipMap_t& clipMap) const;
void loadSubModelCollision(T6::clipMap_t& clipMap, const BSPData& bsp) const;
void loadXModelCollision(T6::clipMap_t& clipMap) const;
std::vector<T6::cplane_s> planeVec; std::vector<T6::cplane_s> planeVec;
std::vector<T6::cNode_t> nodeVec; std::vector<T6::cNode_t> nodeVec;
std::vector<T6::cLeaf_s> leafVec; std::vector<T6::cLeaf_s> leafVec;
std::vector<T6::CollisionAabbTree> AABBTreeVec; std::vector<T6::CollisionAabbTree> AABBTreeVec;
size_t highestLeafObjectCount = 0; size_t highestLeafObjectCount = 0;
void addAABBTreeFromLeaf(T6::clipMap_t& clipMap, const BSPTree& tree, size_t& out_parentCount, size_t& out_parentStartIndex);
int16_t loadBSPNode(T6::clipMap_t& clipMap, const BSPTree& tree);
void loadBSPTree(T6::clipMap_t& clipMap, const BSPData& bsp);
bool loadPartitions(T6::clipMap_t& clipMap, const BSPData& bsp) const;
bool loadWorldCollision(T6::clipMap_t& clipMap, const BSPData& bsp);
}; };
} // namespace BSP } // namespace BSP

View File

@@ -11,10 +11,11 @@ namespace BSP
{ {
} }
ComWorld* ComWorldLinker::linkComWorld(const BSPData& bsp) const ComWorld* ComWorldLinker::LinkComWorld(const BSPData& bsp) const
{ {
// all lights that aren't the sunlight or default light need their own GfxLightDef asset // all lights that aren't the sunlight or default light need their own GfxLightDef asset
ComWorld* comWorld = m_memory.Alloc<ComWorld>(); ComWorld* comWorld = m_memory.Alloc<ComWorld>();
comWorld->name = m_memory.Dup(bsp.bspName.c_str()); comWorld->name = m_memory.Dup(bsp.bspName.c_str());
comWorld->isInUse = 1; comWorld->isInUse = 1;
comWorld->primaryLightCount = BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT; comWorld->primaryLightCount = BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT;
@@ -25,6 +26,7 @@ namespace BSP
ComPrimaryLight* sunLight = &comWorld->primaryLights[1]; ComPrimaryLight* sunLight = &comWorld->primaryLights[1];
const vec4_t sunLightColor = BSPEditableConstants::SUNLIGHT_COLOR; const vec4_t sunLightColor = BSPEditableConstants::SUNLIGHT_COLOR;
const vec3_t sunLightDirection = BSPEditableConstants::SUNLIGHT_DIRECTION; const vec3_t sunLightDirection = BSPEditableConstants::SUNLIGHT_DIRECTION;
sunLight->type = GFX_LIGHT_TYPE_DIR; sunLight->type = GFX_LIGHT_TYPE_DIR;
sunLight->diffuseColor.r = sunLightColor.r; sunLight->diffuseColor.r = sunLightColor.r;
sunLight->diffuseColor.g = sunLightColor.g; sunLight->diffuseColor.g = sunLightColor.g;

View File

@@ -11,7 +11,8 @@ namespace BSP
{ {
public: public:
ComWorldLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); ComWorldLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] T6::ComWorld* linkComWorld(const BSPData& bsp) const;
[[nodiscard]] T6::ComWorld* LinkComWorld(const BSPData& bsp) const;
private: private:
MemoryManager& m_memory; MemoryManager& m_memory;

View File

@@ -11,7 +11,7 @@ namespace BSP
{ {
} }
GameWorldMp* GameWorldMpLinker::linkGameWorldMp(const BSPData& bsp) const GameWorldMp* GameWorldMpLinker::LinkGameWorldMp(const BSPData& bsp) const
{ {
GameWorldMp* gameWorldMp = m_memory.Alloc<GameWorldMp>(); GameWorldMp* gameWorldMp = m_memory.Alloc<GameWorldMp>();
@@ -24,7 +24,7 @@ namespace BSP
gameWorldMp->path.nodeTreeCount = 0; gameWorldMp->path.nodeTreeCount = 0;
// The game has 128 empty nodes allocated // The game has 128 empty nodes allocated
const auto extraNodeCount = gameWorldMp->path.nodeCount + 128; const auto extraNodeCount = gameWorldMp->path.nodeCount + 128u;
gameWorldMp->path.nodes = m_memory.Alloc<pathnode_t>(extraNodeCount); gameWorldMp->path.nodes = m_memory.Alloc<pathnode_t>(extraNodeCount);
gameWorldMp->path.basenodes = m_memory.Alloc<pathbasenode_t>(extraNodeCount); gameWorldMp->path.basenodes = m_memory.Alloc<pathbasenode_t>(extraNodeCount);
gameWorldMp->path.pathVis = nullptr; gameWorldMp->path.pathVis = nullptr;

View File

@@ -11,7 +11,8 @@ namespace BSP
{ {
public: public:
GameWorldMpLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); GameWorldMpLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] T6::GameWorldMp* linkGameWorldMp(const BSPData& bsp) const;
[[nodiscard]] T6::GameWorldMp* LinkGameWorldMp(const BSPData& bsp) const;
private: private:
MemoryManager& m_memory; MemoryManager& m_memory;

View File

@@ -18,7 +18,7 @@ namespace BSP
{ {
} }
void GfxWorldLinker::loadDrawData(const BSPData& bsp, GfxWorld& gfxWorld) const void GfxWorldLinker::LoadDrawData(const BSPData& bsp, GfxWorld& gfxWorld) const
{ {
size_t vertexCount = bsp.gfxWorld.vertices.size(); size_t vertexCount = bsp.gfxWorld.vertices.size();
gfxWorld.draw.vertexCount = static_cast<unsigned int>(vertexCount); gfxWorld.draw.vertexCount = static_cast<unsigned int>(vertexCount);
@@ -56,9 +56,9 @@ namespace BSP
} }
} }
bool GfxWorldLinker::loadMapSurfaces(const BSPData& bsp, GfxWorld& gfxWorld) const bool GfxWorldLinker::LoadMapSurfaces(const BSPData& bsp, GfxWorld& gfxWorld) const
{ {
loadDrawData(bsp, gfxWorld); LoadDrawData(bsp, gfxWorld);
size_t surfaceCount = bsp.gfxWorld.surfaces.size(); size_t surfaceCount = bsp.gfxWorld.surfaces.size();
gfxWorld.surfaceCount = static_cast<int>(surfaceCount); gfxWorld.surfaceCount = static_cast<int>(surfaceCount);
@@ -75,13 +75,13 @@ namespace BSP
gfxSurface->flags = BSPEditableConstants::DEFAULT_SURFACE_FLAGS; gfxSurface->flags = BSPEditableConstants::DEFAULT_SURFACE_FLAGS;
gfxSurface->tris.triCount = static_cast<uint16_t>(bspSurface.triCount); gfxSurface->tris.triCount = static_cast<uint16_t>(bspSurface.triCount);
gfxSurface->tris.baseIndex = bspSurface.indexOfFirstIndex; gfxSurface->tris.baseIndex = static_cast<int>(bspSurface.indexOfFirstIndex);
gfxSurface->tris.vertexDataOffset0 = bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex); gfxSurface->tris.vertexDataOffset0 = static_cast<int>(bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex));
gfxSurface->tris.vertexDataOffset1 = 0; gfxSurface->tris.vertexDataOffset1 = 0;
std::string surfMaterialName; std::string surfMaterialName;
if (bspSurface.material.materialType == MATERIAL_TYPE_TEXTURE) if (bspSurface.material.materialType == BSPMaterialType::MATERIAL_TYPE_TEXTURE)
surfMaterialName = bspSurface.material.materialName; surfMaterialName = bspSurface.material.materialName;
else // MATERIAL_TYPE_COLOUR || MATERIAL_TYPE_EMPTY else // MATERIAL_TYPE_COLOUR || MATERIAL_TYPE_EMPTY
surfMaterialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME; surfMaterialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME;
@@ -156,7 +156,7 @@ namespace BSP
return true; return true;
} }
void GfxWorldLinker::loadXModels(const BSPData& bsp, GfxWorld& gfxWorld) const void GfxWorldLinker::LoadXModels(const BSPData& bsp, GfxWorld& gfxWorld) const
{ {
/* /*
Models are unsupported right now Models are unsupported right now
@@ -185,10 +185,10 @@ namespace BSP
currModel->placement.origin.x = inModel->origin.x; currModel->placement.origin.x = inModel->origin.x;
currModel->placement.origin.y = inModel->origin.y; currModel->placement.origin.y = inModel->origin.y;
currModel->placement.origin.z = inModel->origin.z; currModel->placement.origin.z = inModel->origin.z;
currModel->placement.origin = BSPUtil::convertToBO2Coords(currModel->placement.origin); currModel->placement.origin = ConvertToBO2Coords(currModel->placement.origin);
currModel->placement.scale = inModel->scale; currModel->placement.scale = inModel->scale;
BSPUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis); ConvertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
// mins and maxs are calculated in world space not local space // mins and maxs are calculated in world space not local space
// TODO: this does not account for model rotation or scale // TODO: this does not account for model rotation or scale
@@ -200,9 +200,9 @@ namespace BSP
currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z; currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
currModel->cullDist = DEFAULT_SMODEL_CULL_DIST; currModel->cullDist = DEFAULT_SMODEL_CULL_DIST;
currModel->flags = DEFAULT_SMODEL_FLAGS; currModel->flags = BSPEditableConstants::DEFAULT_SMODEL_FLAGS;
currModel->primaryLightIndex = DEFAULT_SMODEL_LIGHT; currModel->primaryLightIndex = BSPEditableConstants::DEFAULT_SMODEL_LIGHT;
currModel->reflectionProbeIndex = DEFAULT_SMODEL_REFLECTION_PROBE; currModel->reflectionProbeIndex = BSPEditableConstants::DEFAULT_SMODEL_REFLECTION_PROBE;
// unknown use / unused // unknown use / unused
currModel->smid = i; currModel->smid = i;
@@ -231,7 +231,7 @@ namespace BSP
gfxWorld.dpvs.smodelDrawInsts = m_memory.Alloc<GfxStaticModelDrawInst>(modelCount); gfxWorld.dpvs.smodelDrawInsts = m_memory.Alloc<GfxStaticModelDrawInst>(modelCount);
// visdata is written to by the game // visdata is written to by the game
// all visdata is alligned by 128 // all visdata is aligned by 128
const auto alignedModelCount = utils::Align(modelCount, 128uz); const auto alignedModelCount = utils::Align(modelCount, 128uz);
gfxWorld.dpvs.smodelVisDataCount = static_cast<unsigned int>(alignedModelCount); gfxWorld.dpvs.smodelVisDataCount = static_cast<unsigned int>(alignedModelCount);
gfxWorld.dpvs.smodelVisData[0] = m_memory.Alloc<char>(alignedModelCount); gfxWorld.dpvs.smodelVisData[0] = m_memory.Alloc<char>(alignedModelCount);
@@ -251,7 +251,7 @@ namespace BSP
gfxWorld.dpvs.usageCount = 0; gfxWorld.dpvs.usageCount = 0;
} }
void GfxWorldLinker::cleanGfxWorld(GfxWorld& gfxWorld) const void GfxWorldLinker::CleanGfxWorld(GfxWorld& gfxWorld) const
{ {
// checksum is generated by the game // checksum is generated by the game
gfxWorld.checksum = 0; gfxWorld.checksum = 0;
@@ -337,7 +337,7 @@ namespace BSP
gfxWorld.sunLight = m_memory.Alloc<GfxLight>(); gfxWorld.sunLight = m_memory.Alloc<GfxLight>();
} }
void GfxWorldLinker::loadGfxLights(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadGfxLights(GfxWorld& gfxWorld) const
{ {
// there must be 2 or more lights, first is the static light and second is the sun light // there must be 2 or more lights, first is the static light and second is the sun light
gfxWorld.primaryLightCount = BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT; gfxWorld.primaryLightCount = BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT;
@@ -366,7 +366,7 @@ namespace BSP
gfxWorld.primaryLightEntityShadowVis = nullptr; gfxWorld.primaryLightEntityShadowVis = nullptr;
} }
void GfxWorldLinker::loadLightGrid(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadLightGrid(GfxWorld& gfxWorld) const
{ {
// there is almost no basis for the values in this code, they were chosen based on what looks correct when reverse engineering. // there is almost no basis for the values in this code, they were chosen based on what looks correct when reverse engineering.
@@ -424,7 +424,7 @@ namespace BSP
gfxWorld.lightGrid.skyGridVolumes = nullptr; gfxWorld.lightGrid.skyGridVolumes = nullptr;
} }
void GfxWorldLinker::loadGfxCells(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadGfxCells(GfxWorld& gfxWorld) const
{ {
// Cells are basically data used to determine what can be seen and what cant be seen // Cells are basically data used to determine what can be seen and what cant be seen
// Right now custom maps have no optimisation so there is only 1 cell // Right now custom maps have no optimisation so there is only 1 cell
@@ -488,7 +488,7 @@ namespace BSP
gfxWorld.dpvsPlanes.planes = nullptr; gfxWorld.dpvsPlanes.planes = nullptr;
} }
void GfxWorldLinker::loadWorldBounds(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadWorldBounds(GfxWorld& gfxWorld) const
{ {
gfxWorld.mins.x = 0.0f; gfxWorld.mins.x = 0.0f;
gfxWorld.mins.y = 0.0f; gfxWorld.mins.y = 0.0f;
@@ -503,7 +503,7 @@ namespace BSP
} }
} }
void GfxWorldLinker::loadModels(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadModels(GfxWorld& gfxWorld) const
{ {
// Models (Submodels in the clipmap code) are used for the world and map ent collision (triggers, bomb zones, etc) // Models (Submodels in the clipmap code) are used for the world and map ent collision (triggers, bomb zones, etc)
// Right now there is only one submodel, the world sub model // Right now there is only one submodel, the world sub model
@@ -540,7 +540,7 @@ namespace BSP
//} //}
} }
void GfxWorldLinker::loadSunData(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadSunData(GfxWorld& gfxWorld) const
{ {
// default values taken from mp_dig // default values taken from mp_dig
gfxWorld.sunParse.fogTransitionTime = 0.001f; gfxWorld.sunParse.fogTransitionTime = 0.001f;
@@ -586,7 +586,7 @@ namespace BSP
gfxWorld.sunParse.initWorldFog->sunFogYaw = 254.0f; gfxWorld.sunParse.initWorldFog->sunFogYaw = 254.0f;
} }
bool GfxWorldLinker::loadReflectionProbeData(GfxWorld& gfxWorld) const bool GfxWorldLinker::LoadReflectionProbeData(GfxWorld& gfxWorld) const
{ {
gfxWorld.draw.reflectionProbeCount = 1; gfxWorld.draw.reflectionProbeCount = 1;
@@ -616,7 +616,7 @@ namespace BSP
std::string probeImageName = "reflection_probe0"; std::string probeImageName = "reflection_probe0";
auto probeImageAsset = m_context.LoadDependency<AssetImage>(probeImageName); auto probeImageAsset = m_context.LoadDependency<AssetImage>(probeImageName);
if (probeImageAsset == nullptr) if (!probeImageAsset)
{ {
con::error("ERROR! unable to find reflection probe image {}!", probeImageName); con::error("ERROR! unable to find reflection probe image {}!", probeImageName);
return false; return false;
@@ -626,7 +626,7 @@ namespace BSP
return true; return true;
} }
bool GfxWorldLinker::loadLightmapData(GfxWorld& gfxWorld) const bool GfxWorldLinker::LoadLightmapData(GfxWorld& gfxWorld) const
{ {
gfxWorld.draw.lightmapCount = 1; gfxWorld.draw.lightmapCount = 1;
@@ -635,7 +635,7 @@ namespace BSP
std::string secondaryTexture = "lightmap0_secondary"; std::string secondaryTexture = "lightmap0_secondary";
auto secondaryTextureAsset = m_context.LoadDependency<AssetImage>(secondaryTexture); auto secondaryTextureAsset = m_context.LoadDependency<AssetImage>(secondaryTexture);
if (secondaryTextureAsset == nullptr) if (!secondaryTextureAsset)
{ {
con::error("ERROR! unable to find lightmap image {}!", secondaryTexture); con::error("ERROR! unable to find lightmap image {}!", secondaryTexture);
return false; return false;
@@ -647,7 +647,7 @@ namespace BSP
return true; return true;
} }
void GfxWorldLinker::loadSkyBox(const BSPData& projInfo, GfxWorld& gfxWorld) const void GfxWorldLinker::LoadSkyBox(const BSPData& projInfo, GfxWorld& gfxWorld) const
{ {
const auto skyBoxName = std::format("skybox_{}", projInfo.name); const auto skyBoxName = std::format("skybox_{}", projInfo.name);
gfxWorld.skyBoxModel = m_memory.Dup(skyBoxName.c_str()); gfxWorld.skyBoxModel = m_memory.Dup(skyBoxName.c_str());
@@ -664,9 +664,9 @@ namespace BSP
gfxWorld.skyDynIntensity.factor1 = 1.0f; gfxWorld.skyDynIntensity.factor1 = 1.0f;
} }
void GfxWorldLinker::loadDynEntData(GfxWorld& gfxWorld) const void GfxWorldLinker::LoadDynEntData(GfxWorld& gfxWorld) const
{ {
int dynEntCount = 0; unsigned dynEntCount = 0u;
gfxWorld.dpvsDyn.dynEntClientCount[0] = dynEntCount + 256; // the game allocs 256 empty dynents, as they may be used ingame gfxWorld.dpvsDyn.dynEntClientCount[0] = dynEntCount + 256; // the game allocs 256 empty dynents, as they may be used ingame
gfxWorld.dpvsDyn.dynEntClientCount[1] = 0; gfxWorld.dpvsDyn.dynEntClientCount[1] = 0;
@@ -676,11 +676,11 @@ namespace BSP
gfxWorld.dpvsDyn.dynEntClientWordCount[1] = 0; gfxWorld.dpvsDyn.dynEntClientWordCount[1] = 0;
gfxWorld.dpvsDyn.usageCount = 0; gfxWorld.dpvsDyn.usageCount = 0;
const auto dynEntCellBitsSize = gfxWorld.dpvsDyn.dynEntClientWordCount[0] * gfxWorld.dpvsPlanes.cellCount; const auto dynEntCellBitsSize = gfxWorld.dpvsDyn.dynEntClientWordCount[0] * static_cast<unsigned>(gfxWorld.dpvsPlanes.cellCount);
gfxWorld.dpvsDyn.dynEntCellBits[0] = m_memory.Alloc<unsigned int>(dynEntCellBitsSize); gfxWorld.dpvsDyn.dynEntCellBits[0] = m_memory.Alloc<unsigned int>(dynEntCellBitsSize);
gfxWorld.dpvsDyn.dynEntCellBits[1] = nullptr; gfxWorld.dpvsDyn.dynEntCellBits[1] = nullptr;
const auto dynEntVisData0Size = gfxWorld.dpvsDyn.dynEntClientWordCount[0] * 32; const auto dynEntVisData0Size = gfxWorld.dpvsDyn.dynEntClientWordCount[0] * 32u;
gfxWorld.dpvsDyn.dynEntVisData[0][0] = m_memory.Alloc<char>(dynEntVisData0Size); gfxWorld.dpvsDyn.dynEntVisData[0][0] = m_memory.Alloc<char>(dynEntVisData0Size);
gfxWorld.dpvsDyn.dynEntVisData[0][1] = m_memory.Alloc<char>(dynEntVisData0Size); gfxWorld.dpvsDyn.dynEntVisData[0][1] = m_memory.Alloc<char>(dynEntVisData0Size);
gfxWorld.dpvsDyn.dynEntVisData[0][2] = m_memory.Alloc<char>(dynEntVisData0Size); gfxWorld.dpvsDyn.dynEntVisData[0][2] = m_memory.Alloc<char>(dynEntVisData0Size);
@@ -688,7 +688,7 @@ namespace BSP
gfxWorld.dpvsDyn.dynEntVisData[1][1] = nullptr; gfxWorld.dpvsDyn.dynEntVisData[1][1] = nullptr;
gfxWorld.dpvsDyn.dynEntVisData[1][2] = nullptr; gfxWorld.dpvsDyn.dynEntVisData[1][2] = nullptr;
const auto dynEntShadowVisCount = gfxWorld.dpvsDyn.dynEntClientCount[0] * (gfxWorld.primaryLightCount - gfxWorld.sunPrimaryLightIndex - 1); const auto dynEntShadowVisCount = gfxWorld.dpvsDyn.dynEntClientCount[0] * (gfxWorld.primaryLightCount - gfxWorld.sunPrimaryLightIndex - 1u);
gfxWorld.primaryLightDynEntShadowVis[0] = m_memory.Alloc<unsigned int>(dynEntShadowVisCount); gfxWorld.primaryLightDynEntShadowVis[0] = m_memory.Alloc<unsigned int>(dynEntShadowVisCount);
gfxWorld.primaryLightDynEntShadowVis[1] = nullptr; gfxWorld.primaryLightDynEntShadowVis[1] = nullptr;
@@ -696,7 +696,7 @@ namespace BSP
gfxWorld.sceneDynBrush = nullptr; gfxWorld.sceneDynBrush = nullptr;
} }
bool GfxWorldLinker::loadOutdoors(GfxWorld& gfxWorld) const bool GfxWorldLinker::LoadOutdoors(GfxWorld& gfxWorld) const
{ {
const auto xRecip = 1.0f / (gfxWorld.maxs.x - gfxWorld.mins.x); const auto xRecip = 1.0f / (gfxWorld.maxs.x - gfxWorld.mins.x);
const auto xScale = -(xRecip * gfxWorld.mins.x); const auto xScale = -(xRecip * gfxWorld.mins.x);
@@ -717,9 +717,8 @@ namespace BSP
gfxWorld.outdoorLookupMatrix[3].z = zScale; gfxWorld.outdoorLookupMatrix[3].z = zScale;
gfxWorld.outdoorLookupMatrix[3].w = 1.0f; gfxWorld.outdoorLookupMatrix[3].w = 1.0f;
const std::string outdoorImageName = std::string("$outdoor"); const auto outdoorImageAsset = m_context.LoadDependency<AssetImage>("$outdoor");
auto outdoorImageAsset = m_context.LoadDependency<AssetImage>(outdoorImageName); if (!outdoorImageAsset)
if (outdoorImageAsset == nullptr)
{ {
con::error("ERROR! unable to find outdoor image $outdoor!"); con::error("ERROR! unable to find outdoor image $outdoor!");
return false; return false;
@@ -729,7 +728,7 @@ namespace BSP
return true; return true;
} }
GfxWorld* GfxWorldLinker::linkGfxWorld(const BSPData& bsp) const GfxWorld* GfxWorldLinker::LinkGfxWorld(const BSPData& bsp) const
{ {
GfxWorld* gfxWorld = m_memory.Alloc<GfxWorld>(); GfxWorld* gfxWorld = m_memory.Alloc<GfxWorld>();
gfxWorld->baseName = m_memory.Dup(bsp.name.c_str()); gfxWorld->baseName = m_memory.Dup(bsp.name.c_str());
@@ -739,39 +738,39 @@ namespace BSP
gfxWorld->lightingFlags = 0; gfxWorld->lightingFlags = 0;
gfxWorld->lightingQuality = 4096; gfxWorld->lightingQuality = 4096;
cleanGfxWorld(*gfxWorld); CleanGfxWorld(*gfxWorld);
if (!loadMapSurfaces(bsp, *gfxWorld)) if (!LoadMapSurfaces(bsp, *gfxWorld))
return nullptr; return nullptr;
loadXModels(bsp, *gfxWorld); LoadXModels(bsp, *gfxWorld);
if (!loadLightmapData(*gfxWorld)) if (!LoadLightmapData(*gfxWorld))
return nullptr; return nullptr;
loadSkyBox(bsp, *gfxWorld); LoadSkyBox(bsp, *gfxWorld);
if (!loadReflectionProbeData(*gfxWorld)) if (!LoadReflectionProbeData(*gfxWorld))
return nullptr; return nullptr;
// world bounds are based on loaded surface mins/maxs // world bounds are based on loaded surface mins/maxs
loadWorldBounds(*gfxWorld); LoadWorldBounds(*gfxWorld);
if (!loadOutdoors(*gfxWorld)) if (!LoadOutdoors(*gfxWorld))
return nullptr; return nullptr;
// gfx cells depend on surface/smodel count // gfx cells depend on surface/smodel count
loadGfxCells(*gfxWorld); LoadGfxCells(*gfxWorld);
loadLightGrid(*gfxWorld); LoadLightGrid(*gfxWorld);
loadGfxLights(*gfxWorld); LoadGfxLights(*gfxWorld);
loadModels(*gfxWorld); LoadModels(*gfxWorld);
loadSunData(*gfxWorld); LoadSunData(*gfxWorld);
loadDynEntData(*gfxWorld); LoadDynEntData(*gfxWorld);
return gfxWorld; return gfxWorld;
} }

View File

@@ -11,27 +11,28 @@ namespace BSP
{ {
public: public:
GfxWorldLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); GfxWorldLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] T6::GfxWorld* linkGfxWorld(const BSPData& bsp) const;
[[nodiscard]] T6::GfxWorld* LinkGfxWorld(const BSPData& bsp) const;
private: private:
void LoadDrawData(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
bool LoadMapSurfaces(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
void LoadXModels(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
void CleanGfxWorld(T6::GfxWorld& gfxWorld) const;
void LoadGfxLights(T6::GfxWorld& gfxWorld) const;
void LoadLightGrid(T6::GfxWorld& gfxWorld) const;
void LoadGfxCells(T6::GfxWorld& gfxWorld) const;
void LoadModels(T6::GfxWorld& gfxWorld) const;
bool LoadReflectionProbeData(T6::GfxWorld& gfxWorld) const;
bool LoadLightmapData(T6::GfxWorld& gfxWorld) const;
void LoadSkyBox(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
void LoadDynEntData(T6::GfxWorld& gfxWorld) const;
bool LoadOutdoors(T6::GfxWorld& gfxWorld) const;
void LoadSunData(T6::GfxWorld& gfxWorld) const;
void LoadWorldBounds(T6::GfxWorld& gfxWorld) const;
MemoryManager& m_memory; MemoryManager& m_memory;
ISearchPath& m_search_path; ISearchPath& m_search_path;
AssetCreationContext& m_context; AssetCreationContext& m_context;
void loadDrawData(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
bool loadMapSurfaces(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
void loadXModels(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
void cleanGfxWorld(T6::GfxWorld& gfxWorld) const;
void loadGfxLights(T6::GfxWorld& gfxWorld) const;
void loadLightGrid(T6::GfxWorld& gfxWorld) const;
void loadGfxCells(T6::GfxWorld& gfxWorld) const;
void loadModels(T6::GfxWorld& gfxWorld) const;
bool loadReflectionProbeData(T6::GfxWorld& gfxWorld) const;
bool loadLightmapData(T6::GfxWorld& gfxWorld) const;
void loadSkyBox(const BSPData& projInfo, T6::GfxWorld& gfxWorld) const;
void loadDynEntData(T6::GfxWorld& gfxWorld) const;
bool loadOutdoors(T6::GfxWorld& gfxWorld) const;
void loadSunData(T6::GfxWorld& gfxWorld) const;
void loadWorldBounds(T6::GfxWorld& gfxWorld) const;
}; };
} // namespace BSP } // namespace BSP

View File

@@ -74,13 +74,12 @@ namespace BSP
{ {
} }
MapEnts* MapEntsLinker::linkMapEnts(const BSPData& bsp) const MapEnts* MapEntsLinker::LinkMapEnts(const BSPData& bsp) const
{ {
try try
{ {
json entJs; json entJs;
std::string entityFileName = "entities.json"; std::string entityFilePath = GetFileNameForBSPAsset("entities.json");
std::string entityFilePath = GetFileNameForBSPAsset(entityFileName);
const auto entFile = m_search_path.Open(entityFilePath); const auto entFile = m_search_path.Open(entityFilePath);
if (!entFile.IsOpen()) if (!entFile.IsOpen())
{ {
@@ -108,9 +107,9 @@ namespace BSP
{ {
spawnJs = json::parse(*spawnFile.m_stream); spawnJs = json::parse(*spawnFile.m_stream);
} }
size_t defenderNameCount = std::extent<decltype(BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES)>::value; size_t defenderNameCount = std::extent_v<decltype(BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES)>;
size_t attackerNameCount = std::extent<decltype(BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES)>::value; size_t attackerNameCount = std::extent_v<decltype(BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES)>;
size_t ffaNameCount = std::extent<decltype(BSPGameConstants::FFA_SPAWN_POINT_NAMES)>::value; size_t ffaNameCount = std::extent_v<decltype(BSPGameConstants::FFA_SPAWN_POINT_NAMES)>;
parseSpawnpointJSON(spawnJs["attackers"], entityString, BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES, defenderNameCount); parseSpawnpointJSON(spawnJs["attackers"], entityString, BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES, defenderNameCount);
parseSpawnpointJSON(spawnJs["defenders"], entityString, BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES, attackerNameCount); parseSpawnpointJSON(spawnJs["defenders"], entityString, BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES, attackerNameCount);
parseSpawnpointJSON(spawnJs["FFA"], entityString, BSPGameConstants::FFA_SPAWN_POINT_NAMES, ffaNameCount); parseSpawnpointJSON(spawnJs["FFA"], entityString, BSPGameConstants::FFA_SPAWN_POINT_NAMES, ffaNameCount);

View File

@@ -11,7 +11,8 @@ namespace BSP
{ {
public: public:
MapEntsLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); MapEntsLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] T6::MapEnts* linkMapEnts(const BSPData& bsp) const;
[[nodiscard]] T6::MapEnts* LinkMapEnts(const BSPData& bsp) const;
private: private:
MemoryManager& m_memory; MemoryManager& m_memory;

View File

@@ -9,7 +9,7 @@ namespace BSP
{ {
} }
T6::SkinnedVertsDef* SkinnedVertsLinker::linkSkinnedVerts(const BSPData& bsp) const T6::SkinnedVertsDef* SkinnedVertsLinker::LinkSkinnedVerts(const BSPData& bsp) const
{ {
// Pretty sure maxSkinnedVerts relates to the max amount of xmodel skinned verts a map will have // Pretty sure maxSkinnedVerts relates to the max amount of xmodel skinned verts a map will have
// But setting it to the world vertex count seems to work // But setting it to the world vertex count seems to work

View File

@@ -11,7 +11,8 @@ namespace BSP
{ {
public: public:
SkinnedVertsLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context); SkinnedVertsLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context);
[[nodiscard]] T6::SkinnedVertsDef* linkSkinnedVerts(const BSPData& bsp) const;
[[nodiscard]] T6::SkinnedVertsDef* LinkSkinnedVerts(const BSPData& bsp) const;
private: private:
MemoryManager& m_memory; MemoryManager& m_memory;

View File

@@ -32,12 +32,12 @@ namespace
bool FinalizeZone(AssetCreationContext& context) override bool FinalizeZone(AssetCreationContext& context) override
{ {
const std::unique_ptr<BSPData> bsp = BSP::createBSPData(m_zone.m_name, m_search_path); const auto bsp = CreateBSPData(m_zone.m_name, m_search_path);
if (bsp == nullptr) if (!bsp)
return false; return false;
BSPLinker linker(m_memory, m_search_path, context); BSPLinker linker(m_memory, m_search_path, context);
const auto result = linker.linkBSP(*bsp); const auto result = linker.LinkBSP(*bsp);
if (!result) if (!result)
con::error("BSP link has failed."); con::error("BSP link has failed.");