mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-06-06 16:52:35 +00:00
feat: load xmodels from GLTF and link them, xmodel collision not working yet.
This commit is contained in:
@@ -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<BSPSurface> surfaces;
|
||||
std::vector<BSPVertex> vertices;
|
||||
std::vector<uint16_t> indices;
|
||||
std::vector<BSPMaterial> materials;
|
||||
std::vector<BSPXModel> 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<BSPLight> lights;
|
||||
std::vector<BSPXModel> xmodels;
|
||||
std::vector<BSPSpawnPoint> spawnpoints;
|
||||
};
|
||||
|
||||
|
||||
@@ -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<int> 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<AssetGfxWorld>(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<AssetXModel>(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);
|
||||
|
||||
|
||||
@@ -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<cplane_s> planeVec;
|
||||
std::vector<cNode_t> nodeVec;
|
||||
|
||||
@@ -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<AssetXModel>(inModel->name);
|
||||
if (xModelAsset == nullptr)
|
||||
auto xModelAsset = m_context.LoadDependency<AssetXModel>(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<GfxStaticModelInst>(modelCount);
|
||||
gfxWorld->dpvs.smodelDrawInsts = m_memory.Alloc<GfxStaticModelDrawInst>(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<char>(allignedModelCount);
|
||||
gfxWorld->dpvs.smodelVisDataCameraSaved = m_memory.Alloc<char>(allignedModelCount);
|
||||
gfxWorld->dpvs.smodelCastsShadow = m_memory.Alloc<char>(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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user