2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 08:42:35 +00:00

refactor: remove extra classes from BSP.h and move vars to their respective files

This commit is contained in:
LJW-Dev
2026-04-24 00:30:59 +08:00
committed by Jan Laupetin
parent 8fd7691a2d
commit 99229fa1ac
4 changed files with 228 additions and 271 deletions
+5 -60
View File
@@ -180,65 +180,10 @@ namespace BSP
std::vector<BSPModel> models; std::vector<BSPModel> models;
}; };
// BSPGameConstants: enum BSPDefaultLights
// These values are hardcoded ingame and will break the map if they are changed
namespace BSPGameConstants
{ {
constexpr unsigned int MAX_COLLISION_VERTS = UINT16_MAX; EMPTY_LIGHT_INDEX = 0,
SUN_LIGHT_INDEX = 1,
constexpr size_t MAX_AABB_TREE_CHILDREN = 128; BSP_DEFAULT_LIGHT_COUNT = 2
};
enum BSPDefaultLights
{
EMPTY_LIGHT_INDEX = 0,
SUN_LIGHT_INDEX = 1,
BSP_DEFAULT_LIGHT_COUNT = 2
};
} // namespace BSPGameConstants
// BSPLinkingConstants:
// These values are BSP linking constants that are required for the link to be successful
namespace BSPLinkingConstants
{
constexpr const char* MISSING_IMAGE_NAME = ",mc/lambert1";
constexpr const char* COLOR_ONLY_IMAGE_NAME = ",mc/lambert1";
} // namespace BSPLinkingConstants
// BSPEditableConstants:
// These values are BSP constants that can be edited and may not break the linker/game if changed
namespace BSPEditableConstants
{
// Default xmodel values
// Unused as there is no support for xmodels right now
constexpr float DEFAULT_SMODEL_CULL_DIST = 10000.0f;
constexpr int DEFAULT_SMODEL_FLAGS = STATIC_MODEL_FLAG_NO_SHADOW;
constexpr int DEFAULT_SMODEL_LIGHT = 1;
constexpr int DEFAULT_SMODEL_REFLECTION_PROBE = 0;
// Default surface values
constexpr int DEFAULT_SURFACE_LIGHT = 1;
constexpr int DEFAULT_SURFACE_LIGHTMAP = 0;
constexpr int DEFAULT_SURFACE_REFLECTION_PROBE = 0;
constexpr int DEFAULT_SURFACE_FLAGS = 0;
// material flags determine the features of a surface
// unsure which flag type changes what right now
// -1 results in: no running, water splashes all the time, low friction, slanted angles make you slide very fast
// 1 results in: normal surface features, grenades work, seems normal
constexpr int MATERIAL_SURFACE_FLAGS = 1;
constexpr int MATERIAL_CONTENT_FLAGS = 1;
// terrain/world flags: does not change the type of terrain or what features they have
// from testing, as long at it isn't 0 things will work correctly
constexpr int LEAF_TERRAIN_CONTENTS = 1;
constexpr int WORLD_TERRAIN_CONTENTS = 1;
// lightgrid (global) lighting colour
// since lightgrids are not well understood, this colour is used for the R, G and B values right now
constexpr unsigned char LIGHTGRID_COLOUR = 128;
// Sunlight values
constexpr vec4_t SUNLIGHT_COLOR = {0.75f, 0.75f, 0.75f, 1.0f};
constexpr vec3_t SUNLIGHT_DIRECTION = {0.0f, 0.0f, 0.0f};
}; // namespace BSPEditableConstants
} // namespace BSP } // namespace BSP
@@ -2,6 +2,17 @@
#include "../BSPUtil.h" #include "../BSPUtil.h"
namespace
{
struct uniqueMatData
{
size_t materialIndex;
std::vector<int> partitionIndexes;
};
constexpr size_t MAX_AABB_TREE_CHILDREN = 128;
} // namespace
namespace BSP namespace BSP
{ {
ClipMapLinker::ClipMapLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context) ClipMapLinker::ClipMapLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context)
@@ -202,179 +213,6 @@ namespace BSP
return true; return true;
} }
void calculatePartitionAABB(clipMap_t* clipMap, CollisionPartition* partition, vec3_t& out_mins, vec3_t& out_maxs);
void addAABBTreeFromPartitions(
clipMap_t* clipMap, std::vector<int>& partitions, size_t* out_parentCount, size_t* out_parentStartIndex, int* out_treeContents);
void ClipMapLinker::loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp)
{
// Submodels are used for the world and map ent collision (triggers, bomb zones, etc)
clipMap->numSubModels = static_cast<unsigned int>(bsp->models.size() + 1);
clipMap->cmodels = m_memory.Alloc<cmodel_t>(clipMap->numSubModels);
// first model is always the world model
for (unsigned int vertIdx = 0; vertIdx < clipMap->vertCount; vertIdx++)
{
vec3_t vertex = clipMap->verts[vertIdx];
if (vertIdx == 0)
{
clipMap->cmodels[0].mins = vertex;
clipMap->cmodels[0].maxs = vertex;
}
else
BSPUtil::updateAABBWithPoint(vertex, clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs);
}
clipMap->cmodels[0].radius = BSPUtil::distBetweenPoints(clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs) / 2;
// The world sub model has no data apart from the bounds
clipMap->cmodels[0].leaf.firstCollAabbIndex = 0;
clipMap->cmodels[0].leaf.collAabbCount = 0;
clipMap->cmodels[0].leaf.brushContents = 0;
clipMap->cmodels[0].leaf.terrainContents = 0;
clipMap->cmodels[0].leaf.mins.x = 0.0f;
clipMap->cmodels[0].leaf.mins.y = 0.0f;
clipMap->cmodels[0].leaf.mins.z = 0.0f;
clipMap->cmodels[0].leaf.maxs.x = 0.0f;
clipMap->cmodels[0].leaf.maxs.y = 0.0f;
clipMap->cmodels[0].leaf.maxs.z = 0.0f;
clipMap->cmodels[0].leaf.leafBrushNode = 0;
clipMap->cmodels[0].leaf.cluster = 0;
clipMap->cmodels[0].info = nullptr;
for (size_t modelIdx = 0; modelIdx < bsp->models.size(); modelIdx++)
{
auto clipModel = &clipMap->cmodels[modelIdx + 1];
auto& bspModel = bsp->models.at(modelIdx);
if (bspModel.isGfxModel)
{
memset(clipModel, 0, sizeof(cmodel_t));
continue;
}
if (bspModel.surfaceCount != 0)
{
std::vector<int> partitionIndexes;
for (size_t surfIdx = 0; surfIdx < bspModel.surfaceCount; surfIdx++)
{
ColSurface& surf = collisionSurfaceVec.at(bsp->colWorld.staticSurfaces.size() + bspModel.surfaceIndex + surfIdx);
for (size_t partitionIdx = 0; partitionIdx < surf.partitionCount; partitionIdx++)
{
size_t clipMapPartitionIndex = surf.partitionStartIndex + partitionIdx;
partitionIndexes.emplace_back(clipMapPartitionIndex);
vec3_t mins;
vec3_t maxs;
calculatePartitionAABB(clipMap, &clipMap->partitions[clipMapPartitionIndex], mins, maxs);
if (surfIdx == 0 && partitionIdx == 0)
{
clipModel->mins = mins;
clipModel->maxs = maxs;
}
else
BSPUtil::updateAABB(mins, maxs, clipModel->mins, clipModel->maxs);
}
}
int terrainContents = 0;
size_t firstCollAabbIndex = 0;
size_t collAabbCount = 0;
addAABBTreeFromPartitions(clipMap, partitionIndexes, &collAabbCount, &firstCollAabbIndex, &terrainContents);
clipModel->leaf.terrainContents = terrainContents;
clipModel->leaf.firstCollAabbIndex = static_cast<uint16_t>(firstCollAabbIndex);
clipModel->leaf.collAabbCount = static_cast<uint16_t>(collAabbCount);
}
else
{
clipModel->leaf.terrainContents = 0;
clipModel->leaf.firstCollAabbIndex = 0;
clipModel->leaf.collAabbCount = 0;
}
if (bspModel.hasBrush)
{
BSPBoxBrush& bspBrush = bsp->colWorld.scriptBoxBrushes.at(bspModel.brushIndex);
vec3_t mins;
vec3_t maxs;
for (size_t vertIdx = 0; vertIdx < bspBrush.vertexCount; vertIdx++)
{
vec3_t* vertex = &clipMap->info.brushVerts[bspBrush.vertexIndex + vertIdx];
if (vertIdx == 0)
{
mins = *vertex;
maxs = *vertex;
}
else
BSPUtil::updateAABBWithPoint(*vertex, mins, maxs);
}
clipModel->leaf.mins = mins;
clipModel->leaf.maxs = maxs;
clipModel->leaf.brushContents = bspBrush.contentFlags;
clipModel->leaf.leafBrushNode = static_cast<int>(brushNodeVec.size());
assert(clipModel->leaf.leafBrushNode != 0);
cLeafBrushNode_s brushNode;
brushNode.axis = 0;
brushNode.contents = bspBrush.contentFlags;
brushNode.leafBrushCount = 1;
brushNode.data.leaf.brushes = m_memory.Alloc<LeafBrush>(1);
brushNode.data.leaf.brushes[0] = static_cast<unsigned short>(brushVec.size());
brushNodeVec.emplace_back(brushNode);
cbrush_array_t brush;
memset(&brush, 0, sizeof(cbrush_array_t)); // if not sides or verts are given, the mins/maxs are used instead
brush.numverts = static_cast<unsigned int>(bspBrush.vertexCount);
brush.verts = &clipMap->info.brushVerts[bspBrush.vertexIndex];
brush.contents = bspBrush.contentFlags;
brush.mins = mins;
brush.maxs = maxs;
brush.axial_cflags[0][0] = bspBrush.contentFlags;
brush.axial_cflags[0][1] = bspBrush.contentFlags;
brush.axial_cflags[0][2] = bspBrush.contentFlags;
brush.axial_cflags[1][0] = bspBrush.contentFlags;
brush.axial_cflags[1][1] = bspBrush.contentFlags;
brush.axial_cflags[1][2] = bspBrush.contentFlags;
brush.axial_sflags[0][0] = bspBrush.surfaceFlags;
brush.axial_sflags[0][1] = bspBrush.surfaceFlags;
brush.axial_sflags[0][2] = bspBrush.surfaceFlags;
brush.axial_sflags[1][0] = bspBrush.surfaceFlags;
brush.axial_sflags[1][1] = bspBrush.surfaceFlags;
brush.axial_sflags[1][2] = bspBrush.surfaceFlags;
brushVec.emplace_back(brush);
if (bspModel.surfaceCount != 0)
BSPUtil::updateAABB(mins, maxs, clipModel->mins, clipModel->maxs);
else
{
clipModel->mins = mins;
clipModel->maxs = maxs;
}
}
else
{
clipModel->leaf.brushContents = 0;
clipModel->leaf.mins.x = 0.0f;
clipModel->leaf.mins.y = 0.0f;
clipModel->leaf.mins.z = 0.0f;
clipModel->leaf.maxs.x = 0.0f;
clipModel->leaf.maxs.y = 0.0f;
clipModel->leaf.maxs.z = 0.0f;
clipModel->leaf.leafBrushNode = 0;
}
if (bspModel.surfaceCount == 0 && !bspModel.hasBrush)
{
clipModel->mins = {0.0f, 0.0f, 0.0f};
clipModel->maxs = {0.0f, 0.0f, 0.0f};
clipModel->radius = 0.0f;
}
else
clipModel->radius = BSPUtil::distBetweenPoints(clipModel->mins, clipModel->maxs) / 2;
clipModel->leaf.cluster = 0;
clipModel->info = nullptr;
}
}
// out_mins and out_maxs are initialised in the function // out_mins and out_maxs are initialised in the function
void calculatePartitionAABB(clipMap_t* clipMap, CollisionPartition* partition, vec3_t& out_mins, vec3_t& out_maxs) void calculatePartitionAABB(clipMap_t* clipMap, CollisionPartition* partition, vec3_t& out_mins, vec3_t& out_maxs)
{ {
@@ -394,12 +232,6 @@ namespace BSP
} }
} }
struct uniqueMatData
{
size_t materialIndex;
std::vector<int> partitionIndexes;
};
void ClipMapLinker::addAABBTreeFromPartitions( void ClipMapLinker::addAABBTreeFromPartitions(
clipMap_t* clipMap, std::vector<int>& partitions, size_t* out_parentCount, size_t* out_parentStartIndex, int* out_treeContents) clipMap_t* clipMap, std::vector<int>& partitions, size_t* out_parentCount, size_t* out_parentStartIndex, int* out_treeContents)
{ {
@@ -438,8 +270,8 @@ namespace BSP
for (auto& matData : uniqueMaterials) for (auto& matData : uniqueMaterials)
{ {
size_t objCount = matData.partitionIndexes.size(); size_t objCount = matData.partitionIndexes.size();
size_t result = objCount / BSPGameConstants::MAX_AABB_TREE_CHILDREN; size_t result = objCount / MAX_AABB_TREE_CHILDREN;
size_t remainder = objCount % BSPGameConstants::MAX_AABB_TREE_CHILDREN; size_t remainder = objCount % MAX_AABB_TREE_CHILDREN;
if (remainder > 0) if (remainder > 0)
result++; result++;
totalParentCount += result; totalParentCount += result;
@@ -454,8 +286,8 @@ namespace BSP
for (auto& matData : uniqueMaterials) for (auto& matData : uniqueMaterials)
{ {
size_t matPartCount = matData.partitionIndexes.size(); size_t matPartCount = matData.partitionIndexes.size();
size_t parentCount = matPartCount / BSPGameConstants::MAX_AABB_TREE_CHILDREN; size_t parentCount = matPartCount / MAX_AABB_TREE_CHILDREN;
size_t remainder = matPartCount % BSPGameConstants::MAX_AABB_TREE_CHILDREN; size_t remainder = matPartCount % MAX_AABB_TREE_CHILDREN;
if (remainder > 0) if (remainder > 0)
parentCount++; parentCount++;
@@ -463,11 +295,11 @@ namespace BSP
size_t addedObjectCount = 0; size_t addedObjectCount = 0;
for (size_t parentIdx = 0; parentIdx < parentCount; parentIdx++) for (size_t parentIdx = 0; parentIdx < parentCount; parentIdx++)
{ {
size_t currChildObjectCount = BSPGameConstants::MAX_AABB_TREE_CHILDREN; size_t currChildObjectCount = MAX_AABB_TREE_CHILDREN;
if (unaddedObjectCount <= BSPGameConstants::MAX_AABB_TREE_CHILDREN) if (unaddedObjectCount <= MAX_AABB_TREE_CHILDREN)
currChildObjectCount = unaddedObjectCount; currChildObjectCount = unaddedObjectCount;
else else
unaddedObjectCount -= BSPGameConstants::MAX_AABB_TREE_CHILDREN; unaddedObjectCount -= MAX_AABB_TREE_CHILDREN;
vec3_t parentMins; vec3_t parentMins;
vec3_t parentMaxs; vec3_t parentMaxs;
@@ -680,10 +512,9 @@ namespace BSP
{ {
// 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
if (static_cast<unsigned int>(bsp->colWorld.vertices.size()) > BSPGameConstants::MAX_COLLISION_VERTS) if (static_cast<unsigned int>(bsp->colWorld.vertices.size()) > UINT16_MAX)
{ {
con::error( con::error("ERROR: collision vertex count {} exceeds the maximum number: {}!\n", bsp->colWorld.vertices.size(), UINT16_MAX);
"ERROR: collision vertex count {} exceeds the maximum number: {}!\n", bsp->colWorld.vertices.size(), BSPGameConstants::MAX_COLLISION_VERTS);
return false; return false;
} }
@@ -826,6 +657,175 @@ namespace BSP
return true; return true;
} }
void ClipMapLinker::loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp)
{
// Submodels are used for the world and map ent collision (triggers, bomb zones, etc)
clipMap->numSubModels = static_cast<unsigned int>(bsp->models.size() + 1);
clipMap->cmodels = m_memory.Alloc<cmodel_t>(clipMap->numSubModels);
// first model is always the world model
for (unsigned int vertIdx = 0; vertIdx < clipMap->vertCount; vertIdx++)
{
vec3_t vertex = clipMap->verts[vertIdx];
if (vertIdx == 0)
{
clipMap->cmodels[0].mins = vertex;
clipMap->cmodels[0].maxs = vertex;
}
else
BSPUtil::updateAABBWithPoint(vertex, clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs);
}
clipMap->cmodels[0].radius = BSPUtil::distBetweenPoints(clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs) / 2;
// The world sub model has no data apart from the bounds
clipMap->cmodels[0].leaf.firstCollAabbIndex = 0;
clipMap->cmodels[0].leaf.collAabbCount = 0;
clipMap->cmodels[0].leaf.brushContents = 0;
clipMap->cmodels[0].leaf.terrainContents = 0;
clipMap->cmodels[0].leaf.mins.x = 0.0f;
clipMap->cmodels[0].leaf.mins.y = 0.0f;
clipMap->cmodels[0].leaf.mins.z = 0.0f;
clipMap->cmodels[0].leaf.maxs.x = 0.0f;
clipMap->cmodels[0].leaf.maxs.y = 0.0f;
clipMap->cmodels[0].leaf.maxs.z = 0.0f;
clipMap->cmodels[0].leaf.leafBrushNode = 0;
clipMap->cmodels[0].leaf.cluster = 0;
clipMap->cmodels[0].info = nullptr;
for (size_t modelIdx = 0; modelIdx < bsp->models.size(); modelIdx++)
{
auto clipModel = &clipMap->cmodels[modelIdx + 1];
auto& bspModel = bsp->models.at(modelIdx);
if (bspModel.isGfxModel)
{
memset(clipModel, 0, sizeof(cmodel_t));
continue;
}
if (bspModel.surfaceCount != 0)
{
std::vector<int> partitionIndexes;
for (size_t surfIdx = 0; surfIdx < bspModel.surfaceCount; surfIdx++)
{
ColSurface& surf = collisionSurfaceVec.at(bsp->colWorld.staticSurfaces.size() + bspModel.surfaceIndex + surfIdx);
for (size_t partitionIdx = 0; partitionIdx < surf.partitionCount; partitionIdx++)
{
size_t clipMapPartitionIndex = surf.partitionStartIndex + partitionIdx;
partitionIndexes.emplace_back(clipMapPartitionIndex);
vec3_t mins;
vec3_t maxs;
calculatePartitionAABB(clipMap, &clipMap->partitions[clipMapPartitionIndex], mins, maxs);
if (surfIdx == 0 && partitionIdx == 0)
{
clipModel->mins = mins;
clipModel->maxs = maxs;
}
else
BSPUtil::updateAABB(mins, maxs, clipModel->mins, clipModel->maxs);
}
}
int terrainContents = 0;
size_t firstCollAabbIndex = 0;
size_t collAabbCount = 0;
addAABBTreeFromPartitions(clipMap, partitionIndexes, &collAabbCount, &firstCollAabbIndex, &terrainContents);
clipModel->leaf.terrainContents = terrainContents;
clipModel->leaf.firstCollAabbIndex = static_cast<uint16_t>(firstCollAabbIndex);
clipModel->leaf.collAabbCount = static_cast<uint16_t>(collAabbCount);
}
else
{
clipModel->leaf.terrainContents = 0;
clipModel->leaf.firstCollAabbIndex = 0;
clipModel->leaf.collAabbCount = 0;
}
if (bspModel.hasBrush)
{
BSPBoxBrush& bspBrush = bsp->colWorld.scriptBoxBrushes.at(bspModel.brushIndex);
vec3_t mins;
vec3_t maxs;
for (size_t vertIdx = 0; vertIdx < bspBrush.vertexCount; vertIdx++)
{
vec3_t* vertex = &clipMap->info.brushVerts[bspBrush.vertexIndex + vertIdx];
if (vertIdx == 0)
{
mins = *vertex;
maxs = *vertex;
}
else
BSPUtil::updateAABBWithPoint(*vertex, mins, maxs);
}
clipModel->leaf.mins = mins;
clipModel->leaf.maxs = maxs;
clipModel->leaf.brushContents = bspBrush.contentFlags;
clipModel->leaf.leafBrushNode = static_cast<int>(brushNodeVec.size());
assert(clipModel->leaf.leafBrushNode != 0);
cLeafBrushNode_s brushNode;
brushNode.axis = 0;
brushNode.contents = bspBrush.contentFlags;
brushNode.leafBrushCount = 1;
brushNode.data.leaf.brushes = m_memory.Alloc<LeafBrush>(1);
brushNode.data.leaf.brushes[0] = static_cast<unsigned short>(brushVec.size());
brushNodeVec.emplace_back(brushNode);
cbrush_array_t brush;
memset(&brush, 0, sizeof(cbrush_array_t)); // if not sides or verts are given, the mins/maxs are used instead
brush.numverts = static_cast<unsigned int>(bspBrush.vertexCount);
brush.verts = &clipMap->info.brushVerts[bspBrush.vertexIndex];
brush.contents = bspBrush.contentFlags;
brush.mins = mins;
brush.maxs = maxs;
brush.axial_cflags[0][0] = bspBrush.contentFlags;
brush.axial_cflags[0][1] = bspBrush.contentFlags;
brush.axial_cflags[0][2] = bspBrush.contentFlags;
brush.axial_cflags[1][0] = bspBrush.contentFlags;
brush.axial_cflags[1][1] = bspBrush.contentFlags;
brush.axial_cflags[1][2] = bspBrush.contentFlags;
brush.axial_sflags[0][0] = bspBrush.surfaceFlags;
brush.axial_sflags[0][1] = bspBrush.surfaceFlags;
brush.axial_sflags[0][2] = bspBrush.surfaceFlags;
brush.axial_sflags[1][0] = bspBrush.surfaceFlags;
brush.axial_sflags[1][1] = bspBrush.surfaceFlags;
brush.axial_sflags[1][2] = bspBrush.surfaceFlags;
brushVec.emplace_back(brush);
if (bspModel.surfaceCount != 0)
BSPUtil::updateAABB(mins, maxs, clipModel->mins, clipModel->maxs);
else
{
clipModel->mins = mins;
clipModel->maxs = maxs;
}
}
else
{
clipModel->leaf.brushContents = 0;
clipModel->leaf.mins.x = 0.0f;
clipModel->leaf.mins.y = 0.0f;
clipModel->leaf.mins.z = 0.0f;
clipModel->leaf.maxs.x = 0.0f;
clipModel->leaf.maxs.y = 0.0f;
clipModel->leaf.maxs.z = 0.0f;
clipModel->leaf.leafBrushNode = 0;
}
if (bspModel.surfaceCount == 0 && !bspModel.hasBrush)
{
clipModel->mins = {0.0f, 0.0f, 0.0f};
clipModel->maxs = {0.0f, 0.0f, 0.0f};
clipModel->radius = 0.0f;
}
else
clipModel->radius = BSPUtil::distBetweenPoints(clipModel->mins, clipModel->maxs) / 2;
clipModel->leaf.cluster = 0;
clipModel->info = nullptr;
}
}
bool ClipMapLinker::loadMaterials(clipMap_t* clipMap, BSPData* bsp) bool ClipMapLinker::loadMaterials(clipMap_t* clipMap, BSPData* bsp)
{ {
// 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)
@@ -4,6 +4,12 @@
#include <numbers> #include <numbers>
namespace
{
constexpr const char* DEFAULT_LIGHTDEF_NAME = "white_light";
constexpr short LIGHT_CULLDIST = 10000;
} // namespace
namespace BSP namespace BSP
{ {
ComWorldLinker::ComWorldLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context) ComWorldLinker::ComWorldLinker(MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context)
@@ -16,10 +22,10 @@ namespace BSP
bool ComWorldLinker::createLightDefs() bool ComWorldLinker::createLightDefs()
{ {
T6::GfxLightDef* lightDef2d = m_memory.Alloc<T6::GfxLightDef>(); T6::GfxLightDef* lightDef2d = m_memory.Alloc<T6::GfxLightDef>();
lightDef2d->name = m_memory.Dup("white_light"); lightDef2d->name = m_memory.Dup(DEFAULT_LIGHTDEF_NAME);
lightDef2d->lmapLookupStart = 0; // always 0 lightDef2d->lmapLookupStart = 0; // always 0
lightDef2d->attenuation.samplerState = 115; // always 115 lightDef2d->attenuation.samplerState = 115; // always 115
auto image2dAsset = m_context.LoadDependency<T6::AssetImage>("whitesquare"); auto image2dAsset = m_context.LoadDependency<T6::AssetImage>(",$white");
if (image2dAsset == nullptr) if (image2dAsset == nullptr)
return false; return false;
lightDef2d->attenuation.image = image2dAsset->Asset(); lightDef2d->attenuation.image = image2dAsset->Asset();
@@ -36,7 +42,7 @@ namespace BSP
comWorld->isInUse = 1; comWorld->isInUse = 1;
// first two lights are the empty light and the sun light. // first two lights are the empty light and the sun light.
size_t totalLightCount = bsp->lights.size() + BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT; size_t totalLightCount = bsp->lights.size() + BSP_DEFAULT_LIGHT_COUNT;
comWorld->primaryLightCount = static_cast<unsigned int>(totalLightCount); comWorld->primaryLightCount = static_cast<unsigned int>(totalLightCount);
comWorld->primaryLights = m_memory.Alloc<ComPrimaryLight>(totalLightCount); comWorld->primaryLights = m_memory.Alloc<ComPrimaryLight>(totalLightCount);
@@ -49,9 +55,9 @@ namespace BSP
for (size_t lightIdx = 0; lightIdx < totalLightCount; lightIdx++) for (size_t lightIdx = 0; lightIdx < totalLightCount; lightIdx++)
{ {
ComPrimaryLight* light = &comWorld->primaryLights[lightIdx]; ComPrimaryLight* light = &comWorld->primaryLights[lightIdx];
if (lightIdx == BSPGameConstants::EMPTY_LIGHT_INDEX) if (lightIdx == EMPTY_LIGHT_INDEX)
continue; // first (empty) light has no data continue; // first (empty) light has no data
else if (lightIdx == BSPGameConstants::SUN_LIGHT_INDEX) else if (lightIdx == SUN_LIGHT_INDEX)
{ {
BSPLight* bspLight = &bsp->sunlight; BSPLight* bspLight = &bsp->sunlight;
@@ -68,7 +74,7 @@ namespace BSP
} }
else else
{ {
BSPLight* bspLight = &bsp->lights.at(lightIdx - BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT); BSPLight* bspLight = &bsp->lights.at(lightIdx - BSP_DEFAULT_LIGHT_COUNT);
light->type = GFX_LIGHT_TYPE_SPOT; light->type = GFX_LIGHT_TYPE_SPOT;
@@ -103,8 +109,8 @@ namespace BSP
light->aAbB.z = 0.75f; light->aAbB.z = 0.75f;
light->aAbB.w = 1.0f; light->aAbB.w = 1.0f;
light->cullDist = 10000; light->cullDist = LIGHT_CULLDIST;
light->defName = "white_light"; light->defName = DEFAULT_LIGHTDEF_NAME;
light->rotationLimit = 1.0f; // 1.0f - doesn't rotate, -1.0f - unclamped rotation light->rotationLimit = 1.0f; // 1.0f - doesn't rotate, -1.0f - unclamped rotation
light->translationLimit = 0.0f; // 0.0f - doesn't translate, above 0.0f - distance per game update translated light->translationLimit = 0.0f; // 0.0f - doesn't translate, above 0.0f - distance per game update translated
light->roundness = 1.0f; // 0.0f - light is a square. 1.0f - light is a circle light->roundness = 1.0f; // 0.0f - light is a square. 1.0f - light is a circle
@@ -19,6 +19,12 @@ namespace
return result; return result;
} }
constexpr const char* DEFAULT_IMAGE_NAME = ",mc/lambert1";
constexpr char EMPTY_LIGHTMAP_INDEX = 0;
constexpr char EMPTY_RPROBE_INDEX = 0;
constexpr float XMODEL_CULL_DIST = 10000.0f;
constexpr char DEFAULT_LIGHTGRID_COLOUR = 32;
} // namespace } // namespace
namespace BSP namespace BSP
@@ -99,12 +105,12 @@ namespace BSP
if (bspMaterial.materialType == MATERIAL_TYPE_TEXTURE) if (bspMaterial.materialType == MATERIAL_TYPE_TEXTURE)
materialName = bspMaterial.materialName; materialName = bspMaterial.materialName;
else // MATERIAL_TYPE_COLOUR else // MATERIAL_TYPE_COLOUR
materialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME; materialName = DEFAULT_IMAGE_NAME;
auto surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(materialName); auto surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(materialName);
if (surfMaterialAsset == nullptr) if (surfMaterialAsset == nullptr)
{ {
surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(BSPLinkingConstants::MISSING_IMAGE_NAME); surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(DEFAULT_IMAGE_NAME);
assert(surfMaterialAsset != nullptr); assert(surfMaterialAsset != nullptr);
} }
gfxSurface->material = surfMaterialAsset->Asset(); gfxSurface->material = surfMaterialAsset->Asset();
@@ -138,9 +144,9 @@ namespace BSP
if ((bspMaterial.surfaceFlags & BSPFlags::surfaceTypeToFlagMap[BSPFlags::SURF_TYPE_NOCASTSHADOW].surfaceFlags) == 0) if ((bspMaterial.surfaceFlags & BSPFlags::surfaceTypeToFlagMap[BSPFlags::SURF_TYPE_NOCASTSHADOW].surfaceFlags) == 0)
gfxSurface->flags |= GFX_SURFACE_CASTS_SHADOW; gfxSurface->flags |= GFX_SURFACE_CASTS_SHADOW;
gfxSurface->primaryLightIndex = BSPEditableConstants::DEFAULT_SURFACE_LIGHT; gfxSurface->primaryLightIndex = SUN_LIGHT_INDEX;
gfxSurface->lightmapIndex = BSPEditableConstants::DEFAULT_SURFACE_LIGHTMAP; gfxSurface->lightmapIndex = EMPTY_LIGHTMAP_INDEX;
gfxSurface->reflectionProbeIndex = BSPEditableConstants::DEFAULT_SURFACE_REFLECTION_PROBE; gfxSurface->reflectionProbeIndex = EMPTY_RPROBE_INDEX;
// unknown value // unknown value
gfxSurface->tris.himipRadiusInvSq = 0.0f; gfxSurface->tris.himipRadiusInvSq = 0.0f;
@@ -210,9 +216,9 @@ namespace BSP
if (!bspModel.doesCastShadow) if (!bspModel.doesCastShadow)
currModel->flags |= STATIC_MODEL_FLAG_NO_SHADOW; currModel->flags |= STATIC_MODEL_FLAG_NO_SHADOW;
currModel->cullDist = 10000.0f; currModel->cullDist = XMODEL_CULL_DIST;
currModel->primaryLightIndex = 1; currModel->primaryLightIndex = SUN_LIGHT_INDEX;
currModel->reflectionProbeIndex = 0; currModel->reflectionProbeIndex = EMPTY_LIGHTMAP_INDEX;
currModel->smid = modelIdx; currModel->smid = modelIdx;
// unknown use / unused // unknown use / unused
@@ -392,8 +398,8 @@ namespace BSP
void GfxWorldLinker::loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld) void GfxWorldLinker::loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld)
{ {
// 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 + static_cast<unsigned int>(bsp->lights.size()); gfxWorld->primaryLightCount = BSP_DEFAULT_LIGHT_COUNT + static_cast<unsigned int>(bsp->lights.size());
gfxWorld->sunPrimaryLightIndex = BSPGameConstants::SUN_LIGHT_INDEX; gfxWorld->sunPrimaryLightIndex = SUN_LIGHT_INDEX;
gfxWorld->shadowGeom = m_memory.Alloc<GfxShadowGeometry>(gfxWorld->primaryLightCount); gfxWorld->shadowGeom = m_memory.Alloc<GfxShadowGeometry>(gfxWorld->primaryLightCount);
for (unsigned int lightIdx = 0; lightIdx < gfxWorld->primaryLightCount; lightIdx++) for (unsigned int lightIdx = 0; lightIdx < gfxWorld->primaryLightCount; lightIdx++)
@@ -446,7 +452,7 @@ namespace BSP
gfxWorld->lightGrid.rowAxis = 0; // default value gfxWorld->lightGrid.rowAxis = 0; // default value
gfxWorld->lightGrid.colAxis = 1; // default value gfxWorld->lightGrid.colAxis = 1; // default value
gfxWorld->lightGrid.sunPrimaryLightIndex = BSPGameConstants::SUN_LIGHT_INDEX; gfxWorld->lightGrid.sunPrimaryLightIndex = SUN_LIGHT_INDEX;
gfxWorld->lightGrid.offset = 0.0f; // default value gfxWorld->lightGrid.offset = 0.0f; // default value
// setting all rowDataStart indexes to 0 will always index the first row in rawRowData // setting all rowDataStart indexes to 0 will always index the first row in rawRowData
@@ -471,12 +477,12 @@ namespace BSP
for (unsigned int i = 0; i < gfxWorld->lightGrid.entryCount; i++) for (unsigned int i = 0; i < gfxWorld->lightGrid.entryCount; i++)
{ {
entryArray[i].colorsIndex = 0; // always index first colour entryArray[i].colorsIndex = 0; // always index first colour
entryArray[i].primaryLightIndex = BSPGameConstants::SUN_LIGHT_INDEX; entryArray[i].primaryLightIndex = SUN_LIGHT_INDEX;
entryArray[i].visibility = 0; entryArray[i].visibility = 0;
} }
gfxWorld->lightGrid.entries = entryArray; gfxWorld->lightGrid.entries = entryArray;
char color = 32; char color = DEFAULT_LIGHTGRID_COLOUR;
float sunIntensity = bsp->sunlight.intensity; float sunIntensity = bsp->sunlight.intensity;
if (sunIntensity < 0.0f || sunIntensity > 20000.0f) if (sunIntensity < 0.0f || sunIntensity > 20000.0f)
con::warn("Sun intensity ({}) needs to be between 0 and 20000", sunIntensity); con::warn("Sun intensity ({}) needs to be between 0 and 20000", sunIntensity);
@@ -534,7 +540,7 @@ namespace BSP
// there is only 1 reflection probe // there is only 1 reflection probe
gfxWorld->cells[0].reflectionProbeCount = 1; gfxWorld->cells[0].reflectionProbeCount = 1;
gfxWorld->cells[0].reflectionProbes = m_memory.Alloc<char>(gfxWorld->cells[0].reflectionProbeCount); gfxWorld->cells[0].reflectionProbes = m_memory.Alloc<char>(gfxWorld->cells[0].reflectionProbeCount);
gfxWorld->cells[0].reflectionProbes[0] = BSPEditableConstants::DEFAULT_SURFACE_REFLECTION_PROBE; gfxWorld->cells[0].reflectionProbes[0] = EMPTY_RPROBE_INDEX;
// AABB trees are used to detect what should be rendered and what shouldn't // AABB trees are used to detect what should be rendered and what shouldn't
// Just use the first AABB node to hold all models, no optimisation but all models/surfaces wil lbe drawn // Just use the first AABB node to hold all models, no optimisation but all models/surfaces wil lbe drawn