From 7d09877d02afce02097c243383592f3ccc3213e7 Mon Sep 17 00:00:00 2001 From: LJW-Dev Date: Tue, 21 Oct 2025 17:37:56 +0800 Subject: [PATCH] WIP: - 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 --- .../T6/CustomMap/BinarySpacePartitionTree.cpp | 147 +++++++++ .../T6/CustomMap/BinarySpacePartitionTree.h | 209 +++--------- .../Game/T6/CustomMap/CustomMapLinker.h | 307 +++++++++--------- src/ObjLoading/Game/T6/CustomMap/Util.h | 1 + 4 files changed, 344 insertions(+), 320 deletions(-) diff --git a/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.cpp b/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.cpp index e69de29b..644f86a7 100644 --- a/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.cpp +++ b/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.cpp @@ -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) +{ + 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 frontTree, std::unique_ptr 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 front; + std::unique_ptr 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(halfLength, min.y, min.z, max.x, max.y, max.z, level + 1); + back = std::make_unique(min.x, min.y, min.z, halfLength, max.y, max.z, level + 1); + + isLeaf = false; + node = std::make_unique(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(min.x, min.y, halfLength, max.x, max.y, max.z, level + 1); + back = std::make_unique(min.x, min.y, min.z, max.x, max.y, halfLength, level + 1); + + isLeaf = false; + node = std::make_unique(std::move(front), std::move(back), AXIS_Z, halfLength); + leaf = nullptr; + } + else + { + isLeaf = true; + node = nullptr; + leaf = std::make_unique(); + } +} + +void BSPTree::addObjectToTree(std::shared_ptr 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); + } + } +} \ No newline at end of file diff --git a/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.h b/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.h index 52ea1e0c..7a63478a 100644 --- a/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.h +++ b/src/ObjLoading/Game/T6/CustomMap/BinarySpacePartitionTree.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #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> objectList; - -public: - void addObject(std::unique_ptr object) - { - objectList.push_back(std::move(object)); - } - - std::unique_ptr 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> objectList; + + void addObject(std::shared_ptr object); + Object* getObject(int index); + int getObjectCount(); +}; + +class BSPTree; + class BSPNode { public: - BSPTree* front; - BSPTree* back; + std::unique_ptr front; + std::unique_ptr 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 frontTree, std::unique_ptr backTree, PlaneAxis nodeAxis, float nodeDistance); + PlaneSide objectIsInfront(Object* object); }; class BSPTree { public: bool isLeaf; - u_BSPNode u; + std::unique_ptr leaf; + std::unique_ptr 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); }; diff --git a/src/ObjLoading/Game/T6/CustomMap/CustomMapLinker.h b/src/ObjLoading/Game/T6/CustomMap/CustomMapLinker.h index 9f0de39a..4361f834 100644 --- a/src/ObjLoading/Game/T6/CustomMap/CustomMapLinker.h +++ b/src/ObjLoading/Game/T6/CustomMap/CustomMapLinker.h @@ -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(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(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(gfxWorld->name, gfxWorld); } - void addXModelsToCollision(customMapInfo* projInfo, clipMap_t* clipMap) + void addXModelsToCollision(CustomMapBSP* projInfo, clipMap_t* clipMap) { auto gfxWorldAsset = m_context.LoadDependency(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 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 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 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 currObject = std::make_shared(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(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(mapEnts->name, mapEnts); } - void createGameWorldMp(customMapInfo* projInfo) + void createGameWorldMp(CustomMapBSP* projInfo) { GameWorldMp* gameWorldMp = new GameWorldMp; @@ -1887,11 +1894,13 @@ private: m_context.AddAsset(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("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()) diff --git a/src/ObjLoading/Game/T6/CustomMap/Util.h b/src/ObjLoading/Game/T6/CustomMap/Util.h index 1d23a831..e8292aba 100644 --- a/src/ObjLoading/Game/T6/CustomMap/Util.h +++ b/src/ObjLoading/Game/T6/CustomMap/Util.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "Game/T6/T6.h" using namespace T6;