mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-06-06 08:42:35 +00:00
chore: added many bound checks to prevent integer overflows and game imposed limits, beautified code, added comments where logic wasn't very obvious.
This commit is contained in:
@@ -272,6 +272,8 @@ namespace
|
|||||||
const auto faceCount = indexCount / 3u;
|
const auto faceCount = indexCount / 3u;
|
||||||
if (faceCount > UINT16_MAX)
|
if (faceCount > UINT16_MAX)
|
||||||
throw GltfLoadException(std::format("Face count ({}) on node {} exceeded the UINT16_MAX", faceCount, node.name.value_or("unnamed node")));
|
throw GltfLoadException(std::format("Face count ({}) on node {} exceeded the UINT16_MAX", faceCount, node.name.value_or("unnamed node")));
|
||||||
|
if (vertexCount > UINT16_MAX)
|
||||||
|
throw GltfLoadException(std::format("Vertex count ({}) on node {} exceeded the UINT16_MAX", vertexCount, node.name.value_or("unnamed node")));
|
||||||
|
|
||||||
out_surface.vertexCount = static_cast<uint16_t>(vertexCount);
|
out_surface.vertexCount = static_cast<uint16_t>(vertexCount);
|
||||||
out_surface.triCount = static_cast<uint16_t>(faceCount);
|
out_surface.triCount = static_cast<uint16_t>(faceCount);
|
||||||
@@ -1013,17 +1015,17 @@ namespace
|
|||||||
return addXModelNode(jRoot, node, nodeMatrix);
|
return addXModelNode(jRoot, node, nodeMatrix);
|
||||||
|
|
||||||
if (hasSpawnpoint)
|
if (hasSpawnpoint)
|
||||||
return addSpawnPointNode(node, nodeMatrix);
|
return addSpawnPointNode(node, nodeMatrix);
|
||||||
|
|
||||||
if (m_bsp->isZombiesMap)
|
if (m_bsp->isZombiesMap)
|
||||||
{
|
{
|
||||||
if (hasZone)
|
if (hasZone)
|
||||||
return addZoneNode(jRoot, node, nodeMatrix);
|
return addZoneNode(jRoot, node, nodeMatrix);
|
||||||
|
|
||||||
if (hasSpawner)
|
if (hasSpawner)
|
||||||
return addZSpawnerNode(node, nodeMatrix);
|
return addZSpawnerNode(node, nodeMatrix);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (node.mesh)
|
if (node.mesh)
|
||||||
{
|
{
|
||||||
@@ -1036,7 +1038,7 @@ namespace
|
|||||||
if (m_is_world_gfx && isNoDraw)
|
if (m_is_world_gfx && isNoDraw)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return addMeshNode(jRoot, node, nodeMatrix);
|
return addMeshNode(jRoot, node, nodeMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1354,6 +1356,7 @@ namespace BSP
|
|||||||
bsp->containsWorldspawn = false;
|
bsp->containsWorldspawn = false;
|
||||||
|
|
||||||
con::warn("XModels don't support scale currently, keep it at 1 in your editor");
|
con::warn("XModels don't support scale currently, keep it at 1 in your editor");
|
||||||
|
con::warn("All brushmodels, zones, triggers, and info_volumes must be an axis aligned box with 6 sides to work correctly.");
|
||||||
|
|
||||||
BSPLoader loader(bsp.get());
|
BSPLoader loader(bsp.get());
|
||||||
if (isGfxFileGltf)
|
if (isGfxFileGltf)
|
||||||
@@ -1411,7 +1414,6 @@ namespace BSP
|
|||||||
bsp->sunlight.innerConeAngle = 0.0f;
|
bsp->sunlight.innerConeAngle = 0.0f;
|
||||||
bsp->sunlight.outerConeAngle = 0.0f;
|
bsp->sunlight.outerConeAngle = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bsp->containsIntermssion)
|
if (!bsp->containsIntermssion)
|
||||||
{
|
{
|
||||||
con::error("Map does not contain a mp_global_intermission class");
|
con::error("Map does not contain a mp_global_intermission class");
|
||||||
@@ -1422,6 +1424,23 @@ namespace BSP
|
|||||||
con::error("Map does not contain a worldspawn class");
|
con::error("Map does not contain a worldspawn class");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (bsp->spawnpoints.size() == 0)
|
||||||
|
{
|
||||||
|
con::error("Map must have spawn points!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (bsp->gfxWorld.staticSurfaces.size() + bsp->gfxWorld.scriptSurfaces.size() == 0 || bsp->gfxWorld.vertices.size() == 0
|
||||||
|
|| bsp->gfxWorld.indices.size() == 0)
|
||||||
|
{
|
||||||
|
con::error("GFX world has no surfaces, indicies or vertices!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (bsp->colWorld.staticSurfaces.size() + bsp->colWorld.scriptSurfaces.size() == 0 || bsp->colWorld.vertices.size() == 0
|
||||||
|
|| bsp->colWorld.indices.size() == 0)
|
||||||
|
{
|
||||||
|
con::error("Collision world has no surfaces, indicies or vertices!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return bsp;
|
return bsp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,18 +26,23 @@ namespace BSP
|
|||||||
bool BSPLinker::addDefaultRequiredAssets(BSPData* bsp)
|
bool BSPLinker::addDefaultRequiredAssets(BSPData* bsp)
|
||||||
{
|
{
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/" + bsp->name + ".gsc") == nullptr)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/" + bsp->name + ".gsc") == nullptr)
|
||||||
return false;
|
{
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/" + bsp->name + "_amb.gsc") == nullptr)
|
con::error("maps/mp/" + bsp->name + ".gsc not found, make sure GSC file is in another fastfile.");
|
||||||
return false;
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/" + bsp->name + "_fx.gsc") == nullptr)
|
else
|
||||||
return false;
|
{
|
||||||
|
if (m_context.LoadDependency<AssetScript>("maps/mp/" + bsp->name + "_amb.gsc") == nullptr)
|
||||||
|
return false;
|
||||||
|
if (m_context.LoadDependency<AssetScript>("maps/mp/" + bsp->name + "_fx.gsc") == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + bsp->name + ".csc") == nullptr)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + bsp->name + ".csc") == nullptr)
|
||||||
return false;
|
return false;
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + bsp->name + "_amb.csc") == nullptr)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + bsp->name + "_amb.csc") == nullptr)
|
||||||
return false;
|
return false;
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + bsp->name + "_fx.csc") == nullptr)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + bsp->name + "_fx.csc") == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
addEmptyFootstepTableAsset("default_1st_person");
|
addEmptyFootstepTableAsset("default_1st_person");
|
||||||
addEmptyFootstepTableAsset("default_3rd_person");
|
addEmptyFootstepTableAsset("default_3rd_person");
|
||||||
@@ -91,12 +96,12 @@ namespace BSP
|
|||||||
return false;
|
return false;
|
||||||
m_context.AddAsset<AssetSkinnedVerts>(skinnedVerts->name, skinnedVerts);
|
m_context.AddAsset<AssetSkinnedVerts>(skinnedVerts->name, skinnedVerts);
|
||||||
|
|
||||||
GfxWorld* gfxWorld = gfxWorldLinker.linkGfxWorld(bsp); // requires mapents asset
|
GfxWorld* gfxWorld = gfxWorldLinker.linkGfxWorld(bsp);
|
||||||
if (gfxWorld == nullptr)
|
if (gfxWorld == nullptr)
|
||||||
return false;
|
return false;
|
||||||
m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld);
|
m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld);
|
||||||
|
|
||||||
clipMap_t* clipMap = clipMapLinker.linkClipMap(bsp); // requires gfxworld and mapents asset
|
clipMap_t* clipMap = clipMapLinker.linkClipMap(bsp); // requires 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);
|
||||||
|
|||||||
@@ -134,12 +134,20 @@ namespace BSP
|
|||||||
bool ClipMapLinker::loadXModelCollision(clipMap_t* clipMap, BSPData* bsp)
|
bool ClipMapLinker::loadXModelCollision(clipMap_t* clipMap, BSPData* bsp)
|
||||||
{
|
{
|
||||||
// it seems like for players to be able to collide with xmodels, it requires xmodel->collmaps to be valid.
|
// it seems like for players to be able to collide with xmodels, it requires xmodel->collmaps to be valid.
|
||||||
// A lot of XModels don't implement collmaps (OAT also doesn't generate these collmaps), and
|
// A lot of XModels don't implement collmaps (OAT also doesn't generate these collmaps atm), and
|
||||||
// even official maps instead use terrain or brushes to cover where the collision should be.
|
// even official maps instead use terrain or brushes to cover where the collision should be.
|
||||||
|
|
||||||
clipMap->numStaticModels = bsp->colWorld.xmodels.size();
|
clipMap->numStaticModels = bsp->colWorld.xmodels.size();
|
||||||
clipMap->staticModelList = m_memory.Alloc<cStaticModel_s>(clipMap->numStaticModels);
|
clipMap->staticModelList = m_memory.Alloc<cStaticModel_s>(clipMap->numStaticModels);
|
||||||
|
|
||||||
|
if (clipMap->numStaticModels == 0)
|
||||||
|
return true;
|
||||||
|
if (clipMap->numStaticModels > 0xFFFF)
|
||||||
|
{
|
||||||
|
con::error("COLWorld exceeded the maximum number of static xmodels (65535 max, map count: {})", clipMap->numStaticModels);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < clipMap->numStaticModels; i++)
|
for (unsigned int i = 0; i < clipMap->numStaticModels; i++)
|
||||||
{
|
{
|
||||||
cStaticModel_s* currModel = &clipMap->staticModelList[i];
|
cStaticModel_s* currModel = &clipMap->staticModelList[i];
|
||||||
@@ -386,12 +394,8 @@ namespace BSP
|
|||||||
|
|
||||||
// no brushes used so data is set to 0
|
// no brushes used so data is set to 0
|
||||||
leaf.brushContents = 0;
|
leaf.brushContents = 0;
|
||||||
leaf.mins.x = 0.0f;
|
leaf.mins = {};
|
||||||
leaf.mins.y = 0.0f;
|
leaf.maxs = {};
|
||||||
leaf.mins.z = 0.0f;
|
|
||||||
leaf.maxs.x = 0.0f;
|
|
||||||
leaf.maxs.y = 0.0f;
|
|
||||||
leaf.maxs.z = 0.0f;
|
|
||||||
leaf.leafBrushNode = 0;
|
leaf.leafBrushNode = 0;
|
||||||
|
|
||||||
if (tree->leaf->getObjectCount() > 0)
|
if (tree->leaf->getObjectCount() > 0)
|
||||||
@@ -527,8 +531,6 @@ namespace BSP
|
|||||||
size_t scriptSurfaceCount = bsp->colWorld.scriptSurfaces.size();
|
size_t scriptSurfaceCount = bsp->colWorld.scriptSurfaces.size();
|
||||||
size_t totalSurfaceCount = staticSurfaceCount + scriptSurfaceCount;
|
size_t totalSurfaceCount = staticSurfaceCount + scriptSurfaceCount;
|
||||||
|
|
||||||
// TODO: figure out SV_EntityContact and see how it interacts with partitions
|
|
||||||
|
|
||||||
std::vector<uint16_t> triIndexVec;
|
std::vector<uint16_t> triIndexVec;
|
||||||
std::vector<CollisionPartition> partitionVec;
|
std::vector<CollisionPartition> partitionVec;
|
||||||
std::vector<uint16_t> uniqueIndicesVec;
|
std::vector<uint16_t> uniqueIndicesVec;
|
||||||
@@ -598,71 +600,17 @@ namespace BSP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClipMapLinker::loadWorldCollision(clipMap_t* clipMap, BSPData* bsp)
|
bool ClipMapLinker::loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp)
|
||||||
{
|
|
||||||
// No support for brushes, only tris right now
|
|
||||||
clipMap->info.numBrushSides = 0;
|
|
||||||
clipMap->info.brushsides = nullptr;
|
|
||||||
clipMap->info.numLeafBrushes = 0;
|
|
||||||
clipMap->info.leafbrushes = nullptr;
|
|
||||||
clipMap->info.brushBounds = nullptr;
|
|
||||||
clipMap->info.brushContents = nullptr;
|
|
||||||
|
|
||||||
// first brush node is always empty
|
|
||||||
cLeafBrushNode_s tempNode;
|
|
||||||
memset(&tempNode, 0, sizeof(cLeafBrushNode_s));
|
|
||||||
brushNodeVec.emplace_back(tempNode);
|
|
||||||
|
|
||||||
clipMap->info.numBrushVerts = static_cast<uint16_t>(bsp->colWorld.boxBrushVerts.size());
|
|
||||||
clipMap->info.brushVerts = m_memory.Alloc<vec3_t>(bsp->colWorld.boxBrushVerts.size());
|
|
||||||
memcpy(clipMap->info.brushVerts, bsp->colWorld.boxBrushVerts.data(), sizeof(vec3_t) * bsp->colWorld.boxBrushVerts.size());
|
|
||||||
|
|
||||||
// load verts, tris, uinds and partitions
|
|
||||||
if (!loadPartitions(clipMap, bsp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!loadBSPTree(clipMap, bsp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
loadSubModelCollision(clipMap, bsp); // requires tri verts
|
|
||||||
|
|
||||||
clipMap->info.planeCount = static_cast<int>(planeVec.size());
|
|
||||||
clipMap->info.planes = m_memory.Alloc<cplane_s>(planeVec.size());
|
|
||||||
memcpy(clipMap->info.planes, planeVec.data(), sizeof(cplane_s) * planeVec.size());
|
|
||||||
|
|
||||||
clipMap->numNodes = static_cast<unsigned int>(nodeVec.size());
|
|
||||||
clipMap->nodes = m_memory.Alloc<cNode_t>(nodeVec.size());
|
|
||||||
memcpy(clipMap->nodes, nodeVec.data(), sizeof(cNode_t) * nodeVec.size());
|
|
||||||
|
|
||||||
clipMap->numLeafs = static_cast<unsigned int>(leafVec.size());
|
|
||||||
clipMap->leafs = m_memory.Alloc<cLeaf_s>(leafVec.size());
|
|
||||||
memcpy(clipMap->leafs, leafVec.data(), sizeof(cLeaf_s) * leafVec.size());
|
|
||||||
|
|
||||||
clipMap->aabbTreeCount = static_cast<unsigned int>(AABBTreeVec.size());
|
|
||||||
clipMap->aabbTrees = m_memory.Alloc<CollisionAabbTree>(AABBTreeVec.size());
|
|
||||||
memcpy(clipMap->aabbTrees, AABBTreeVec.data(), sizeof(CollisionAabbTree) * AABBTreeVec.size());
|
|
||||||
|
|
||||||
clipMap->info.leafbrushNodesCount = static_cast<unsigned int>(brushNodeVec.size());
|
|
||||||
clipMap->info.leafbrushNodes = m_memory.Alloc<cLeafBrushNode_s>(brushNodeVec.size());
|
|
||||||
memcpy(clipMap->info.leafbrushNodes, brushNodeVec.data(), sizeof(cLeafBrushNode_s) * brushNodeVec.size());
|
|
||||||
|
|
||||||
clipMap->info.numBrushes = static_cast<uint16_t>(brushVec.size());
|
|
||||||
clipMap->info.brushes = m_memory.Alloc<cbrush_array_t>(brushVec.size());
|
|
||||||
memcpy(clipMap->info.brushes, brushVec.data(), sizeof(cbrush_array_t) * brushVec.size());
|
|
||||||
|
|
||||||
// The plane of each node have the same index
|
|
||||||
for (size_t nodeIdx = 0; nodeIdx < nodeVec.size(); nodeIdx++)
|
|
||||||
clipMap->nodes[nodeIdx].plane = &clipMap->info.planes[nodeIdx];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipMapLinker::loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp)
|
|
||||||
{
|
{
|
||||||
// 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)
|
||||||
clipMap->numSubModels = static_cast<unsigned int>(bsp->models.size() + 1);
|
clipMap->numSubModels = static_cast<unsigned int>(bsp->models.size() + 1);
|
||||||
clipMap->cmodels = m_memory.Alloc<cmodel_t>(clipMap->numSubModels);
|
clipMap->cmodels = m_memory.Alloc<cmodel_t>(clipMap->numSubModels);
|
||||||
|
|
||||||
|
if (clipMap->numSubModels > 0x3FFF)
|
||||||
|
{
|
||||||
|
con::error("ERROR: There are more than 0x3FFF entity brushmodels.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// first model is always the world model
|
// first model is always the world model
|
||||||
for (unsigned int vertIdx = 0; vertIdx < clipMap->vertCount; vertIdx++)
|
for (unsigned int vertIdx = 0; vertIdx < clipMap->vertCount; vertIdx++)
|
||||||
{
|
{
|
||||||
@@ -742,10 +690,9 @@ namespace BSP
|
|||||||
|
|
||||||
if (bspModel.hasBrush)
|
if (bspModel.hasBrush)
|
||||||
{
|
{
|
||||||
|
|
||||||
BSPBoxBrush& bspBrush = bsp->colWorld.scriptBoxBrushes.at(bspModel.brushIndex);
|
BSPBoxBrush& bspBrush = bsp->colWorld.scriptBoxBrushes.at(bspModel.brushIndex);
|
||||||
vec3_t mins;
|
vec3_t mins = {};
|
||||||
vec3_t maxs;
|
vec3_t maxs = {};
|
||||||
for (size_t vertIdx = 0; vertIdx < bspBrush.vertexCount; vertIdx++)
|
for (size_t vertIdx = 0; vertIdx < bspBrush.vertexCount; vertIdx++)
|
||||||
{
|
{
|
||||||
vec3_t* vertex = &clipMap->info.brushVerts[bspBrush.vertexIndex + vertIdx];
|
vec3_t* vertex = &clipMap->info.brushVerts[bspBrush.vertexIndex + vertIdx];
|
||||||
@@ -824,6 +771,89 @@ namespace BSP
|
|||||||
clipModel->leaf.cluster = 0;
|
clipModel->leaf.cluster = 0;
|
||||||
clipModel->info = nullptr;
|
clipModel->info = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClipMapLinker::loadWorldCollision(clipMap_t* clipMap, BSPData* bsp)
|
||||||
|
{
|
||||||
|
// unused brush data
|
||||||
|
clipMap->info.numBrushSides = 0;
|
||||||
|
clipMap->info.brushsides = nullptr;
|
||||||
|
clipMap->info.numLeafBrushes = 0;
|
||||||
|
clipMap->info.leafbrushes = nullptr;
|
||||||
|
clipMap->info.brushBounds = nullptr;
|
||||||
|
clipMap->info.brushContents = nullptr;
|
||||||
|
|
||||||
|
// first brush node is always empty
|
||||||
|
cLeafBrushNode_s tempNode;
|
||||||
|
memset(&tempNode, 0, sizeof(cLeafBrushNode_s));
|
||||||
|
brushNodeVec.emplace_back(tempNode);
|
||||||
|
|
||||||
|
clipMap->info.numBrushVerts = static_cast<uint16_t>(bsp->colWorld.boxBrushVerts.size());
|
||||||
|
clipMap->info.brushVerts = m_memory.Alloc<vec3_t>(bsp->colWorld.boxBrushVerts.size());
|
||||||
|
memcpy(clipMap->info.brushVerts, bsp->colWorld.boxBrushVerts.data(), sizeof(vec3_t) * bsp->colWorld.boxBrushVerts.size());
|
||||||
|
|
||||||
|
// load verts, tris, uinds and partitions
|
||||||
|
if (!loadPartitions(clipMap, bsp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!loadBSPTree(clipMap, bsp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!loadSubModelCollision(clipMap, bsp)) // requires tri verts
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (nodeVec.size() > 0xFFFF)
|
||||||
|
{
|
||||||
|
con::error("exceeded 0xFFFF nodes in clipmap");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (leafVec.size() > 0xFFFF)
|
||||||
|
{
|
||||||
|
con::error("exceeded 0xFFFF leafs in clipmap");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (AABBTreeVec.size() > 0xFFFF)
|
||||||
|
{
|
||||||
|
con::error("exceeded 0xFFFF AABBTrees in clipmap");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (brushVec.size() > 0xFFFF)
|
||||||
|
{
|
||||||
|
con::error("exceeded 0xFFFF brushes in clipmap");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clipMap->info.planeCount = static_cast<int>(planeVec.size());
|
||||||
|
clipMap->info.planes = m_memory.Alloc<cplane_s>(planeVec.size());
|
||||||
|
memcpy(clipMap->info.planes, planeVec.data(), sizeof(cplane_s) * planeVec.size());
|
||||||
|
|
||||||
|
clipMap->numNodes = static_cast<unsigned int>(nodeVec.size());
|
||||||
|
clipMap->nodes = m_memory.Alloc<cNode_t>(nodeVec.size());
|
||||||
|
memcpy(clipMap->nodes, nodeVec.data(), sizeof(cNode_t) * nodeVec.size());
|
||||||
|
|
||||||
|
clipMap->numLeafs = static_cast<unsigned int>(leafVec.size());
|
||||||
|
clipMap->leafs = m_memory.Alloc<cLeaf_s>(leafVec.size());
|
||||||
|
memcpy(clipMap->leafs, leafVec.data(), sizeof(cLeaf_s) * leafVec.size());
|
||||||
|
|
||||||
|
clipMap->aabbTreeCount = static_cast<unsigned int>(AABBTreeVec.size());
|
||||||
|
clipMap->aabbTrees = m_memory.Alloc<CollisionAabbTree>(AABBTreeVec.size());
|
||||||
|
memcpy(clipMap->aabbTrees, AABBTreeVec.data(), sizeof(CollisionAabbTree) * AABBTreeVec.size());
|
||||||
|
|
||||||
|
clipMap->info.leafbrushNodesCount = static_cast<unsigned int>(brushNodeVec.size());
|
||||||
|
clipMap->info.leafbrushNodes = m_memory.Alloc<cLeafBrushNode_s>(brushNodeVec.size());
|
||||||
|
memcpy(clipMap->info.leafbrushNodes, brushNodeVec.data(), sizeof(cLeafBrushNode_s) * brushNodeVec.size());
|
||||||
|
|
||||||
|
clipMap->info.numBrushes = static_cast<uint16_t>(brushVec.size());
|
||||||
|
clipMap->info.brushes = m_memory.Alloc<cbrush_array_t>(brushVec.size());
|
||||||
|
memcpy(clipMap->info.brushes, brushVec.data(), sizeof(cbrush_array_t) * brushVec.size());
|
||||||
|
|
||||||
|
// The plane of each node have the same index
|
||||||
|
for (size_t nodeIdx = 0; nodeIdx < nodeVec.size(); nodeIdx++)
|
||||||
|
clipMap->nodes[nodeIdx].plane = &clipMap->info.planes[nodeIdx];
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClipMapLinker::loadMaterials(clipMap_t* clipMap, BSPData* bsp)
|
bool ClipMapLinker::loadMaterials(clipMap_t* clipMap, BSPData* bsp)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace BSP
|
|||||||
void loadVisibility(clipMap_t* clipMap);
|
void loadVisibility(clipMap_t* clipMap);
|
||||||
void loadDynEnts(clipMap_t* clipMap);
|
void loadDynEnts(clipMap_t* clipMap);
|
||||||
void loadRopesAndConstraints(clipMap_t* clipMap);
|
void loadRopesAndConstraints(clipMap_t* clipMap);
|
||||||
void loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp);
|
bool loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp);
|
||||||
bool loadXModelCollision(clipMap_t* clipMap, BSPData* bsp);
|
bool loadXModelCollision(clipMap_t* clipMap, BSPData* bsp);
|
||||||
|
|
||||||
std::vector<cplane_s> planeVec;
|
std::vector<cplane_s> planeVec;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "ComWorldLinker.h"
|
#include "ComWorldLinker.h"
|
||||||
|
|
||||||
#include "../BSPUtil.h"
|
|
||||||
|
|
||||||
#include <numbers>
|
#include <numbers>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -36,7 +34,6 @@ namespace BSP
|
|||||||
|
|
||||||
ComWorld* ComWorldLinker::linkComWorld(BSPData* bsp)
|
ComWorld* ComWorldLinker::linkComWorld(BSPData* bsp)
|
||||||
{
|
{
|
||||||
// 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;
|
||||||
@@ -110,11 +107,11 @@ namespace BSP
|
|||||||
light->aAbB.w = 1.0f;
|
light->aAbB.w = 1.0f;
|
||||||
|
|
||||||
light->cullDist = LIGHT_CULLDIST;
|
light->cullDist = LIGHT_CULLDIST;
|
||||||
light->defName = DEFAULT_LIGHTDEF_NAME;
|
light->defName = DEFAULT_LIGHTDEF_NAME; // all lights that aren't the sunlight or default light need their own GfxLightDef asset
|
||||||
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
|
||||||
light->canUseShadowMap = 1; // light does not show up with this set to 0
|
light->canUseShadowMap = 1; // light does not show up with this set to 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const char* DEFAULT_IMAGE_NAME = ",mc/lambert1";
|
constexpr const char* DEFAULT_IMAGE_NAME = ",mc/lambert1";
|
||||||
constexpr char EMPTY_LIGHTMAP_INDEX = 0;
|
constexpr char DEFAULT_PRIMARYLIGHT_INDEX = 1; // max 254
|
||||||
constexpr char EMPTY_RPROBE_INDEX = 0;
|
constexpr char DEFAULT_LIGHTMAP_INDEX = 0; // max 30
|
||||||
|
constexpr char DEFAULT_RPROBE_INDEX = 0; // max 254
|
||||||
constexpr float XMODEL_CULL_DIST = 10000.0f;
|
constexpr float XMODEL_CULL_DIST = 10000.0f;
|
||||||
constexpr char DEFAULT_LIGHTGRID_COLOUR = 32;
|
constexpr char DEFAULT_LIGHTGRID_COLOUR = 32;
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -65,7 +66,7 @@ namespace BSP
|
|||||||
size_t indexCount = bsp->gfxWorld.indices.size();
|
size_t indexCount = bsp->gfxWorld.indices.size();
|
||||||
assert(indexCount % 3 == 0);
|
assert(indexCount % 3 == 0);
|
||||||
gfxWorld->draw.indexCount = static_cast<int>(indexCount);
|
gfxWorld->draw.indexCount = static_cast<int>(indexCount);
|
||||||
gfxWorld->draw.indices = m_memory.Alloc<uint16_t>(indexCount);
|
gfxWorld->draw.indices = m_memory.Alloc<uint16_t>(indexCount); // overflow checked in bspcreator
|
||||||
static_assert(sizeof(bsp->gfxWorld.indices.data()[0]) == sizeof(uint16_t));
|
static_assert(sizeof(bsp->gfxWorld.indices.data()[0]) == sizeof(uint16_t));
|
||||||
memcpy(gfxWorld->draw.indices, bsp->gfxWorld.indices.data(), sizeof(uint16_t) * indexCount);
|
memcpy(gfxWorld->draw.indices, bsp->gfxWorld.indices.data(), sizeof(uint16_t) * indexCount);
|
||||||
}
|
}
|
||||||
@@ -78,6 +79,12 @@ namespace BSP
|
|||||||
size_t scriptSurfaceCount = bsp->gfxWorld.scriptSurfaces.size();
|
size_t scriptSurfaceCount = bsp->gfxWorld.scriptSurfaces.size();
|
||||||
size_t totalSurfaceCount = staticSurfaceCount + scriptSurfaceCount;
|
size_t totalSurfaceCount = staticSurfaceCount + scriptSurfaceCount;
|
||||||
|
|
||||||
|
if (staticSurfaceCount > 0xffff)
|
||||||
|
{
|
||||||
|
con::error("There are more than 65535 Static surfaces. count: {}", staticSurfaceCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Static surfaces go first in the array then script surfaces after
|
// Static surfaces go first in the array then script surfaces after
|
||||||
gfxWorld->surfaceCount = static_cast<int>(totalSurfaceCount);
|
gfxWorld->surfaceCount = static_cast<int>(totalSurfaceCount);
|
||||||
gfxWorld->dpvs.staticSurfaceCount = static_cast<unsigned int>(staticSurfaceCount);
|
gfxWorld->dpvs.staticSurfaceCount = static_cast<unsigned int>(staticSurfaceCount);
|
||||||
@@ -91,9 +98,9 @@ namespace BSP
|
|||||||
bspSurface = bsp->gfxWorld.scriptSurfaces.at(surfIdx - staticSurfaceCount);
|
bspSurface = bsp->gfxWorld.scriptSurfaces.at(surfIdx - staticSurfaceCount);
|
||||||
GfxSurface* gfxSurface = &gfxWorld->dpvs.surfaces[surfIdx];
|
GfxSurface* gfxSurface = &gfxWorld->dpvs.surfaces[surfIdx];
|
||||||
|
|
||||||
gfxSurface->tris.triCount = bspSurface.triCount;
|
gfxSurface->tris.triCount = bspSurface.triCount; // overflow checked in bspcreator
|
||||||
gfxSurface->tris.baseIndex = bspSurface.indexOfFirstIndex;
|
gfxSurface->tris.baseIndex = bspSurface.indexOfFirstIndex;
|
||||||
gfxSurface->tris.vertexCount = bspSurface.vertexCount;
|
gfxSurface->tris.vertexCount = bspSurface.vertexCount; // overflow checked in bspcreator
|
||||||
gfxSurface->tris.firstVertex = bspSurface.indexOfFirstVertex;
|
gfxSurface->tris.firstVertex = bspSurface.indexOfFirstVertex;
|
||||||
|
|
||||||
gfxSurface->tris.vertexDataOffset0 = bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex);
|
gfxSurface->tris.vertexDataOffset0 = bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex);
|
||||||
@@ -116,23 +123,15 @@ namespace BSP
|
|||||||
gfxSurface->material = surfMaterialAsset->Asset();
|
gfxSurface->material = surfMaterialAsset->Asset();
|
||||||
|
|
||||||
GfxPackedWorldVertex* firstVert = reinterpret_cast<GfxPackedWorldVertex*>(&gfxWorld->draw.vd0.data[gfxSurface->tris.vertexDataOffset0]);
|
GfxPackedWorldVertex* firstVert = reinterpret_cast<GfxPackedWorldVertex*>(&gfxWorld->draw.vd0.data[gfxSurface->tris.vertexDataOffset0]);
|
||||||
gfxSurface->bounds[0].x = firstVert[0].xyz.x;
|
gfxSurface->bounds[0] = firstVert[0].xyz;
|
||||||
gfxSurface->bounds[0].y = firstVert[0].xyz.y;
|
gfxSurface->bounds[1] = firstVert[0].xyz;
|
||||||
gfxSurface->bounds[0].z = firstVert[0].xyz.z;
|
|
||||||
gfxSurface->bounds[1].x = firstVert[0].xyz.x;
|
|
||||||
gfxSurface->bounds[1].y = firstVert[0].xyz.y;
|
|
||||||
gfxSurface->bounds[1].z = firstVert[0].xyz.z;
|
|
||||||
for (size_t indexIdx = 0; indexIdx < static_cast<size_t>(gfxSurface->tris.triCount * 3); indexIdx++)
|
for (size_t indexIdx = 0; indexIdx < static_cast<size_t>(gfxSurface->tris.triCount * 3); indexIdx++)
|
||||||
{
|
{
|
||||||
uint16_t vertIndex = gfxWorld->draw.indices[gfxSurface->tris.baseIndex + indexIdx];
|
uint16_t vertIndex = gfxWorld->draw.indices[gfxSurface->tris.baseIndex + indexIdx];
|
||||||
BSPUtil::updateAABBWithPoint(firstVert[vertIndex].xyz, gfxSurface->bounds[0], gfxSurface->bounds[1]);
|
BSPUtil::updateAABBWithPoint(firstVert[vertIndex].xyz, gfxSurface->bounds[0], gfxSurface->bounds[1]);
|
||||||
}
|
}
|
||||||
gfxSurface->tris.mins.x = gfxSurface->bounds[0].x;
|
gfxSurface->tris.mins = gfxSurface->bounds[0];
|
||||||
gfxSurface->tris.mins.y = gfxSurface->bounds[0].y;
|
gfxSurface->tris.maxs = gfxSurface->bounds[1];
|
||||||
gfxSurface->tris.mins.z = gfxSurface->bounds[0].z;
|
|
||||||
gfxSurface->tris.maxs.x = gfxSurface->bounds[1].x;
|
|
||||||
gfxSurface->tris.maxs.y = gfxSurface->bounds[1].y;
|
|
||||||
gfxSurface->tris.maxs.z = gfxSurface->bounds[1].z;
|
|
||||||
|
|
||||||
gfxSurface->flags = 0;
|
gfxSurface->flags = 0;
|
||||||
if ((bspMaterial.contentFlags & BSPFlags::surfaceTypeToFlagMap[BSPFlags::SURF_TYPE_SKY].contentFlags) != 0)
|
if ((bspMaterial.contentFlags & BSPFlags::surfaceTypeToFlagMap[BSPFlags::SURF_TYPE_SKY].contentFlags) != 0)
|
||||||
@@ -144,12 +143,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 = SUN_LIGHT_INDEX;
|
gfxSurface->primaryLightIndex = DEFAULT_PRIMARYLIGHT_INDEX;
|
||||||
gfxSurface->lightmapIndex = EMPTY_LIGHTMAP_INDEX;
|
gfxSurface->lightmapIndex = DEFAULT_LIGHTMAP_INDEX;
|
||||||
gfxSurface->reflectionProbeIndex = EMPTY_RPROBE_INDEX;
|
gfxSurface->reflectionProbeIndex = DEFAULT_RPROBE_INDEX;
|
||||||
|
|
||||||
// unknown value
|
|
||||||
gfxSurface->tris.himipRadiusInvSq = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some code uses Sorted surfs to index surfaces, so for simplicity keep the indexes sequential and from 0
|
// Some code uses Sorted surfs to index surfaces, so for simplicity keep the indexes sequential and from 0
|
||||||
@@ -191,6 +187,29 @@ namespace BSP
|
|||||||
gfxWorld->dpvs.smodelInsts = m_memory.Alloc<GfxStaticModelInst>(modelCount);
|
gfxWorld->dpvs.smodelInsts = m_memory.Alloc<GfxStaticModelInst>(modelCount);
|
||||||
gfxWorld->dpvs.smodelDrawInsts = m_memory.Alloc<GfxStaticModelDrawInst>(modelCount);
|
gfxWorld->dpvs.smodelDrawInsts = m_memory.Alloc<GfxStaticModelDrawInst>(modelCount);
|
||||||
|
|
||||||
|
if (modelCount == 0)
|
||||||
|
return true;
|
||||||
|
if (modelCount > 0xFFFF)
|
||||||
|
{
|
||||||
|
con::error("GFXWorld exceeded the maximum number of static xmodels (65535 max, map count: {})", modelCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char color = DEFAULT_LIGHTGRID_COLOUR;
|
||||||
|
float sunIntensity = bsp->sunlight.intensity;
|
||||||
|
if (sunIntensity < 0.0f || sunIntensity > 20000.0f)
|
||||||
|
{
|
||||||
|
con::error("Sun intensity ({}) needs to be between 0 and 20000", sunIntensity);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float normalised = sunIntensity / 20000.0f;
|
||||||
|
normalised *= 255.0f;
|
||||||
|
float clean = roundf(normalised);
|
||||||
|
color = static_cast<char>(clean);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t modelIdx = 0; modelIdx < modelCount; modelIdx++)
|
for (size_t modelIdx = 0; modelIdx < modelCount; modelIdx++)
|
||||||
{
|
{
|
||||||
auto currModel = &gfxWorld->dpvs.smodelDrawInsts[modelIdx];
|
auto currModel = &gfxWorld->dpvs.smodelDrawInsts[modelIdx];
|
||||||
@@ -206,9 +225,7 @@ namespace BSP
|
|||||||
else
|
else
|
||||||
currModel->model = (XModel*)xModelAsset->Asset();
|
currModel->model = (XModel*)xModelAsset->Asset();
|
||||||
|
|
||||||
currModel->placement.origin.x = bspModel.origin.x;
|
currModel->placement.origin = bspModel.origin;
|
||||||
currModel->placement.origin.y = bspModel.origin.y;
|
|
||||||
currModel->placement.origin.z = bspModel.origin.z;
|
|
||||||
BSPUtil::convertQuaternionToAxis(&bspModel.rotationQuaternion, currModel->placement.axis);
|
BSPUtil::convertQuaternionToAxis(&bspModel.rotationQuaternion, currModel->placement.axis);
|
||||||
currModel->placement.scale = bspModel.scale;
|
currModel->placement.scale = bspModel.scale;
|
||||||
|
|
||||||
@@ -217,16 +234,11 @@ namespace BSP
|
|||||||
currModel->flags |= STATIC_MODEL_FLAG_NO_SHADOW;
|
currModel->flags |= STATIC_MODEL_FLAG_NO_SHADOW;
|
||||||
|
|
||||||
currModel->cullDist = XMODEL_CULL_DIST;
|
currModel->cullDist = XMODEL_CULL_DIST;
|
||||||
currModel->primaryLightIndex = SUN_LIGHT_INDEX;
|
currModel->primaryLightIndex = DEFAULT_PRIMARYLIGHT_INDEX;
|
||||||
currModel->reflectionProbeIndex = EMPTY_LIGHTMAP_INDEX;
|
currModel->reflectionProbeIndex = DEFAULT_RPROBE_INDEX;
|
||||||
currModel->smid = modelIdx;
|
currModel->smid = modelIdx;
|
||||||
|
|
||||||
// unknown use / unused
|
currModelInst->lightingOrigin = bspModel.origin;
|
||||||
memset(&currModel->lightingSH, 0, sizeof(GfxLightingSHQuantized));
|
|
||||||
currModel->invScaleSq = 0.0f;
|
|
||||||
currModel->lightingHandle = 0; // overwritten to by the game
|
|
||||||
currModel->colorsIndex = 0;
|
|
||||||
currModel->visibility = 0;
|
|
||||||
|
|
||||||
if (!xModelAsset->IsReference())
|
if (!xModelAsset->IsReference())
|
||||||
{
|
{
|
||||||
@@ -249,8 +261,7 @@ namespace BSP
|
|||||||
|
|
||||||
currModel->lmapVertexInfo[lodIdx].numLmapVertexColors = vertCount;
|
currModel->lmapVertexInfo[lodIdx].numLmapVertexColors = vertCount;
|
||||||
currModel->lmapVertexInfo[lodIdx].lmapVertexColors = m_memory.Alloc<unsigned int>(vertCount);
|
currModel->lmapVertexInfo[lodIdx].lmapVertexColors = m_memory.Alloc<unsigned int>(vertCount);
|
||||||
// a value of 1 makes shadowed surfaces slightly easier to see
|
memset(currModel->lmapVertexInfo[lodIdx].lmapVertexColors, color, sizeof(unsigned int) * vertCount);
|
||||||
memset(currModel->lmapVertexInfo[lodIdx].lmapVertexColors, 1, sizeof(unsigned int) * vertCount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -270,20 +281,7 @@ namespace BSP
|
|||||||
currModelInst->maxs.y = bspModel.origin.y + 1.0f;
|
currModelInst->maxs.y = bspModel.origin.y + 1.0f;
|
||||||
currModelInst->maxs.z = bspModel.origin.z + 1.0f;
|
currModelInst->maxs.z = bspModel.origin.z + 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting these to nullptr makes any static/baked lighting go black when not rendered by real-time lighting or in a shadow
|
|
||||||
currModel->lmapVertexInfo[0].numLmapVertexColors = 0;
|
|
||||||
currModel->lmapVertexInfo[0].lmapVertexColors = nullptr;
|
|
||||||
currModel->lmapVertexInfo[1].numLmapVertexColors = 0;
|
|
||||||
currModel->lmapVertexInfo[1].lmapVertexColors = nullptr;
|
|
||||||
currModel->lmapVertexInfo[2].numLmapVertexColors = 0;
|
|
||||||
currModel->lmapVertexInfo[2].lmapVertexColors = nullptr;
|
|
||||||
currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
|
|
||||||
currModel->lmapVertexInfo[3].lmapVertexColors = nullptr;
|
|
||||||
}
|
}
|
||||||
currModelInst->lightingOrigin.x = 0.0f;
|
|
||||||
currModelInst->lightingOrigin.y = 0.0f;
|
|
||||||
currModelInst->lightingOrigin.z = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// visdata is written to by the game
|
// visdata is written to by the game
|
||||||
@@ -299,8 +297,6 @@ namespace BSP
|
|||||||
{
|
{
|
||||||
if ((gfxWorld->dpvs.smodelDrawInsts[i].flags & STATIC_MODEL_FLAG_NO_SHADOW) == 0)
|
if ((gfxWorld->dpvs.smodelDrawInsts[i].flags & STATIC_MODEL_FLAG_NO_SHADOW) == 0)
|
||||||
gfxWorld->dpvs.smodelCastsShadow[i] = 1;
|
gfxWorld->dpvs.smodelCastsShadow[i] = 1;
|
||||||
else
|
|
||||||
gfxWorld->dpvs.smodelCastsShadow[i] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -395,12 +391,18 @@ namespace BSP
|
|||||||
gfxWorld->sunLight = m_memory.Alloc<GfxLight>();
|
gfxWorld->sunLight = m_memory.Alloc<GfxLight>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxWorldLinker::loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld)
|
bool 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 = 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 = SUN_LIGHT_INDEX;
|
gfxWorld->sunPrimaryLightIndex = SUN_LIGHT_INDEX;
|
||||||
|
|
||||||
|
if (gfxWorld->primaryLightCount > 254)
|
||||||
|
{
|
||||||
|
con::error("Exceeded 254 lights in BSP, count: {}", gfxWorld->primaryLightCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
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++)
|
||||||
{
|
{
|
||||||
@@ -416,7 +418,7 @@ namespace BSP
|
|||||||
{
|
{
|
||||||
if ((gfxWorld->dpvs.smodelDrawInsts[modelIdx].flags & STATIC_MODEL_FLAG_NO_SHADOW) != 0)
|
if ((gfxWorld->dpvs.smodelDrawInsts[modelIdx].flags & STATIC_MODEL_FLAG_NO_SHADOW) != 0)
|
||||||
continue;
|
continue;
|
||||||
char lightIndex = gfxWorld->dpvs.smodelDrawInsts[modelIdx].primaryLightIndex;
|
unsigned char lightIndex = gfxWorld->dpvs.smodelDrawInsts[modelIdx].primaryLightIndex;
|
||||||
gfxWorld->shadowGeom[lightIndex].smodelIndex[gfxWorld->shadowGeom[lightIndex].smodelCount] = modelIdx;
|
gfxWorld->shadowGeom[lightIndex].smodelIndex[gfxWorld->shadowGeom[lightIndex].smodelCount] = modelIdx;
|
||||||
gfxWorld->shadowGeom[lightIndex].smodelCount++;
|
gfxWorld->shadowGeom[lightIndex].smodelCount++;
|
||||||
}
|
}
|
||||||
@@ -433,22 +435,41 @@ namespace BSP
|
|||||||
gfxWorld->primaryLightEntityShadowVis = m_memory.Alloc<unsigned int>(lightEntShadowVisSize);
|
gfxWorld->primaryLightEntityShadowVis = m_memory.Alloc<unsigned int>(lightEntShadowVisSize);
|
||||||
else
|
else
|
||||||
gfxWorld->primaryLightEntityShadowVis = nullptr;
|
gfxWorld->primaryLightEntityShadowVis = nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxWorldLinker::loadLightGrid(BSPData* bsp, GfxWorld* gfxWorld)
|
bool GfxWorldLinker::loadLightGrid(BSPData* bsp, GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
// gfxWorld->lightGrid.mins[0] = static_cast<uint16_t>((static_cast<int>(gfxWorld->lightGrid.mins[0]) + 0x20000) >> 5);
|
// world to lightgrid coords conversion:
|
||||||
// gfxWorld->lightGrid.mins[1] = static_cast<uint16_t>((static_cast<int>(gfxWorld->lightGrid.mins[1]) + 0x20000) >> 5);
|
// l_x = (w_x + 131072.0f) / 32.0f;
|
||||||
// gfxWorld->lightGrid.mins[2] = static_cast<uint16_t>((static_cast<int>(gfxWorld->lightGrid.mins[2]) + 0x20000) >> 6);
|
// l_y = (w_y + 131072.0f) / 32.0f;
|
||||||
// gfxWorld->lightGrid.maxs[0] = static_cast<uint16_t>((static_cast<int>(gfxWorld->lightGrid.maxs[0]) + 0x20000) >> 5);
|
// l_z = (w_z + 131072.0f) / 64.0f;
|
||||||
// gfxWorld->lightGrid.maxs[1] = static_cast<uint16_t>((static_cast<int>(gfxWorld->lightGrid.maxs[1]) + 0x20000) >> 5);
|
//
|
||||||
// gfxWorld->lightGrid.maxs[2] = static_cast<uint16_t>((static_cast<int>(gfxWorld->lightGrid.maxs[2]) + 0x20000) >> 6);
|
// lightgrid to world coords conversion:
|
||||||
gfxWorld->lightGrid.mins[0] = 100;
|
// w_x = (double)l_x * 32.0f - 131072.0f;
|
||||||
gfxWorld->lightGrid.mins[1] = 100;
|
// w_y = (double)l_y * 32.0f - 131072.0f;
|
||||||
gfxWorld->lightGrid.mins[2] = 100;
|
// w_z = (double)l_z * 64.0f - 131072.0f;
|
||||||
gfxWorld->lightGrid.maxs[0] = 65435;
|
//
|
||||||
gfxWorld->lightGrid.maxs[1] = 65435;
|
// Lightrid coords are bounded by the uint16 limits:
|
||||||
gfxWorld->lightGrid.maxs[2] = 65435;
|
// w_minX = -131072, w_maxX = 1966048
|
||||||
|
// w_minY = -131072, w_maxY = 1966048
|
||||||
|
// w_minZ = -131072, w_maxZ = 4063168
|
||||||
|
|
||||||
|
if (gfxWorld->mins.x < -131072.0f || gfxWorld->mins.y < -131072.0f || gfxWorld->mins.z < -131072.0f || gfxWorld->maxs.x > 1966048.0f
|
||||||
|
|| gfxWorld->maxs.y > 1966048.0f || gfxWorld->maxs.z > 4063168.0f)
|
||||||
|
{
|
||||||
|
con::error("Lightrid mins/maxs exceeded");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer-only method used by the game
|
||||||
|
gfxWorld->lightGrid.mins[0] = static_cast<uint16_t>((static_cast<int>(gfxWorld->mins.x) + 0x20000) >> 5);
|
||||||
|
gfxWorld->lightGrid.mins[1] = static_cast<uint16_t>((static_cast<int>(gfxWorld->mins.y) + 0x20000) >> 5);
|
||||||
|
gfxWorld->lightGrid.mins[2] = static_cast<uint16_t>((static_cast<int>(gfxWorld->mins.z) + 0x20000) >> 6);
|
||||||
|
gfxWorld->lightGrid.maxs[0] = static_cast<uint16_t>((static_cast<int>(gfxWorld->maxs.x) + 0x20000) >> 5);
|
||||||
|
gfxWorld->lightGrid.maxs[1] = static_cast<uint16_t>((static_cast<int>(gfxWorld->maxs.y) + 0x20000) >> 5);
|
||||||
|
gfxWorld->lightGrid.maxs[2] = static_cast<uint16_t>((static_cast<int>(gfxWorld->maxs.z) + 0x20000) >> 6);
|
||||||
|
|
||||||
gfxWorld->lightGrid.rowAxis = 0; // default value
|
gfxWorld->lightGrid.rowAxis = 0; // default value
|
||||||
gfxWorld->lightGrid.colAxis = 1; // default value
|
gfxWorld->lightGrid.colAxis = 1; // default value
|
||||||
@@ -467,8 +488,8 @@ namespace BSP
|
|||||||
row->zStart = 0;
|
row->zStart = 0;
|
||||||
row->zCount = 0xFF; // 0xFF as this seems to be the sweet spot of values
|
row->zCount = 0xFF; // 0xFF as this seems to be the sweet spot of values
|
||||||
row->firstEntry = 0;
|
row->firstEntry = 0;
|
||||||
for (int i = 0; i < 0x200; i++) // set the lookup table to all 0xFF
|
for (int i = 0; i < 0x200; i++)
|
||||||
row->lookupTable[i] = -1;
|
row->lookupTable[i] = -1; // values in the lookup table are subtracted from the sample pos until it reaches 0, so use 0xFF
|
||||||
gfxWorld->lightGrid.rawRowData = reinterpret_cast<aligned_byte_pointer*>(row);
|
gfxWorld->lightGrid.rawRowData = reinterpret_cast<aligned_byte_pointer*>(row);
|
||||||
|
|
||||||
// entries are looked up based on the lightgrid sample pos (given ingame) and the lightgrid lookup table
|
// entries are looked up based on the lightgrid sample pos (given ingame) and the lightgrid lookup table
|
||||||
@@ -477,7 +498,7 @@ 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 = SUN_LIGHT_INDEX;
|
entryArray[i].primaryLightIndex = DEFAULT_PRIMARYLIGHT_INDEX;
|
||||||
entryArray[i].visibility = 0;
|
entryArray[i].visibility = 0;
|
||||||
}
|
}
|
||||||
gfxWorld->lightGrid.entries = entryArray;
|
gfxWorld->lightGrid.entries = entryArray;
|
||||||
@@ -485,7 +506,10 @@ namespace BSP
|
|||||||
char color = DEFAULT_LIGHTGRID_COLOUR;
|
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::error("Sun intensity ({}) needs to be between 0 and 20000", sunIntensity);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float normalised = sunIntensity / 20000.0f;
|
float normalised = sunIntensity / 20000.0f;
|
||||||
@@ -504,6 +528,8 @@ namespace BSP
|
|||||||
gfxWorld->lightGrid.coeffs = nullptr;
|
gfxWorld->lightGrid.coeffs = nullptr;
|
||||||
gfxWorld->lightGrid.skyGridVolumeCount = 0;
|
gfxWorld->lightGrid.skyGridVolumeCount = 0;
|
||||||
gfxWorld->lightGrid.skyGridVolumes = nullptr;
|
gfxWorld->lightGrid.skyGridVolumes = nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mnode_t
|
struct mnode_t
|
||||||
@@ -530,17 +556,13 @@ namespace BSP
|
|||||||
gfxWorld->cells = m_memory.Alloc<GfxCell>(cellCount);
|
gfxWorld->cells = m_memory.Alloc<GfxCell>(cellCount);
|
||||||
gfxWorld->cells[0].portalCount = 0;
|
gfxWorld->cells[0].portalCount = 0;
|
||||||
gfxWorld->cells[0].portals = nullptr;
|
gfxWorld->cells[0].portals = nullptr;
|
||||||
gfxWorld->cells[0].mins.x = gfxWorld->mins.x;
|
gfxWorld->cells[0].mins = gfxWorld->mins;
|
||||||
gfxWorld->cells[0].mins.y = gfxWorld->mins.y;
|
gfxWorld->cells[0].maxs = gfxWorld->maxs;
|
||||||
gfxWorld->cells[0].mins.z = gfxWorld->mins.z;
|
|
||||||
gfxWorld->cells[0].maxs.x = gfxWorld->maxs.x;
|
|
||||||
gfxWorld->cells[0].maxs.y = gfxWorld->maxs.y;
|
|
||||||
gfxWorld->cells[0].maxs.z = gfxWorld->maxs.z;
|
|
||||||
|
|
||||||
// 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] = EMPTY_RPROBE_INDEX;
|
gfxWorld->cells[0].reflectionProbes[0] = DEFAULT_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
|
||||||
@@ -556,12 +578,8 @@ namespace BSP
|
|||||||
{
|
{
|
||||||
gfxWorld->cells[0].aabbTree[0].smodelIndexes[smodelIdx] = smodelIdx;
|
gfxWorld->cells[0].aabbTree[0].smodelIndexes[smodelIdx] = smodelIdx;
|
||||||
}
|
}
|
||||||
gfxWorld->cells[0].aabbTree[0].mins.x = gfxWorld->mins.x;
|
gfxWorld->cells[0].aabbTree[0].mins = gfxWorld->mins;
|
||||||
gfxWorld->cells[0].aabbTree[0].mins.y = gfxWorld->mins.y;
|
gfxWorld->cells[0].aabbTree[0].maxs = gfxWorld->maxs;
|
||||||
gfxWorld->cells[0].aabbTree[0].mins.z = gfxWorld->mins.z;
|
|
||||||
gfxWorld->cells[0].aabbTree[0].maxs.x = gfxWorld->maxs.x;
|
|
||||||
gfxWorld->cells[0].aabbTree[0].maxs.y = gfxWorld->maxs.y;
|
|
||||||
gfxWorld->cells[0].aabbTree[0].maxs.z = gfxWorld->maxs.z;
|
|
||||||
|
|
||||||
// nodes have the struct mnode_t, and there must be at least 1 node (similar to BSP nodes)
|
// nodes have the struct mnode_t, and there must be at least 1 node (similar to BSP nodes)
|
||||||
// Nodes mnode_t.cellIndex indexes gfxWorld->cells
|
// Nodes mnode_t.cellIndex indexes gfxWorld->cells
|
||||||
@@ -595,6 +613,7 @@ namespace BSP
|
|||||||
void GfxWorldLinker::loadModels(BSPData* bsp, GfxWorld* gfxWorld)
|
void GfxWorldLinker::loadModels(BSPData* bsp, GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
// 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)
|
||||||
|
// bounds are checked in clipmap linker
|
||||||
gfxWorld->modelCount = static_cast<int>(bsp->models.size() + 1);
|
gfxWorld->modelCount = static_cast<int>(bsp->models.size() + 1);
|
||||||
gfxWorld->models = m_memory.Alloc<GfxBrushModel>(gfxWorld->modelCount);
|
gfxWorld->models = m_memory.Alloc<GfxBrushModel>(gfxWorld->modelCount);
|
||||||
|
|
||||||
@@ -614,6 +633,11 @@ namespace BSP
|
|||||||
gfxWorld->models[0].bounds[0],
|
gfxWorld->models[0].bounds[0],
|
||||||
gfxWorld->models[0].bounds[1]);
|
gfxWorld->models[0].bounds[1]);
|
||||||
}
|
}
|
||||||
|
if (gfxWorld->dpvs.staticSurfaceCount == 0)
|
||||||
|
{
|
||||||
|
gfxWorld->models[0].bounds[0] = {};
|
||||||
|
gfxWorld->models[0].bounds[1] = {};
|
||||||
|
}
|
||||||
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
||||||
|
|
||||||
for (size_t modelIdx = 0; modelIdx < bsp->models.size(); modelIdx++)
|
for (size_t modelIdx = 0; modelIdx < bsp->models.size(); modelIdx++)
|
||||||
@@ -641,12 +665,8 @@ namespace BSP
|
|||||||
{
|
{
|
||||||
currEntModel->startSurfIndex = -1; // -1 when it doesn't use map surfaces
|
currEntModel->startSurfIndex = -1; // -1 when it doesn't use map surfaces
|
||||||
currEntModel->surfaceCount = 0;
|
currEntModel->surfaceCount = 0;
|
||||||
currEntModel->bounds[0].x = 0.0f;
|
currEntModel->bounds[0] = {};
|
||||||
currEntModel->bounds[0].y = 0.0f;
|
currEntModel->bounds[1] = {};
|
||||||
currEntModel->bounds[0].z = 0.0f;
|
|
||||||
currEntModel->bounds[1].x = 0.0f;
|
|
||||||
currEntModel->bounds[1].y = 0.0f;
|
|
||||||
currEntModel->bounds[1].z = 0.0f;
|
|
||||||
}
|
}
|
||||||
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
||||||
}
|
}
|
||||||
@@ -656,14 +676,13 @@ namespace BSP
|
|||||||
{
|
{
|
||||||
BSPLight& sunlight = bsp->sunlight;
|
BSPLight& sunlight = bsp->sunlight;
|
||||||
vec3_t viewAngles = BSPUtil::convertForwardVectorToViewAngles(sunlight.direction);
|
vec3_t viewAngles = BSPUtil::convertForwardVectorToViewAngles(sunlight.direction);
|
||||||
gfxWorld->sunParse.initWorldSun->angles.x = viewAngles.x;
|
gfxWorld->sunParse.initWorldSun->angles = viewAngles;
|
||||||
gfxWorld->sunParse.initWorldSun->angles.y = viewAngles.y;
|
|
||||||
gfxWorld->sunParse.initWorldSun->angles.z = viewAngles.z;
|
|
||||||
gfxWorld->sunParse.initWorldSun->sunCd.x = sunlight.colour.x;
|
gfxWorld->sunParse.initWorldSun->sunCd.x = sunlight.colour.x;
|
||||||
gfxWorld->sunParse.initWorldSun->sunCd.y = sunlight.colour.y;
|
gfxWorld->sunParse.initWorldSun->sunCd.y = sunlight.colour.y;
|
||||||
gfxWorld->sunParse.initWorldSun->sunCd.z = sunlight.colour.z;
|
gfxWorld->sunParse.initWorldSun->sunCd.z = sunlight.colour.z;
|
||||||
gfxWorld->sunParse.initWorldSun->sunCd.w = 1.0f;
|
gfxWorld->sunParse.initWorldSun->sunCd.w = 1.0f;
|
||||||
|
|
||||||
|
// fog is not implemented yet, values taken from mp_dig
|
||||||
gfxWorld->sunParse.initWorldFog->baseDist = 150.0f;
|
gfxWorld->sunParse.initWorldFog->baseDist = 150.0f;
|
||||||
gfxWorld->sunParse.initWorldFog->baseHeight = -100.0f;
|
gfxWorld->sunParse.initWorldFog->baseHeight = -100.0f;
|
||||||
gfxWorld->sunParse.initWorldFog->fogColor.x = 2.35f;
|
gfxWorld->sunParse.initWorldFog->fogColor.x = 2.35f;
|
||||||
@@ -690,22 +709,11 @@ namespace BSP
|
|||||||
|
|
||||||
// default values taken from mp_dig
|
// default values taken from mp_dig
|
||||||
gfxWorld->draw.reflectionProbes = m_memory.Alloc<GfxReflectionProbe>(gfxWorld->draw.reflectionProbeCount);
|
gfxWorld->draw.reflectionProbes = m_memory.Alloc<GfxReflectionProbe>(gfxWorld->draw.reflectionProbeCount);
|
||||||
gfxWorld->draw.reflectionProbes[0].mipLodBias = -8.0;
|
gfxWorld->draw.reflectionProbes[0].mipLodBias = -8.0; // always -8.0f
|
||||||
gfxWorld->draw.reflectionProbes[0].origin.x = 0.0f;
|
gfxWorld->draw.reflectionProbes[0].origin = {};
|
||||||
gfxWorld->draw.reflectionProbes[0].origin.y = 0.0f;
|
gfxWorld->draw.reflectionProbes[0].lightingSH.V0 = {};
|
||||||
gfxWorld->draw.reflectionProbes[0].origin.z = 0.0f;
|
gfxWorld->draw.reflectionProbes[0].lightingSH.V1 = {};
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V0.x = 0.0f;
|
gfxWorld->draw.reflectionProbes[0].lightingSH.V2 = {};
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V0.y = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V0.z = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V0.w = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V1.x = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V1.y = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V1.z = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V1.w = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V2.x = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V2.y = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V2.z = 0.0f;
|
|
||||||
gfxWorld->draw.reflectionProbes[0].lightingSH.V2.w = 0.0f;
|
|
||||||
|
|
||||||
gfxWorld->draw.reflectionProbes[0].probeVolumeCount = 0;
|
gfxWorld->draw.reflectionProbes[0].probeVolumeCount = 0;
|
||||||
gfxWorld->draw.reflectionProbes[0].probeVolumes = nullptr;
|
gfxWorld->draw.reflectionProbes[0].probeVolumes = nullptr;
|
||||||
@@ -753,7 +761,7 @@ namespace BSP
|
|||||||
con::warn("WARN: Unable to load the skybox xmodel {}!", skyBoxName);
|
con::warn("WARN: Unable to load the skybox xmodel {}!", skyBoxName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// default skybox values from mp_dig
|
// always 0 and 1
|
||||||
gfxWorld->skyDynIntensity.angle0 = 0.0f;
|
gfxWorld->skyDynIntensity.angle0 = 0.0f;
|
||||||
gfxWorld->skyDynIntensity.angle1 = 0.0f;
|
gfxWorld->skyDynIntensity.angle1 = 0.0f;
|
||||||
gfxWorld->skyDynIntensity.factor0 = 1.0f;
|
gfxWorld->skyDynIntensity.factor0 = 1.0f;
|
||||||
@@ -831,9 +839,9 @@ namespace BSP
|
|||||||
gfxWorld->baseName = m_memory.Dup(bsp->name.c_str());
|
gfxWorld->baseName = m_memory.Dup(bsp->name.c_str());
|
||||||
gfxWorld->name = m_memory.Dup(bsp->bspName.c_str());
|
gfxWorld->name = m_memory.Dup(bsp->bspName.c_str());
|
||||||
|
|
||||||
// Default values taken from official maps
|
// Default values taken from origins
|
||||||
gfxWorld->lightingFlags = 0;
|
gfxWorld->lightingFlags = 4;
|
||||||
gfxWorld->lightingQuality = 4096;
|
gfxWorld->lightingQuality = 10000;
|
||||||
|
|
||||||
cleanGfxWorld(gfxWorld);
|
cleanGfxWorld(gfxWorld);
|
||||||
|
|
||||||
@@ -854,21 +862,22 @@ namespace BSP
|
|||||||
// world bounds are based on loaded surface mins/maxs and xmodels
|
// world bounds are based on loaded surface mins/maxs and xmodels
|
||||||
loadWorldBounds(gfxWorld);
|
loadWorldBounds(gfxWorld);
|
||||||
|
|
||||||
if (!loadOutdoors(gfxWorld))
|
if (!loadOutdoors(gfxWorld)) // requires world mins/maxs
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// gfx cells depend on surface/smodel count
|
// gfx cells depend on surface/smodel count
|
||||||
loadGfxCells(gfxWorld);
|
loadGfxCells(gfxWorld);
|
||||||
|
|
||||||
loadLightGrid(bsp, gfxWorld);
|
loadLightGrid(bsp, gfxWorld); // requires world mins/maxs
|
||||||
|
|
||||||
loadGfxLights(bsp, gfxWorld); // requires xmodels and surfaces
|
if (!loadGfxLights(bsp, gfxWorld)) // requires xmodels and surfaces
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
loadModels(bsp, gfxWorld); // requires surfaces
|
loadModels(bsp, gfxWorld); // requires surfaces
|
||||||
|
|
||||||
loadSunData(bsp, gfxWorld);
|
loadSunData(bsp, gfxWorld);
|
||||||
|
|
||||||
loadDynEntData(gfxWorld);
|
loadDynEntData(gfxWorld); // requires cells and lights
|
||||||
|
|
||||||
return gfxWorld;
|
return gfxWorld;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ namespace BSP
|
|||||||
bool loadMapSurfaces(BSPData* projInfo, GfxWorld* gfxWorld);
|
bool loadMapSurfaces(BSPData* projInfo, GfxWorld* gfxWorld);
|
||||||
bool loadXModels(BSPData* projInfo, GfxWorld* gfxWorld);
|
bool loadXModels(BSPData* projInfo, GfxWorld* gfxWorld);
|
||||||
void cleanGfxWorld(GfxWorld* gfxWorld);
|
void cleanGfxWorld(GfxWorld* gfxWorld);
|
||||||
void loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld);
|
bool loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld);
|
||||||
void loadLightGrid(BSPData* bsp, GfxWorld* gfxWorld);
|
bool loadLightGrid(BSPData* bsp, GfxWorld* gfxWorld);
|
||||||
void loadGfxCells(GfxWorld* gfxWorld);
|
void loadGfxCells(GfxWorld* gfxWorld);
|
||||||
void loadModels(BSPData* bsp, GfxWorld* gfxWorld);
|
void loadModels(BSPData* bsp, GfxWorld* gfxWorld);
|
||||||
bool loadReflectionProbeData(GfxWorld* gfxWorld);
|
bool loadReflectionProbeData(GfxWorld* gfxWorld);
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
#include "../BSPUtil.h"
|
#include "../BSPUtil.h"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
using namespace nlohmann;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
inline const std::vector<const char*> DEFENDER_SPAWN_POINT_NAMES = {"mp_ctf_spawn_allies",
|
inline const std::vector<const char*> DEFENDER_SPAWN_POINT_NAMES = {"mp_ctf_spawn_allies",
|
||||||
@@ -172,14 +169,6 @@ namespace BSP
|
|||||||
mapEnts->entityString = m_memory.Dup(entityString.c_str());
|
mapEnts->entityString = m_memory.Dup(entityString.c_str());
|
||||||
mapEnts->numEntityChars = static_cast<int>(entityString.length() + 1); // numEntityChars includes the null character
|
mapEnts->numEntityChars = static_cast<int>(entityString.length() + 1); // numEntityChars includes the null character
|
||||||
|
|
||||||
// don't need these, unused by the game
|
|
||||||
mapEnts->trigger.count = 0;
|
|
||||||
mapEnts->trigger.models = nullptr;
|
|
||||||
mapEnts->trigger.hullCount = 0;
|
|
||||||
mapEnts->trigger.hulls = nullptr;
|
|
||||||
mapEnts->trigger.slabCount = 0;
|
|
||||||
mapEnts->trigger.slabs = nullptr;
|
|
||||||
|
|
||||||
return mapEnts;
|
return mapEnts;
|
||||||
}
|
}
|
||||||
} // namespace BSP
|
} // namespace BSP
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ namespace BSP
|
|||||||
SkinnedVertsDef* SkinnedVertsLinker::linkSkinnedVerts(BSPData* bsp)
|
SkinnedVertsDef* SkinnedVertsLinker::linkSkinnedVerts(BSPData* bsp)
|
||||||
{
|
{
|
||||||
// maxSkinnedVerts defines how many model verts can be drawn at once
|
// maxSkinnedVerts defines how many model verts can be drawn at once
|
||||||
// Low values cause models not to be drawn, so double origin's maxSkinnedVerts is used as a safe bet
|
// Low values cause models not to be drawn, so double origin's maxSkinnedVerts (163840) is used as a safe bet
|
||||||
SkinnedVertsDef* skinnedVerts = m_memory.Alloc<SkinnedVertsDef>();
|
SkinnedVertsDef* skinnedVerts = m_memory.Alloc<SkinnedVertsDef>();
|
||||||
skinnedVerts->name = m_memory.Dup("skinnedverts");
|
skinnedVerts->name = m_memory.Dup("skinnedverts");
|
||||||
skinnedVerts->maxSkinnedVerts = static_cast<unsigned int>(300000);
|
skinnedVerts->maxSkinnedVerts = 300000;
|
||||||
|
|
||||||
return skinnedVerts;
|
return skinnedVerts;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user