diff --git a/src/ObjLoading/Game/T6/BSP/BSP.h b/src/ObjLoading/Game/T6/BSP/BSP.h index 3a2f1dfe..2635981e 100644 --- a/src/ObjLoading/Game/T6/BSP/BSP.h +++ b/src/ObjLoading/Game/T6/BSP/BSP.h @@ -43,12 +43,26 @@ namespace BSP int indexOfFirstIndex; }; + struct BSPXModel + { + std::string name; + + vec3_t origin; + vec4_t rotationQuaternion; + float scale; + + bool areBoundsValid; + vec3_t mins; + vec3_t maxs; + }; + struct BSPWorld { std::vector surfaces; std::vector vertices; std::vector indices; std::vector materials; + std::vector xmodels; }; enum BSPLightType @@ -74,21 +88,6 @@ namespace BSP float outerConeAngle; }; - struct BSPXModel - { - std::string name; - - vec3_t origin; - float scale; - vec3_t forward; - vec3_t right; - vec3_t up; - - bool areBoundsValid; - vec3_t mins; - vec3_t maxs; - }; - enum BSPSpawnPointType { SPAWNPOINT_TYPE_DEFENDER, @@ -112,7 +111,6 @@ namespace BSP BSPWorld colWorld; std::vector lights; - std::vector xmodels; std::vector spawnpoints; }; diff --git a/src/ObjLoading/Game/T6/BSP/BSPCreator.cpp b/src/ObjLoading/Game/T6/BSP/BSPCreator.cpp index 1708e59a..49206de7 100644 --- a/src/ObjLoading/Game/T6/BSP/BSPCreator.cpp +++ b/src/ObjLoading/Game/T6/BSP/BSPCreator.cpp @@ -32,6 +32,16 @@ namespace unsigned m_index_accessor; }; + void RhcToLhcQuaternion(float (&coords)[4]) + { + const float two[4]{coords[0], coords[1], coords[2], coords[3]}; + + coords[0] = two[0]; + coords[1] = -two[2]; + coords[2] = two[1]; + coords[3] = two[3]; + } + void RhcToLhcCoordinates(float (&coords)[3]) { const float two[3]{coords[0], coords[1], coords[2]}; @@ -392,8 +402,110 @@ namespace return true; } - bool addXModelNode(const gltf::JsonNode& node) + void calculateXmodelBounds(BSPXModel& xmodel, std::optional meshIndex, Eigen::Matrix4f& nodeMatrix, const JsonRoot& jRoot) { + if (meshIndex) + { + xmodel.areBoundsValid = true; + Eigen::Vector4f position(0, 0, 0, 1.0f); + Eigen::Vector4f transformedPosition = nodeMatrix * position; + xmodel.mins.x = transformedPosition.x(); + xmodel.mins.y = transformedPosition.y(); + xmodel.mins.z = transformedPosition.z(); + xmodel.maxs.x = transformedPosition.x(); + xmodel.maxs.y = transformedPosition.y(); + xmodel.maxs.z = transformedPosition.z(); + RhcToLhcCoordinates(xmodel.mins.v); + RhcToLhcCoordinates(xmodel.maxs.v); + + const auto& mesh = jRoot.meshes.value()[*meshIndex]; + for (size_t primIdx = 0; primIdx < mesh.primitives.size(); primIdx++) + { + const auto& primitive = mesh.primitives.at(primIdx); + + if (!primitive.attributes.POSITION) + throw GltfLoadException("Requires primitives attribute POSITION"); + + // clang-format off + const auto* positionAccessor = GetAccessorForIndex( + "POSITION", + primitive.attributes.POSITION, + { JsonAccessorType::VEC3 }, + { JsonAccessorComponentType::FLOAT } + ).value_or(nullptr); + // clang-format on + assert(positionAccessor != nullptr); + + for (size_t vertexIndex = 0u; vertexIndex < positionAccessor->GetCount(); vertexIndex++) + { + vec3_t vertex; + if (!positionAccessor->GetFloatVec3(vertexIndex, vertex.v)) + assert(false); + + Eigen::Vector4f position(vertex.x, vertex.y, vertex.z, 1.0f); + Eigen::Vector4f transformedPosition = nodeMatrix * position; + vertex.x = transformedPosition.x(); + vertex.y = transformedPosition.y(); + vertex.z = transformedPosition.z(); + RhcToLhcCoordinates(vertex.v); + + if (vertexIndex == 0 && primIdx == 0) + { + xmodel.mins = vertex; + xmodel.maxs = vertex; + } + else + BSPUtil::updateAABBWithPoint(vertex, xmodel.mins, xmodel.maxs); + } + } + } + else + { + xmodel.areBoundsValid = false; + xmodel.mins.x = 0.0f; + xmodel.mins.y = 0.0f; + xmodel.mins.z = 0.0f; + xmodel.maxs.x = 0.0f; + xmodel.maxs.y = 0.0f; + xmodel.maxs.z = 0.0f; + } + } + + bool addXModelNode(const JsonRoot& jRoot, const gltf::JsonNode& node) + { + assert(node.extras); + assert(node.extras->xmodel); + + Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); + BSPXModel xmodel; + + if (node.extras->xmodel->size() == 0) + throw GltfLoadException("Xmodel has no name."); + xmodel.name = *node.extras->xmodel; + + Eigen::Vector4f position(0, 0, 0, 1.0f); + Eigen::Vector4f transformedPosition = nodeMatrix * position; + xmodel.origin.x = transformedPosition.x(); + xmodel.origin.y = transformedPosition.y(); + xmodel.origin.z = transformedPosition.z(); + RhcToLhcCoordinates(xmodel.origin.v); + + Eigen::Affine3f affineTransform(nodeMatrix); + Eigen::Quaternionf rotationQuat(affineTransform.rotation()); + rotationQuat.normalize(); + xmodel.rotationQuaternion.x = rotationQuat.x(); + xmodel.rotationQuaternion.y = rotationQuat.y(); + xmodel.rotationQuaternion.z = rotationQuat.z(); + xmodel.rotationQuaternion.w = rotationQuat.w(); // Eigen is WXYZ, game is XYZW + RhcToLhcQuaternion(xmodel.rotationQuaternion.v); + + con::warn("XModels don't support scale currently, keep it at 1 in your editor"); + xmodel.scale = 1.0f; + + calculateXmodelBounds(xmodel, node.mesh, nodeMatrix, jRoot); + + m_curr_bsp_world->xmodels.emplace_back(xmodel); + return true; } @@ -447,8 +559,8 @@ namespace if (node.extras) { - if (m_is_world_gfx && node.extras->xmodel) - return addXModelNode(node); + if (node.extras->xmodel) + return addXModelNode(jRoot, node); if (m_is_world_gfx && node.extras->spawnpoint) return addSpawnPointNode(node); diff --git a/src/ObjLoading/Game/T6/BSP/BSPUtil.cpp b/src/ObjLoading/Game/T6/BSP/BSPUtil.cpp index 28c170db..00002025 100644 --- a/src/ObjLoading/Game/T6/BSP/BSPUtil.cpp +++ b/src/ObjLoading/Game/T6/BSP/BSPUtil.cpp @@ -104,7 +104,43 @@ namespace BSP return sqrtf((x * x) + (y * y) + (z * z)); } - void BSPUtil::convertAnglesToAxis(vec3_t* angles, vec3_t* axis) + void BSPUtil::calculateXmodelBounds(XModel* xmodel, vec3_t axis[3], vec3_t& out_mins, vec3_t& out_maxs) + { + out_mins.x = 0.0f; + out_mins.y = 0.0f; + out_mins.z = 0.0f; + out_maxs.x = 0.0f; + out_maxs.y = 0.0f; + out_maxs.z = 0.0f; + + for (auto surfaceIndex = 0u; surfaceIndex < xmodel->lodInfo[0].numsurfs; surfaceIndex++) + { + const auto& surface = xmodel->surfs[surfaceIndex + xmodel->lodInfo[0].surfIndex]; + + if (!surface.verts0) + continue; + + for (auto vertIndex = 0u; vertIndex < surface.vertCount; vertIndex++) + { + const auto& vertex = surface.verts0[vertIndex].xyz; + + vec3_t rotatedVert; + rotatedVert.x = (vertex.x * axis[0].x) + (vertex.y * axis[1].x) + (vertex.z * axis[2].x); + rotatedVert.y = (vertex.x * axis[0].y) + (vertex.y * axis[1].y) + (vertex.z * axis[2].y); + rotatedVert.z = (vertex.x * axis[0].z) + (vertex.y * axis[1].z) + (vertex.z * axis[2].z); + + if (vertIndex == 0 && surfaceIndex == 0) + { + out_mins = rotatedVert; + out_maxs = rotatedVert; + } + else + BSPUtil::updateAABBWithPoint(rotatedVert, out_mins, out_maxs); + } + } + } + + void BSPUtil::convertAnglesToAxis(vec3_t* angles, vec3_t axis[3]) { float cosX = cos(angles->x); float sinX = sin(angles->x); @@ -124,6 +160,38 @@ namespace BSP axis[2].z = cosZ * cosX; } + void BSPUtil::convertQuaternionToAxis(vec4_t* quat, vec3_t axis[3]) + { + float quatX = quat->v[0]; + float quatY = quat->v[1]; + float quatZ = quat->v[2]; + float quatW = quat->v[3]; + + float xx = (quatX * 2.0) * quatX; + float xy = (quatX * 2.0) * quatY; + float xz = (quatX * 2.0) * quatZ; + float xw = (quatX * 2.0) * quatW; + + float yy = (quatY * 2.0) * quatY; + float yz = (quatY * 2.0) * quatZ; + float yw = (quatY * 2.0) * quatW; + + float zz = (quatZ * 2.0) * quatZ; + float zw = (quatZ * 2.0) * quatW; + + axis->x = 1.0f - (zz + yy); + axis->y = zw + xy; + axis->z = xz - yw; + + axis[1].x = xy - zw; + axis[1].y = 1.0f - (zz + xx); + axis[1].z = yz + xw; + + axis[2].x = yw + xz; + axis[2].y = yz - xw; + axis[2].z = 1.0f - (yy + xx); + } + vec3_t BSPUtil::convertForwardVectorToViewAngles(vec3_t& forwardVec) { vec3_t viewAngles; diff --git a/src/ObjLoading/Game/T6/BSP/BSPUtil.h b/src/ObjLoading/Game/T6/BSP/BSPUtil.h index 1e3b2ba7..96fd0506 100644 --- a/src/ObjLoading/Game/T6/BSP/BSPUtil.h +++ b/src/ObjLoading/Game/T6/BSP/BSPUtil.h @@ -16,7 +16,9 @@ namespace BSP static vec3_t calcHalfSizeOfAABB(vec3_t& mins, vec3_t& maxs); static size_t allignBy128(size_t size); static float distBetweenPoints(vec3_t& p1, vec3_t& p2); - static void convertAnglesToAxis(vec3_t* angles, vec3_t* axis); + static void calculateXmodelBounds(XModel* xmodel, vec3_t axis[3], vec3_t& out_mins, vec3_t& out_maxs); + static void convertAnglesToAxis(vec3_t* angles, vec3_t axis[3]); + static void convertQuaternionToAxis(vec4_t* quat, vec3_t axis[3]); static vec3_t convertForwardVectorToViewAngles(vec3_t& forwardVec); static void matrixTranspose3x3(const vec3_t* in, vec3_t* out); static vec3_t convertStringToVec3(std::string& str); diff --git a/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.cpp b/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.cpp index 6536be8d..d5ac6fc3 100644 --- a/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.cpp +++ b/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.cpp @@ -154,54 +154,77 @@ namespace BSP clipMap->cmodels[0].info = nullptr; } - void ClipMapLinker::loadXModelCollision(clipMap_t* clipMap) + bool ClipMapLinker::loadXModelCollision(clipMap_t* clipMap, BSPData* bsp) { - // Right now XModels aren't supported - clipMap->numStaticModels = 0; - clipMap->staticModelList = nullptr; - - // WIP code left in for future support - /* - auto gfxWorldAsset = m_context.LoadDependency(bsp->bspName); - assert(gfxWorldAsset != nullptr); - GfxWorld* gfxWorld = gfxWorldAsset->Asset(); - - clipMap->numStaticModels = gfxWorld->dpvs.smodelCount; + clipMap->numStaticModels = bsp->colWorld.xmodels.size(); clipMap->staticModelList = new cStaticModel_s[clipMap->numStaticModels]; for (unsigned int i = 0; i < clipMap->numStaticModels; i++) { - GfxStaticModelDrawInst* gfxModelDrawInst = &gfxWorld->dpvs.smodelDrawInsts[i]; - GfxStaticModelInst* gfxModelInst = &gfxWorld->dpvs.smodelInsts[i]; cStaticModel_s* currModel = &clipMap->staticModelList[i]; + BSPXModel& bspModel = bsp->colWorld.xmodels.at(i); + + vec3_t xmodelAxis[3]; + BSPUtil::convertQuaternionToAxis(&bspModel.rotationQuaternion, xmodelAxis); + + auto xModelAsset = m_context.LoadDependency(bspModel.name); + if (xModelAsset == nullptr) + { + con::error("Unable to load xmodel asset: \"{}\"", bspModel.name); + return false; + } + else + currModel->xmodel = (XModel*)xModelAsset->Asset(); + + currModel->origin.x = bspModel.origin.x; + currModel->origin.y = bspModel.origin.y; + currModel->origin.z = bspModel.origin.z; + + currModel->contents = 1; + // currModel->contents = currModel->xmodel->contents; + + if (!xModelAsset->IsReference()) + { + BSPUtil::calculateXmodelBounds(currModel->xmodel, xmodelAxis, currModel->absmin, currModel->absmax); + currModel->absmin.x = (currModel->absmin.x * bspModel.scale) + bspModel.origin.x; + currModel->absmin.y = (currModel->absmin.y * bspModel.scale) + bspModel.origin.y; + currModel->absmin.z = (currModel->absmin.z * bspModel.scale) + bspModel.origin.z; + currModel->absmax.x = (currModel->absmax.x * bspModel.scale) + bspModel.origin.x; + currModel->absmax.y = (currModel->absmax.y * bspModel.scale) + bspModel.origin.y; + currModel->absmax.z = (currModel->absmax.z * bspModel.scale) + bspModel.origin.z; + } + else + { + if (bspModel.areBoundsValid) + { + currModel->absmin = bspModel.mins; + currModel->absmax = bspModel.maxs; + } + else + { + con::warn("Unable to determine the bounds of xmodel: \"{}\"", bspModel.name); + currModel->absmin.x = bspModel.origin.x - 1.0f; + currModel->absmin.y = bspModel.origin.y - 1.0f; + currModel->absmin.z = bspModel.origin.z - 1.0f; + currModel->absmax.x = bspModel.origin.x + 1.0f; + currModel->absmax.y = bspModel.origin.y + 1.0f; + currModel->absmax.z = bspModel.origin.z + 1.0f; + } + } + + BSPUtil::matrixTranspose3x3(xmodelAxis, currModel->invScaledAxis); + currModel->invScaledAxis[0].x = (1.0f / bspModel.scale) * currModel->invScaledAxis[0].x; + currModel->invScaledAxis[0].y = (1.0f / bspModel.scale) * currModel->invScaledAxis[0].y; + currModel->invScaledAxis[0].z = (1.0f / bspModel.scale) * currModel->invScaledAxis[0].z; + currModel->invScaledAxis[1].x = (1.0f / bspModel.scale) * currModel->invScaledAxis[1].x; + currModel->invScaledAxis[1].y = (1.0f / bspModel.scale) * currModel->invScaledAxis[1].y; + currModel->invScaledAxis[1].z = (1.0f / bspModel.scale) * currModel->invScaledAxis[1].z; + currModel->invScaledAxis[2].x = (1.0f / bspModel.scale) * currModel->invScaledAxis[2].x; + currModel->invScaledAxis[2].y = (1.0f / bspModel.scale) * currModel->invScaledAxis[2].y; + currModel->invScaledAxis[2].z = (1.0f / bspModel.scale) * currModel->invScaledAxis[2].z; memset(&currModel->writable, 0, sizeof(cStaticModelWritable)); - currModel->xmodel = gfxModelDrawInst->model; - currModel->contents = gfxModelDrawInst->model->contents; - currModel->origin.x = gfxModelDrawInst->placement.origin.x; - currModel->origin.y = gfxModelDrawInst->placement.origin.y; - currModel->origin.z = gfxModelDrawInst->placement.origin.z; - - // TODO: this does not account for model rotation or scale - currModel->absmin.x = gfxModelInst->mins.x; - currModel->absmin.y = gfxModelInst->mins.y; - currModel->absmin.z = gfxModelInst->mins.z; - currModel->absmax.x = gfxModelInst->maxs.x; - currModel->absmax.y = gfxModelInst->maxs.y; - currModel->absmax.z = gfxModelInst->maxs.z; - - BSPUtil::matrixTranspose3x3(gfxModelDrawInst->placement.axis, currModel->invScaledAxis); - currModel->invScaledAxis[0].x = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[0].x; - currModel->invScaledAxis[0].y = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[0].y; - currModel->invScaledAxis[0].z = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[0].z; - currModel->invScaledAxis[1].x = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[1].x; - currModel->invScaledAxis[1].y = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[1].y; - currModel->invScaledAxis[1].z = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[1].z; - currModel->invScaledAxis[2].x = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[2].x; - currModel->invScaledAxis[2].y = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[2].y; - currModel->invScaledAxis[2].z = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[2].z; } - */ } // out_mins and out_maxs are initialised in the function @@ -691,7 +714,7 @@ namespace BSP loadDynEnts(clipMap); - loadXModelCollision(clipMap); + loadXModelCollision(clipMap, bsp); loadMaterials(clipMap, bsp); diff --git a/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.h b/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.h index a4f5f19c..38580075 100644 --- a/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.h +++ b/src/ObjLoading/Game/T6/BSP/Linker/ClipMapLinker.h @@ -24,7 +24,7 @@ namespace BSP void loadDynEnts(clipMap_t* clipMap); void loadRopesAndConstraints(clipMap_t* clipMap); void loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp); - void loadXModelCollision(clipMap_t* clipMap); + bool loadXModelCollision(clipMap_t* clipMap, BSPData* bsp); std::vector planeVec; std::vector nodeVec; diff --git a/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.cpp b/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.cpp index 7b27cf83..c2a6710c 100644 --- a/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.cpp +++ b/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.cpp @@ -145,79 +145,90 @@ namespace BSP return true; } - void GfxWorldLinker::loadXModels(BSPData* bsp, GfxWorld* gfxWorld) + bool GfxWorldLinker::loadXModels(BSPData* bsp, GfxWorld* gfxWorld) { - /* - Models are unsupported right now - Code is left in in case it is supported later on - - unsigned int modelCount = projInfo->modelCount; + size_t modelCount = bsp->gfxWorld.xmodels.size(); gfxWorld->dpvs.smodelCount = modelCount; gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount]; gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount]; - for (unsigned int i = 0; i < modelCount; i++) + for (size_t modelIdx = 0; modelIdx < modelCount; modelIdx++) { - auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i]; - auto currModelInst = &gfxWorld->dpvs.smodelInsts[i]; - customMapModel* inModel = &projInfo->models[i]; + auto currModel = &gfxWorld->dpvs.smodelDrawInsts[modelIdx]; + auto currModelInst = &gfxWorld->dpvs.smodelInsts[modelIdx]; + BSPXModel& bspModel = bsp->gfxWorld.xmodels.at(modelIdx); - auto xModelAsset = m_context.LoadDependency(inModel->name); - if (xModelAsset == nullptr) + auto xModelAsset = m_context.LoadDependency(bspModel.name); + if (xModelAsset == nullptr) + { + con::error("Unable to load xmodel asset: \"{}\"", bspModel.name); + return false; + } + else + currModel->model = (XModel*)xModelAsset->Asset(); + + currModel->placement.origin.x = bspModel.origin.x; + currModel->placement.origin.y = bspModel.origin.y; + currModel->placement.origin.z = bspModel.origin.z; + BSPUtil::convertQuaternionToAxis(&bspModel.rotationQuaternion, currModel->placement.axis); + currModel->placement.scale = bspModel.scale; + + currModel->cullDist = 10000.0f; + currModel->flags = 0; + currModel->primaryLightIndex = 0; + currModel->reflectionProbeIndex = 0; + currModel->smid = modelIdx; + + // unknown use / unused + memset(&currModel->lightingSH, 0, sizeof(GfxLightingSHQuantized)); + currModel->invScaleSq = 0.0f; + currModel->lightingHandle = 0; // overwritten to by the game + currModel->colorsIndex = 0; + currModel->visibility = 0; + + // setting these to nullptr 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 = 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; + + if (!xModelAsset->IsReference()) + { + BSPUtil::calculateXmodelBounds(currModel->model, currModel->placement.axis, currModelInst->mins, currModelInst->maxs); + currModelInst->mins.x = (currModelInst->mins.x * bspModel.scale) + bspModel.origin.x; + currModelInst->mins.y = (currModelInst->mins.y * bspModel.scale) + bspModel.origin.y; + currModelInst->mins.z = (currModelInst->mins.z * bspModel.scale) + bspModel.origin.z; + currModelInst->maxs.x = (currModelInst->maxs.x * bspModel.scale) + bspModel.origin.x; + currModelInst->maxs.y = (currModelInst->maxs.y * bspModel.scale) + bspModel.origin.y; + currModelInst->maxs.z = (currModelInst->maxs.z * bspModel.scale) + bspModel.origin.z; + } + else + { + if (bspModel.areBoundsValid) { - printf("XModel %s not found!\n", inModel->name.c_str()); - currModel->model = nullptr; + currModelInst->mins = bspModel.mins; + currModelInst->maxs = bspModel.maxs; } 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 = BSPUtil::convertToBO2Coords(currModel->placement.origin); - currModel->placement.scale = inModel->scale; - - BSPUtil::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 nullptr 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 = 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; + { + con::warn("Unable to determine the bounds of xmodel: \"{}\"", bspModel.name); + currModelInst->mins.x = bspModel.origin.x - 1.0f; + currModelInst->mins.y = bspModel.origin.y - 1.0f; + currModelInst->mins.z = bspModel.origin.z - 1.0f; + currModelInst->maxs.x = bspModel.origin.x + 1.0f; + currModelInst->maxs.y = bspModel.origin.y + 1.0f; + currModelInst->maxs.z = bspModel.origin.z + 1.0f; + } + } + currModelInst->lightingOrigin.x = 0.0f; + currModelInst->lightingOrigin.y = 0.0f; + currModelInst->lightingOrigin.z = 0.0f; } - */ - - unsigned int modelCount = 0; - gfxWorld->dpvs.smodelCount = modelCount; - gfxWorld->dpvs.smodelInsts = m_memory.Alloc(modelCount); - gfxWorld->dpvs.smodelDrawInsts = m_memory.Alloc(modelCount); // visdata is written to by the game // all visdata is alligned by 128 @@ -228,7 +239,7 @@ namespace BSP gfxWorld->dpvs.smodelVisData[2] = m_memory.Alloc(allignedModelCount); gfxWorld->dpvs.smodelVisDataCameraSaved = m_memory.Alloc(allignedModelCount); gfxWorld->dpvs.smodelCastsShadow = m_memory.Alloc(allignedModelCount); - for (unsigned int i = 0; i < modelCount; i++) + for (size_t i = 0; i < modelCount; i++) { if ((gfxWorld->dpvs.smodelDrawInsts[i].flags & STATIC_MODEL_FLAG_NO_SHADOW) == 0) gfxWorld->dpvs.smodelCastsShadow[i] = 1; @@ -236,8 +247,7 @@ namespace BSP gfxWorld->dpvs.smodelCastsShadow[i] = 0; } - // official maps set this to 0 - gfxWorld->dpvs.usageCount = 0; + return true; } void GfxWorldLinker::cleanGfxWorld(GfxWorld* gfxWorld) @@ -245,6 +255,9 @@ namespace BSP // checksum is generated by the game gfxWorld->checksum = 0; + // official maps set this to 0 + gfxWorld->dpvs.usageCount = 0; + // Remove Coronas gfxWorld->coronaCount = 0; gfxWorld->coronas = nullptr; @@ -735,7 +748,8 @@ namespace BSP if (!loadMapSurfaces(bsp, gfxWorld)) return nullptr; - loadXModels(bsp, gfxWorld); + if (!loadXModels(bsp, gfxWorld)) + return nullptr; if (!loadLightmapData(gfxWorld)) return nullptr; diff --git a/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.h b/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.h index 1c3faad7..6baf4f2e 100644 --- a/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.h +++ b/src/ObjLoading/Game/T6/BSP/Linker/GfxWorldLinker.h @@ -20,7 +20,7 @@ namespace BSP void loadDrawData(BSPData* projInfo, GfxWorld* gfxWorld); bool loadMapSurfaces(BSPData* projInfo, GfxWorld* gfxWorld); - void loadXModels(BSPData* projInfo, GfxWorld* gfxWorld); + bool loadXModels(BSPData* projInfo, GfxWorld* gfxWorld); void cleanGfxWorld(GfxWorld* gfxWorld); void loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld); void loadLightGrid(GfxWorld* gfxWorld);