2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-11-23 05:12:05 +00:00
- Converted BSP tree generation to use unique ptrs
- Updated the linker to use BSP tree unique ptrs and use the new structure of custom map structs
This commit is contained in:
LJW-Dev
2025-10-21 17:37:56 +08:00
parent e19a3a142a
commit 7d09877d02
4 changed files with 344 additions and 320 deletions

View File

@@ -0,0 +1,147 @@
#include "BinarySpacePartitionTree.h"
Object::Object(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex)
{
min.x = xMin;
min.y = yMin;
min.z = zMin;
max.x = xMax;
max.y = yMax;
max.z = zMax;
partitionIndex = objPartitionIndex;
}
void BSPLeaf::addObject(std::shared_ptr<Object> object)
{
objectList.emplace_back(std::move(object));
}
Object* BSPLeaf::getObject(int index)
{
return objectList.at(index).get();
}
int BSPLeaf::getObjectCount()
{
return objectList.size();
}
BSPNode::BSPNode(std::unique_ptr<BSPTree> frontTree, std::unique_ptr<BSPTree> backTree, PlaneAxis nodeAxis, float nodeDistance)
{
front = std::move(frontTree);
back = std::move(backTree);
axis = nodeAxis;
distance = nodeDistance;
}
PlaneSide BSPNode::objectIsInfront(Object* object)
{
float minCoord, maxCoord;
// Select the relevant coordinate based on the plane's axis
if (axis == AXIS_X)
{
minCoord = object->min.x;
maxCoord = object->max.x;
}
else if (axis == AXIS_Y)
{
minCoord = object->min.y;
maxCoord = object->max.y;
}
else // axis == AXIS_Z
{
minCoord = object->min.z;
maxCoord = object->max.z;
}
// Compare with the plane's distance
if (maxCoord < distance)
{
return SIDE_BACK; // Object is entirely on the negative side
}
else if (minCoord > distance)
{
return SIDE_FRONT; // Object is entirely on the positive side
}
else
{
return SIDE_INTERSECTS;
}
}
BSPTree::BSPTree(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int treeLevel)
{
min.x = xMin;
min.y = yMin;
min.z = zMin;
max.x = xMax;
max.y = yMax;
max.z = zMax;
level = treeLevel;
splitTree();
}
// For simplicity, only split across the X and Z axis.
// It is unlikely that there are many layers to a map, and is instead mostly flat
void BSPTree::splitTree()
{
std::unique_ptr<BSPTree> front;
std::unique_ptr<BSPTree> back;
float halfLength;
if (max.x - min.x > MAX_NODE_SIZE)
{
// split along the x axis
halfLength = (min.x + max.x) * 0.5f;
front = std::make_unique<BSPTree>(halfLength, min.y, min.z, max.x, 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;
node = std::make_unique<BSPNode>(std::move(front), std::move(back), AXIS_X, halfLength);
leaf = nullptr;
}
else if (max.z - min.z > MAX_NODE_SIZE)
{
// split along the z axis
halfLength = (min.z + max.z) * 0.5f;
front = std::make_unique<BSPTree>(min.x, min.y, halfLength, max.x, max.y, max.z, level + 1);
back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, max.y, halfLength, level + 1);
isLeaf = false;
node = std::make_unique<BSPNode>(std::move(front), std::move(back), AXIS_Z, halfLength);
leaf = nullptr;
}
else
{
isLeaf = true;
node = nullptr;
leaf = std::make_unique<BSPLeaf>();
}
}
void BSPTree::addObjectToTree(std::shared_ptr<Object> object)
{
if (isLeaf)
{
leaf->addObject(std::move(object));
}
else
{
PlaneSide side = node->objectIsInfront(object.get());
if (side == SIDE_FRONT)
{
node->front->addObjectToTree(std::move(object));
}
else if (side == SIDE_BACK)
{
node->back->addObjectToTree(std::move(object));
}
else // intersects
{
node->front->addObjectToTree(object);
node->back->addObjectToTree(object);
}
}
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <vector>
#include <memory>
#include <vector>
#include "Game/T6/T6.h"
using namespace T6;
@@ -15,194 +15,61 @@ enum PlaneAxis
AXIS_Z
};
class Object
{
public:
vec3_t min;
vec3_t max;
int partitionIndex; // index of the partition the object is contained in
Object(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex)
{
min.x = xMin;
min.y = yMin;
min.z = zMin;
max.x = xMax;
max.y = yMax;
max.z = zMax;
partitionIndex = objPartitionIndex;
}
};
union u_BSPNode
{
BSPLeaf* leaf;
BSPNode* node;
};
class BSPTree;
class BSPLeaf
{
private:
std::vector<std::unique_ptr<Object>> objectList;
public:
void addObject(std::unique_ptr<Object> object)
{
objectList.push_back(std::move(object));
}
std::unique_ptr<Object> getObject(int index)
{
return std::move(objectList.at(index));
}
int getObjectCount()
{
return objectList.size();
}
};
enum objectPlaneSide
enum PlaneSide
{
SIDE_FRONT,
SIDE_BACK,
SIDE_INTERSECTS
};
class Object
{
public:
vec3_t min;
vec3_t max;
int partitionIndex; // index of the partition the object is contained in
Object(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex);
};
class BSPLeaf
{
public:
std::vector<std::shared_ptr<Object>> objectList;
void addObject(std::shared_ptr<Object> object);
Object* getObject(int index);
int getObjectCount();
};
class BSPTree;
class BSPNode
{
public:
BSPTree* front;
BSPTree* back;
std::unique_ptr<BSPTree> front;
std::unique_ptr<BSPTree> back;
PlaneAxis axis; // axis that the split plane is on
double distance; // distance from the origin (0, 0, 0) to the plane
float distance; // distance from the origin (0, 0, 0) to the plane
BSPNode(BSPTree* _front, BSPTree* _back, PlaneAxis _axis, double _distance)
{
front = _front;
back = _back;
axis = _axis;
distance = _distance;
}
objectPlaneSide objectIsInfront(Object* object)
{
float minCoord, maxCoord;
// Select the relevant coordinate based on the plane's axis
if (axis == AXIS_X)
{
minCoord = object->min.x;
maxCoord = object->max.x;
}
else if (axis == AXIS_Y)
{
minCoord = object->min.y;
maxCoord = object->max.y;
}
else // axis == AXIS_Z
{
minCoord = object->min.z;
maxCoord = object->max.z;
}
// Compare with the plane's distance
if (maxCoord < distance)
{
return SIDE_BACK; // Object is entirely on the negative side
}
else if (minCoord > distance)
{
return SIDE_FRONT; // Object is entirely on the positive side
}
else
{
return SIDE_INTERSECTS;
}
}
BSPNode(std::unique_ptr<BSPTree> frontTree, std::unique_ptr<BSPTree> backTree, PlaneAxis nodeAxis, float nodeDistance);
PlaneSide objectIsInfront(Object* object);
};
class BSPTree
{
public:
bool isLeaf;
u_BSPNode u;
std::unique_ptr<BSPLeaf> leaf;
std::unique_ptr<BSPNode> node;
int level; // level in the BSP tree
double low[3]; // mins
double high[3]; // maxs
int level; // level in the BSP tree
vec3_t min;
vec3_t max;
BSPTree(double min_x, double min_y, double min_z, double max_x, double max_y, double max_z, int _level)
{
low[0] = min_x;
low[1] = min_y, low[2] = min_z;
high[0] = max_x;
high[1] = max_y;
high[2] = max_z;
level = _level;
splitTree();
}
// For simplicity, only split across the X and Z axis.
// It is unlikely that there are many layers to a map, and is instead mostly flat
void splitTree()
{
BSPTree* front;
BSPTree* back;
double halfLength;
if (high[0] - low[0] > MAX_NODE_SIZE)
{
// split along the x axis
halfLength = (low[0] + high[0]) * 0.5f;
front = new BSPTree(halfLength, low[1], low[2], high[0], high[1], high[2], level + 1);
back = new BSPTree(low[0], low[1], low[2], halfLength, high[1], high[2], level + 1);
isLeaf = false;
u.node = new BSPNode(front, back, AXIS_X, halfLength);
}
else if (high[2] - low[2] > MAX_NODE_SIZE)
{
// split along the z axis
halfLength = (low[2] + high[2]) * 0.5f;
front = new BSPTree(low[0], low[1], halfLength, high[0], high[1], high[2], level + 1);
back = new BSPTree(low[0], low[1], low[2], high[0], high[1], halfLength, level + 1);
isLeaf = false;
u.node = new BSPNode(front, back, AXIS_Z, halfLength);
}
else
{
isLeaf = true;
u.leaf = new BSPLeaf();
}
}
void addObject(Object* object)
{
if (isLeaf)
{
u.leaf->addToList(object);
}
else
{
objectPlaneSide side = u.node->objectIsInfront(object);
if (side == SIDE_FRONT)
{
u.node->front->addObject(object);
}
else if (side == SIDE_BACK)
{
u.node->back->addObject(object);
}
else // intersects
{
u.node->front->addObject(object);
u.node->back->addObject(object);
}
}
}
BSPTree(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int treeLevel);
void splitTree();
void addObjectToTree(std::shared_ptr<Object> object);
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "BinarySpacePartitionTreePreCalc.h"
#include "BinarySpacePartitionTree.h"
#include "CustomMapConsts.h"
#include "CustomMapOptions.h"
#include "Util.h"
@@ -23,7 +23,7 @@ public:
hasLinkFailed = false;
}
bool linkCustomMap(customMapInfo* projInfo)
bool linkCustomMap(CustomMapBSP* projInfo)
{
_ASSERT(projInfo != NULL);
@@ -72,27 +72,24 @@ private:
// used for UVs of sub-textures, when it is set to empty all of them turn a blank colour
// could fix by removing sub textures or figure out how they are created and redo that
// its not an important issue though
bool overwriteDrawData(customMapInfo* projInfo, GfxWorld* gfxWorld)
bool overwriteDrawData(CustomMapBSP* projInfo, GfxWorld* gfxWorld)
{
int vertexCount = projInfo->gfxInfo.vertexCount;
customMapVertex* worldVertices = projInfo->gfxInfo.vertices;
int vertexCount = projInfo->gfxWorld.vertices.size();
gfxWorld->draw.vertexCount = vertexCount;
gfxWorld->draw.vertexDataSize0 = vertexCount * sizeof(GfxPackedWorldVertex);
GfxPackedWorldVertex* vertexBuffer = new GfxPackedWorldVertex[vertexCount];
for (int i = 0; i < vertexCount; i++)
{
customMapVertex* WorldVertex = &worldVertices[i];
CustomMapVertex* WorldVertex = &projInfo->gfxWorld.vertices[i];
GfxPackedWorldVertex* GfxVertex = &vertexBuffer[i];
GfxVertex->xyz = CMUtil::convertToBO2Coords(WorldVertex->pos);
//GfxVertex->xyz = WorldVertex->pos;
GfxVertex->binormalSign = WorldVertex->binormalSign;
GfxVertex->color.packed = pack32::Vec4PackGfxColor(WorldVertex->color.v);
GfxVertex->color.packed = pack32::Vec4PackGfxColor(WorldVertex->color);
GfxVertex->texCoord.packed = pack32::Vec2PackTexCoordsUV(WorldVertex->texCoord);
GfxVertex->texCoord.packed = pack32::Vec2PackTexCoordsUV(WorldVertex->texCoord.v);
GfxVertex->normal.packed = pack32::Vec3PackUnitVecThirdBased(CMUtil::convertToBO2Coords(WorldVertex->normal).v);
//GfxVertex->normal.packed = pack32::Vec3PackUnitVecThirdBased(WorldVertex->normal.v);
@@ -100,7 +97,11 @@ private:
GfxVertex->tangent.packed = pack32::Vec3PackUnitVecThirdBased(CMUtil::convertToBO2Coords(WorldVertex->tangent).v);
//GfxVertex->tangent.packed = pack32::Vec3PackUnitVecThirdBased(WorldVertex->tangent.v);
GfxVertex->lmapCoord.packed = WorldVertex->packedLmapCoord;
// unknown use variables
// binormalSign may be bitangent of the vertex
// lmapCoord may be the lightmap coordinate of the vertex
GfxVertex->binormalSign = 0.0f;
GfxVertex->lmapCoord.packed = 0;
}
gfxWorld->draw.vd0.data = (char*)vertexBuffer;
@@ -110,16 +111,16 @@ private:
gfxWorld->draw.vd1.data = new char[gfxWorld->draw.vertexDataSize1];
memset(gfxWorld->draw.vd1.data, 0, gfxWorld->draw.vertexDataSize1);
int indexCount = projInfo->gfxInfo.indexCount;
int indexCount = projInfo->gfxWorld.indices.size();
_ASSERT(indexCount % 3 == 0);
gfxWorld->draw.indexCount = indexCount;
gfxWorld->draw.indices = new uint16_t[indexCount];
for (int i = 0; i < indexCount; i += 3)
{
// the editor orders their vertices opposite to bo2, so its converted here
gfxWorld->draw.indices[i + 2] = projInfo->gfxInfo.indices[i + 0];
gfxWorld->draw.indices[i + 1] = projInfo->gfxInfo.indices[i + 1];
gfxWorld->draw.indices[i + 0] = projInfo->gfxInfo.indices[i + 2];
gfxWorld->draw.indices[i + 2] = projInfo->gfxWorld.indices[i + 0];
gfxWorld->draw.indices[i + 1] = projInfo->gfxWorld.indices[i + 1];
gfxWorld->draw.indices[i + 0] = projInfo->gfxWorld.indices[i + 2];
}
return true;
@@ -164,20 +165,20 @@ private:
return material;
}
void overwriteMapSurfaces(customMapInfo* projInfo, GfxWorld* gfxWorld)
void overwriteMapSurfaces(CustomMapBSP* projInfo, GfxWorld* gfxWorld)
{
bool overwriteResult = overwriteDrawData(projInfo, gfxWorld);
if (!overwriteResult)
return;
unsigned int surfaceCount = projInfo->gfxInfo.surfaceCount;
unsigned int surfaceCount = projInfo->gfxWorld.surfaces.size();
gfxWorld->surfaceCount = surfaceCount;
gfxWorld->dpvs.staticSurfaceCount = surfaceCount;
gfxWorld->dpvs.surfaces = new GfxSurface[surfaceCount];
for (unsigned int i = 0; i < surfaceCount; i++)
{
auto currSurface = &gfxWorld->dpvs.surfaces[i];
auto objSurface = &projInfo->gfxInfo.surfaces[i];
auto objSurface = &projInfo->gfxWorld.surfaces[i];
currSurface->primaryLightIndex = DEFAULT_SURFACE_LIGHT;
currSurface->lightmapIndex = DEFAULT_SURFACE_LIGHTMAP;
@@ -185,20 +186,20 @@ private:
currSurface->flags = DEFAULT_SURFACE_FLAGS;
currSurface->tris.triCount = objSurface->triCount;
currSurface->tris.baseIndex = objSurface->firstIndex_Index;
currSurface->tris.baseIndex = objSurface->indexOfFirstIndex;
currSurface->tris.vertexDataOffset0 = objSurface->firstVertexIndex * sizeof(GfxPackedWorldVertex);
currSurface->tris.vertexDataOffset0 = objSurface->indexOfFirstVertex * sizeof(GfxPackedWorldVertex);
currSurface->tris.vertexDataOffset1 = 0;
std::string surfMaterialName;
switch (objSurface->material.materialType)
{
case CM_MATERIAL_TEXTURE:
case MATERIAL_TYPE_TEXTURE:
surfMaterialName = objSurface->material.materialName;
break;
case CM_MATERIAL_COLOUR:
case CM_MATERIAL_EMPTY:
case MATERIAL_TYPE_COLOUR:
case MATERIAL_TYPE_EMPTY:
surfMaterialName = colorOnlyImageName;
break;
@@ -278,78 +279,92 @@ private:
gfxWorld->dpvs.litTransSurfsEnd = surfaceCount;
}
void overwriteMapSModels(customMapInfo* projInfo, GfxWorld* gfxWorld)
void overwriteMapSModels(CustomMapBSP* projInfo, GfxWorld* gfxWorld)
{
unsigned int modelCount = projInfo->modelCount;
/*
Models are unsupported right now
Code is left in in case it is supported later on
*/
//unsigned int modelCount = projInfo->modelCount;
//gfxWorld->dpvs.smodelCount = modelCount;
//gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
//gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount];
//
//for (unsigned int i = 0; i < modelCount; i++)
//{
// auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i];
// auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
// customMapModel* inModel = &projInfo->models[i];
//
// auto xModelAsset = m_context.LoadDependency<AssetXModel>(inModel->name);
// if (xModelAsset == NULL)
// {
// printf("XModel %s not found!\n", inModel->name.c_str());
// currModel->model = NULL;
// }
// else
// currModel->model = (XModel*)xModelAsset->Asset();
//
// currModel->placement.origin.x = inModel->origin.x;
// currModel->placement.origin.y = inModel->origin.y;
// currModel->placement.origin.z = inModel->origin.z;
// currModel->placement.origin = CMUtil::convertToBO2Coords(currModel->placement.origin);
// currModel->placement.scale = inModel->scale;
//
// CMUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
//
// // mins and maxs are calculated in world space not local space
// // TODO: this does not account for model rotation or scale
// currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
// currModelInst->mins.y = currModel->model->mins.y + currModel->placement.origin.y;
// currModelInst->mins.z = currModel->model->mins.z + currModel->placement.origin.z;
// currModelInst->maxs.x = currModel->model->maxs.x + currModel->placement.origin.x;
// currModelInst->maxs.y = currModel->model->maxs.y + currModel->placement.origin.y;
// currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
//
// currModel->cullDist = DEFAULT_SMODEL_CULL_DIST;
// currModel->flags = DEFAULT_SMODEL_FLAGS;
// currModel->primaryLightIndex = DEFAULT_SMODEL_LIGHT;
// currModel->reflectionProbeIndex = DEFAULT_SMODEL_REFLECTION_PROBE;
//
// // unknown use / unused
// currModel->smid = i;
// memset(&currModel->lightingSH, 0, sizeof(GfxLightingSHQuantized));
// currModel->invScaleSq = 0.0f;
// currModel->lightingHandle = 0;
// currModel->colorsIndex = 0;
// currModel->visibility = 0;
//
// // setting these to NULL makes any static/baked lighting go black when not rendered by real-time lighting or in a shadow
// // TODO: calculate lighting and store it here
// currModel->lmapVertexInfo[0].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[0].lmapVertexColors = NULL;
// currModel->lmapVertexInfo[1].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[1].lmapVertexColors = NULL;
// currModel->lmapVertexInfo[2].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[2].lmapVertexColors = NULL;
// currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[3].lmapVertexColors = NULL;
//}
unsigned int modelCount = 0;
gfxWorld->dpvs.smodelCount = modelCount;
gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount];
for (unsigned int i = 0; i < modelCount; i++)
{
auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i];
auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
customMapModel* inModel = &projInfo->models[i];
auto xModelAsset = m_context.LoadDependency<AssetXModel>(inModel->name);
if (xModelAsset == NULL)
{
printf("XModel %s not found!\n", inModel->name.c_str());
currModel->model = NULL;
}
else
currModel->model = (XModel*)xModelAsset->Asset();
currModel->placement.origin.x = inModel->origin.x;
currModel->placement.origin.y = inModel->origin.y;
currModel->placement.origin.z = inModel->origin.z;
currModel->placement.origin = CMUtil::convertToBO2Coords(currModel->placement.origin);
currModel->placement.scale = inModel->scale;
CMUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
// mins and maxs are calculated in world space not local space
// TODO: this does not account for model rotation or scale
currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
currModelInst->mins.y = currModel->model->mins.y + currModel->placement.origin.y;
currModelInst->mins.z = currModel->model->mins.z + currModel->placement.origin.z;
currModelInst->maxs.x = currModel->model->maxs.x + currModel->placement.origin.x;
currModelInst->maxs.y = currModel->model->maxs.y + currModel->placement.origin.y;
currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
currModel->cullDist = DEFAULT_SMODEL_CULL_DIST;
currModel->flags = DEFAULT_SMODEL_FLAGS;
currModel->primaryLightIndex = DEFAULT_SMODEL_LIGHT;
currModel->reflectionProbeIndex = DEFAULT_SMODEL_REFLECTION_PROBE;
// unknown use / unused
currModel->smid = i;
memset(&currModel->lightingSH, 0, sizeof(GfxLightingSHQuantized));
currModel->invScaleSq = 0.0f;
currModel->lightingHandle = 0;
currModel->colorsIndex = 0;
currModel->visibility = 0;
// setting these to NULL makes any static/baked lighting go black when not rendered by real-time lighting or in a shadow
// TODO: calculate lighting and store it here
currModel->lmapVertexInfo[0].numLmapVertexColors = 0;
currModel->lmapVertexInfo[0].lmapVertexColors = NULL;
currModel->lmapVertexInfo[1].numLmapVertexColors = 0;
currModel->lmapVertexInfo[1].lmapVertexColors = NULL;
currModel->lmapVertexInfo[2].numLmapVertexColors = 0;
currModel->lmapVertexInfo[2].lmapVertexColors = NULL;
currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
currModel->lmapVertexInfo[3].lmapVertexColors = NULL;
}
// all visdata is alligned by 128
gfxWorld->dpvs.smodelVisDataCount = CMUtil::allignBy128(modelCount);
gfxWorld->dpvs.smodelVisData[0] = new char[modelCount];
gfxWorld->dpvs.smodelVisData[1] = new char[modelCount];
gfxWorld->dpvs.smodelVisData[2] = new char[modelCount];
gfxWorld->dpvs.smodelVisDataCameraSaved = new char[modelCount];
gfxWorld->dpvs.smodelCastsShadow = new char[modelCount];
int allignedModelCount = CMUtil::allignBy128(modelCount);
gfxWorld->dpvs.smodelVisDataCount = allignedModelCount;
gfxWorld->dpvs.smodelVisData[0] = new char[allignedModelCount];
gfxWorld->dpvs.smodelVisData[1] = new char[allignedModelCount];
gfxWorld->dpvs.smodelVisData[2] = new char[allignedModelCount];
gfxWorld->dpvs.smodelVisDataCameraSaved = new char[allignedModelCount];
gfxWorld->dpvs.smodelCastsShadow = new char[allignedModelCount];
memset(gfxWorld->dpvs.smodelVisData[0], 0, allignedModelCount);
memset(gfxWorld->dpvs.smodelVisData[1], 0, allignedModelCount);
memset(gfxWorld->dpvs.smodelVisData[2], 0, allignedModelCount);
memset(gfxWorld->dpvs.smodelVisDataCameraSaved, 0, allignedModelCount);
memset(gfxWorld->dpvs.smodelCastsShadow, 0, allignedModelCount);
for (unsigned int i = 0; i < modelCount; i++)
{
if ((gfxWorld->dpvs.smodelDrawInsts[i].flags & SMODEL_FLAG_NO_SHADOW) == 0)
@@ -357,16 +372,14 @@ private:
else
gfxWorld->dpvs.smodelCastsShadow[i] = 0;
}
memset(gfxWorld->dpvs.smodelVisData[0], 0, modelCount);
memset(gfxWorld->dpvs.smodelVisData[1], 0, modelCount);
memset(gfxWorld->dpvs.smodelVisData[2], 0, modelCount);
memset(gfxWorld->dpvs.smodelVisDataCameraSaved, 0, modelCount);
// always set to 0
gfxWorld->dpvs.usageCount = 0;
}
void cleanGfxWorld(GfxWorld* gfxWorld)
{
// checksum is generated by the game
gfxWorld->checksum = 0;
// Remove Coronas
@@ -513,22 +526,16 @@ private:
memset(gfxWorld->lightGrid.rowDataStart, 0, rowDataStartSize * sizeof(uint16_t));
gfxWorld->lightGrid.rawRowDataSize = sizeof(GfxLightGridRow);
GfxLightGridRow* row = new GfxLightGridRow[1];
GfxLightGridRow* row = (GfxLightGridRow*)m_memory.AllocRaw(sizeof(GfxLightGridRow) + 0x10);
row->colStart = 0;
row->colCount = 0x1000; // 0x1000 as this is large enough for all checks done by the game
row->zStart = 0;
row->zCount = 0xFF; // 0xFF as this is large enough for all checks done by the game, but small enough not to mess with other checks
row->firstEntry = 0;
// this unknown part is weird, bo2 code uses up to unk5 and possibly onwards but the dumped rawRowData looks like it has a different structure.
// this seems to work though
row->unk.unknown1 = 0;
row->unk.unknown2 = 0;
row->unk.unknown3 = 0;
row->unk.unknown4 = 0;
row->unk.unknown5 = 0;
row->unk.unknown6 = 0;
row->unk.unknown7 = 0;
row->unk.unknown8 = 0;
for (int i = 0; i < 0x11; i++) // set the lookup table to all 0
{
row->lookupTable[i] = 0;
}
gfxWorld->lightGrid.rawRowData = (aligned_byte_pointer*)row;
// entries are looked up based on the lightgrid sample pos and data within GfxLightGridRow
@@ -785,7 +792,7 @@ private:
gfxWorld->draw.lightmaps[0].secondary = secondaryTextureAsset->Asset();
}
void overwriteSkyBox(customMapInfo* projInfo, GfxWorld* gfxWorld)
void overwriteSkyBox(CustomMapBSP* projInfo, GfxWorld* gfxWorld)
{
std::string skyBoxName = "skybox_" + projInfo->name;
gfxWorld->skyBoxModel = _strdup(skyBoxName.c_str());
@@ -871,7 +878,7 @@ private:
gfxWorld->outdoorImage = outdoorImageAsset->Asset();
}
void createGfxWorld(customMapInfo* projInfo)
void createGfxWorld(CustomMapBSP* projInfo)
{
GfxWorld* gfxWorld = new GfxWorld;
gfxWorld->baseName = _strdup(projInfo->name.c_str());
@@ -915,7 +922,7 @@ private:
m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld);
}
void addXModelsToCollision(customMapInfo* projInfo, clipMap_t* clipMap)
void addXModelsToCollision(CustomMapBSP* projInfo, clipMap_t* clipMap)
{
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(projInfo->bspName);
_ASSERT(gfxWorldAsset != NULL);
@@ -992,20 +999,20 @@ private:
{
(*numLeafs)++;
// there won't be an AABB tree when objectList is empty
if (node->u.leaf->getObjectCount() > 0)
if (node->leaf->getObjectCount() > 0)
{
*numAABBTrees += node->u.leaf->getObjectCount() + 1;
*numAABBTrees += node->leaf->getObjectCount() + 1;
if (node->u.leaf->getObjectCount() > *maxObjsPerLeaf)
*maxObjsPerLeaf = node->u.leaf->getObjectCount();
if (node->leaf->getObjectCount() > *maxObjsPerLeaf)
*maxObjsPerLeaf = node->leaf->getObjectCount();
}
}
else
{
(*numPlanes)++;
(*numNodes)++;
traverseBSPTreeForCounts(node->u.node->front, numPlanes, numNodes, numLeafs, numAABBTrees, maxObjsPerLeaf);
traverseBSPTreeForCounts(node->u.node->back, numPlanes, numNodes, numLeafs, numAABBTrees, maxObjsPerLeaf);
traverseBSPTreeForCounts(node->node->front.get(), numPlanes, numNodes, numLeafs, numAABBTrees, maxObjsPerLeaf);
traverseBSPTreeForCounts(node->node->back.get(), numPlanes, numNodes, numLeafs, numAABBTrees, maxObjsPerLeaf);
}
}
@@ -1022,14 +1029,14 @@ private:
{
_ASSERT(node->isLeaf);
int objectCount = node->u.leaf->getObjectCount();
int objectCount = node->leaf->getObjectCount();
int firstAABBIndex = currAABBCount;
currAABBCount += objectCount + 1;
// calculate root AABB node mins and maxs
// cannot convert mins and maxs coord to BO2 directly as this will result in incorrect mins and maxs
// so we have to recompute every min and max, not hard just tedious
int firstPartitionIndex = node->u.leaf->getObject(0)->partitionIndex;
int firstPartitionIndex = node->leaf->getObject(0)->partitionIndex;
auto firstPartition = &clipMap->partitions[firstPartitionIndex];
uint16_t* firstTri = clipMap->triIndices[firstPartition->firstTri];
vec3_t* firstVert = &clipMap->verts[firstTri[0]];
@@ -1043,7 +1050,7 @@ private:
aabbMaxs.z = firstVert->z;
for (int i = 0; i < objectCount; i++)
{
int currPartitionIndex = node->u.leaf->getObject(i)->partitionIndex;
int currPartitionIndex = node->leaf->getObject(i)->partitionIndex;
auto currPartition = &clipMap->partitions[currPartitionIndex];
for (int k = 0; k < currPartition->triCount; k++)
@@ -1067,7 +1074,7 @@ private:
for (int i = 0; i < objectCount; i++)
{
CollisionAabbTree* currAabbTree = &clipMap->aabbTrees[rootAABB->u.firstChildIndex + i];
int currPartitionIndex = node->u.leaf->getObject(i)->partitionIndex;
int currPartitionIndex = node->leaf->getObject(i)->partitionIndex;
currAabbTree->materialIndex = 0;
currAabbTree->childCount = 0;
@@ -1126,7 +1133,7 @@ private:
currLeaf->maxs.z = 0.0f;
currLeaf->leafBrushNode = 0;
if (node->u.leaf->getObjectCount() > 0)
if (node->leaf->getObjectCount() > 0)
{
currLeaf->firstCollAabbIndex = addAABBTreeFromLeaf(node, clipMap);
currLeaf->collAabbCount = 1;
@@ -1144,14 +1151,14 @@ private:
cplane_s* currPlane = &clipMap->info.planes[currPlaneCount];
currPlaneCount++;
if (node->u.node->axis == AXIS_X)
if (node->node->axis == AXIS_X)
{
// X is unchanged when going from OGL x -> BO2 x
currPlane->normal = normalX;
// converting OGL -> BO2 X coords doesn't change the x coords at all, so
// the dist stays the same
currPlane->dist = (float)node->u.node->distance;
currPlane->dist = (float)node->node->distance;
}
else
{
@@ -1163,7 +1170,7 @@ private:
// converting OGL -> BO2 Z coords negates the z coords and sets it to the y coord.
// just negate it here as it is just the distance from the orgin along the axis
currPlane->dist = (float)(-node->u.node->distance);
currPlane->dist = (float)(-node->node->distance);
}
bool foundType = false;
@@ -1211,13 +1218,13 @@ private:
// Do the OGL -> Bo2 coord change on paper and it will make sense
if (currPlane->type == 1)
{
currNode->children[1] = populateBSPTree_r(clipMap, node->u.node->front);
currNode->children[0] = populateBSPTree_r(clipMap, node->u.node->back);
currNode->children[1] = populateBSPTree_r(clipMap, node->node->front.get());
currNode->children[0] = populateBSPTree_r(clipMap, node->node->back.get());
}
else
{
currNode->children[0] = populateBSPTree_r(clipMap, node->u.node->front);
currNode->children[1] = populateBSPTree_r(clipMap, node->u.node->back);
currNode->children[0] = populateBSPTree_r(clipMap, node->node->front.get());
currNode->children[1] = populateBSPTree_r(clipMap, node->node->back.get());
}
return currNodeIndex;
@@ -1263,14 +1270,14 @@ private:
_ASSERT(clipMap->aabbTreeCount == currAABBCount);
}
void createPartitions(customMapInfo* projInfo, clipMap_t* clipMap)
void createPartitions(CustomMapBSP* projInfo, clipMap_t* clipMap)
{
int collisionVertexCount = projInfo->colInfo.vertexCount;
int collisionVertexCount = projInfo->colWorld.vertices.size();
std::vector<vec3_t> collisionVertVec;
for (int i = 0; i < collisionVertexCount; i++)
{
collisionVertVec.push_back(CMUtil::convertToBO2Coords(projInfo->colInfo.vertices[i].pos));
//collisionVertVec.push_back(projInfo->colInfo.vertices[i].pos);
collisionVertVec.push_back(CMUtil::convertToBO2Coords(projInfo->colWorld.vertices[i].pos));
//collisionVertVec.push_back(projInfo->colWorld.vertices[i].pos);
}
clipMap->vertCount = collisionVertexCount;
clipMap->verts = new vec3_t[collisionVertexCount];
@@ -1286,21 +1293,21 @@ private:
}
std::vector<uint16_t> triIndexVec;
for (int i = 0; i < projInfo->colInfo.surfaceCount; i++)
for (size_t i = 0; i < projInfo->colWorld.surfaces.size(); i++)
{
worldSurface* currSurface = &projInfo->colInfo.surfaces[i];
CustomMapSurface* currSurface = &projInfo->colWorld.surfaces[i];
int triCount = currSurface->triCount;
for (int k = 0; k < triCount * 3; k += 3)
{
int firstIndex_Index = currSurface->firstIndex_Index;
int firstVertexIndex = currSurface->firstVertexIndex;
int firstIndex_Index = currSurface->indexOfFirstIndex;
int firstVertexIndex = currSurface->indexOfFirstVertex;
// gfx index bufer starts at 0 for each new mesh, while the clipmap index buffer indexes the entire
// clipmap verts buffer, so this code updates the indexes to follow that.
int triIndex0 = projInfo->colInfo.indices[firstIndex_Index + (k + 0)] + firstVertexIndex;
int triIndex1 = projInfo->colInfo.indices[firstIndex_Index + (k + 1)] + firstVertexIndex;
int triIndex2 = projInfo->colInfo.indices[firstIndex_Index + (k + 2)] + firstVertexIndex;
int triIndex0 = projInfo->colWorld.indices[firstIndex_Index + (k + 0)] + firstVertexIndex;
int triIndex1 = projInfo->colWorld.indices[firstIndex_Index + (k + 1)] + firstVertexIndex;
int triIndex2 = projInfo->colWorld.indices[firstIndex_Index + (k + 2)] + firstVertexIndex;
// triangle index ordering is opposite to blenders, so its converted here
triIndexVec.push_back(triIndex2);
@@ -1317,10 +1324,10 @@ private:
// 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
std::vector<CollisionPartition> partitionVec;
for (int i = 0; i < projInfo->colInfo.surfaceCount; i++)
for (size_t i = 0; i < projInfo->colWorld.surfaces.size(); i++)
{
int triCount = projInfo->colInfo.surfaces[i].triCount;
int firstTriIndex = projInfo->colInfo.surfaces[i].firstIndex_Index / 3;
int triCount = projInfo->colWorld.surfaces[i].triCount;
int firstTriIndex = projInfo->colWorld.surfaces[i].indexOfFirstIndex / 3;
for (int k = 0; k < triCount; k++)
{
CollisionPartition newPartition;
@@ -1375,7 +1382,7 @@ private:
memcpy(clipMap->info.uinds, &uindVec[0], sizeof(uint16_t) * totalUindCount);
}
void createClipMap(customMapInfo* projInfo)
void createClipMap(CustomMapBSP* projInfo)
{
clipMap_t* clipMap = new clipMap_t;
@@ -1605,9 +1612,9 @@ private:
}
}
Object* currObject = new Object(mins.x, mins.y, mins.z, maxs.x, maxs.y, maxs.z, i);
std::shared_ptr<Object> currObject = std::make_shared<Object>(mins.x, mins.y, mins.z, maxs.x, maxs.y, maxs.z, i);
tree->addObject(currObject);
tree->addObjectToTree(std::move(currObject));
}
populateBSPTree(clipMap, tree);
@@ -1615,7 +1622,7 @@ private:
m_context.AddAsset<AssetClipMapPvs>(clipMap->name, clipMap);
}
void createComWorld(customMapInfo* projInfo)
void createComWorld(CustomMapBSP* projInfo)
{
// all lights that aren't the sunlight or default light need their own GfxLightDef asset
ComWorld* comWorld = new ComWorld;
@@ -1800,7 +1807,7 @@ private:
}
}
void createMapEnts(customMapInfo* projInfo)
void createMapEnts(CustomMapBSP* projInfo)
{
MapEnts* mapEnts = new MapEnts;
@@ -1862,7 +1869,7 @@ private:
m_context.AddAsset<AssetMapEnts>(mapEnts->name, mapEnts);
}
void createGameWorldMp(customMapInfo* projInfo)
void createGameWorldMp(CustomMapBSP* projInfo)
{
GameWorldMp* gameWorldMp = new GameWorldMp;
@@ -1887,11 +1894,13 @@ private:
m_context.AddAsset<AssetGameWorldMp>(gameWorldMp->name, gameWorldMp);
}
void createSkinnedVerts(customMapInfo* projInfo)
void createSkinnedVerts(CustomMapBSP* projInfo)
{
SkinnedVertsDef* skinnedVerts = new SkinnedVertsDef;
skinnedVerts->name = "skinnedverts";
skinnedVerts->maxSkinnedVerts = projInfo->gfxInfo.vertexCount;
skinnedVerts->maxSkinnedVerts = projInfo->gfxWorld.vertices.size();
// I'm 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
m_context.AddAsset<AssetSkinnedVerts>("skinnedverts", skinnedVerts);
}
@@ -1910,7 +1919,7 @@ private:
return footstepTable;
}
void checkAndAddDefaultRequiredAssets(customMapInfo* projectInfo)
void checkAndAddDefaultRequiredAssets(CustomMapBSP* projectInfo)
{
auto templateFile = m_search_path.Open("materials/material_template.json");
if (!templateFile.IsOpen())

View File

@@ -1,6 +1,7 @@
#pragma once
#include <cmath>
#include <format>
#include "Game/T6/T6.h"
using namespace T6;