mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-06-06 08:42: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;
|
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
|
struct BSPWorld
|
||||||
{
|
{
|
||||||
std::vector<BSPSurface> surfaces;
|
std::vector<BSPSurface> surfaces;
|
||||||
std::vector<BSPVertex> vertices;
|
std::vector<BSPVertex> vertices;
|
||||||
std::vector<uint16_t> indices;
|
std::vector<uint16_t> indices;
|
||||||
std::vector<BSPMaterial> materials;
|
std::vector<BSPMaterial> materials;
|
||||||
|
std::vector<BSPXModel> xmodels;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BSPLightType
|
enum BSPLightType
|
||||||
@@ -74,21 +88,6 @@ namespace BSP
|
|||||||
float outerConeAngle;
|
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
|
enum BSPSpawnPointType
|
||||||
{
|
{
|
||||||
SPAWNPOINT_TYPE_DEFENDER,
|
SPAWNPOINT_TYPE_DEFENDER,
|
||||||
@@ -112,7 +111,6 @@ namespace BSP
|
|||||||
BSPWorld colWorld;
|
BSPWorld colWorld;
|
||||||
|
|
||||||
std::vector<BSPLight> lights;
|
std::vector<BSPLight> lights;
|
||||||
std::vector<BSPXModel> xmodels;
|
|
||||||
std::vector<BSPSpawnPoint> spawnpoints;
|
std::vector<BSPSpawnPoint> spawnpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,16 @@ namespace
|
|||||||
unsigned m_index_accessor;
|
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])
|
void RhcToLhcCoordinates(float (&coords)[3])
|
||||||
{
|
{
|
||||||
const float two[3]{coords[0], coords[1], coords[2]};
|
const float two[3]{coords[0], coords[1], coords[2]};
|
||||||
@@ -392,8 +402,110 @@ namespace
|
|||||||
return true;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,8 +559,8 @@ namespace
|
|||||||
|
|
||||||
if (node.extras)
|
if (node.extras)
|
||||||
{
|
{
|
||||||
if (m_is_world_gfx && node.extras->xmodel)
|
if (node.extras->xmodel)
|
||||||
return addXModelNode(node);
|
return addXModelNode(jRoot, node);
|
||||||
|
|
||||||
if (m_is_world_gfx && node.extras->spawnpoint)
|
if (m_is_world_gfx && node.extras->spawnpoint)
|
||||||
return addSpawnPointNode(node);
|
return addSpawnPointNode(node);
|
||||||
|
|||||||
@@ -104,7 +104,43 @@ namespace BSP
|
|||||||
return sqrtf((x * x) + (y * y) + (z * z));
|
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 cosX = cos(angles->x);
|
||||||
float sinX = sin(angles->x);
|
float sinX = sin(angles->x);
|
||||||
@@ -124,6 +160,38 @@ namespace BSP
|
|||||||
axis[2].z = cosZ * cosX;
|
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 BSPUtil::convertForwardVectorToViewAngles(vec3_t& forwardVec)
|
||||||
{
|
{
|
||||||
vec3_t viewAngles;
|
vec3_t viewAngles;
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ namespace BSP
|
|||||||
static vec3_t calcHalfSizeOfAABB(vec3_t& mins, vec3_t& maxs);
|
static vec3_t calcHalfSizeOfAABB(vec3_t& mins, vec3_t& maxs);
|
||||||
static size_t allignBy128(size_t size);
|
static size_t allignBy128(size_t size);
|
||||||
static float distBetweenPoints(vec3_t& p1, vec3_t& p2);
|
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 vec3_t convertForwardVectorToViewAngles(vec3_t& forwardVec);
|
||||||
static void matrixTranspose3x3(const vec3_t* in, vec3_t* out);
|
static void matrixTranspose3x3(const vec3_t* in, vec3_t* out);
|
||||||
static vec3_t convertStringToVec3(std::string& str);
|
static vec3_t convertStringToVec3(std::string& str);
|
||||||
|
|||||||
@@ -154,54 +154,77 @@ namespace BSP
|
|||||||
clipMap->cmodels[0].info = nullptr;
|
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 = bsp->colWorld.xmodels.size();
|
||||||
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->staticModelList = new cStaticModel_s[clipMap->numStaticModels];
|
clipMap->staticModelList = new cStaticModel_s[clipMap->numStaticModels];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < clipMap->numStaticModels; i++)
|
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];
|
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));
|
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
|
// out_mins and out_maxs are initialised in the function
|
||||||
@@ -691,7 +714,7 @@ namespace BSP
|
|||||||
|
|
||||||
loadDynEnts(clipMap);
|
loadDynEnts(clipMap);
|
||||||
|
|
||||||
loadXModelCollision(clipMap);
|
loadXModelCollision(clipMap, bsp);
|
||||||
|
|
||||||
loadMaterials(clipMap, bsp);
|
loadMaterials(clipMap, bsp);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace BSP
|
|||||||
void loadDynEnts(clipMap_t* clipMap);
|
void loadDynEnts(clipMap_t* clipMap);
|
||||||
void loadRopesAndConstraints(clipMap_t* clipMap);
|
void loadRopesAndConstraints(clipMap_t* clipMap);
|
||||||
void loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp);
|
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<cplane_s> planeVec;
|
||||||
std::vector<cNode_t> nodeVec;
|
std::vector<cNode_t> nodeVec;
|
||||||
|
|||||||
@@ -145,79 +145,90 @@ namespace BSP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxWorldLinker::loadXModels(BSPData* bsp, GfxWorld* gfxWorld)
|
bool GfxWorldLinker::loadXModels(BSPData* bsp, GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
/*
|
size_t modelCount = bsp->gfxWorld.xmodels.size();
|
||||||
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.smodelCount = modelCount;
|
||||||
gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
|
gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
|
||||||
gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[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 currModel = &gfxWorld->dpvs.smodelDrawInsts[modelIdx];
|
||||||
auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
|
auto currModelInst = &gfxWorld->dpvs.smodelInsts[modelIdx];
|
||||||
customMapModel* inModel = &projInfo->models[i];
|
BSPXModel& bspModel = bsp->gfxWorld.xmodels.at(modelIdx);
|
||||||
|
|
||||||
auto xModelAsset = m_context.LoadDependency<AssetXModel>(inModel->name);
|
auto xModelAsset = m_context.LoadDependency<AssetXModel>(bspModel.name);
|
||||||
if (xModelAsset == nullptr)
|
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());
|
currModelInst->mins = bspModel.mins;
|
||||||
currModel->model = nullptr;
|
currModelInst->maxs = bspModel.maxs;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
currModel->model = (XModel*)xModelAsset->Asset();
|
{
|
||||||
|
con::warn("Unable to determine the bounds of xmodel: \"{}\"", bspModel.name);
|
||||||
currModel->placement.origin.x = inModel->origin.x;
|
currModelInst->mins.x = bspModel.origin.x - 1.0f;
|
||||||
currModel->placement.origin.y = inModel->origin.y;
|
currModelInst->mins.y = bspModel.origin.y - 1.0f;
|
||||||
currModel->placement.origin.z = inModel->origin.z;
|
currModelInst->mins.z = bspModel.origin.z - 1.0f;
|
||||||
currModel->placement.origin = BSPUtil::convertToBO2Coords(currModel->placement.origin);
|
currModelInst->maxs.x = bspModel.origin.x + 1.0f;
|
||||||
currModel->placement.scale = inModel->scale;
|
currModelInst->maxs.y = bspModel.origin.y + 1.0f;
|
||||||
|
currModelInst->maxs.z = bspModel.origin.z + 1.0f;
|
||||||
BSPUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
|
}
|
||||||
|
}
|
||||||
// mins and maxs are calculated in world space not local space
|
currModelInst->lightingOrigin.x = 0.0f;
|
||||||
// TODO: this does not account for model rotation or scale
|
currModelInst->lightingOrigin.y = 0.0f;
|
||||||
currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
|
currModelInst->lightingOrigin.z = 0.0f;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
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
|
// visdata is written to by the game
|
||||||
// all visdata is alligned by 128
|
// all visdata is alligned by 128
|
||||||
@@ -228,7 +239,7 @@ namespace BSP
|
|||||||
gfxWorld->dpvs.smodelVisData[2] = m_memory.Alloc<char>(allignedModelCount);
|
gfxWorld->dpvs.smodelVisData[2] = m_memory.Alloc<char>(allignedModelCount);
|
||||||
gfxWorld->dpvs.smodelVisDataCameraSaved = m_memory.Alloc<char>(allignedModelCount);
|
gfxWorld->dpvs.smodelVisDataCameraSaved = m_memory.Alloc<char>(allignedModelCount);
|
||||||
gfxWorld->dpvs.smodelCastsShadow = 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)
|
if ((gfxWorld->dpvs.smodelDrawInsts[i].flags & STATIC_MODEL_FLAG_NO_SHADOW) == 0)
|
||||||
gfxWorld->dpvs.smodelCastsShadow[i] = 1;
|
gfxWorld->dpvs.smodelCastsShadow[i] = 1;
|
||||||
@@ -236,8 +247,7 @@ namespace BSP
|
|||||||
gfxWorld->dpvs.smodelCastsShadow[i] = 0;
|
gfxWorld->dpvs.smodelCastsShadow[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// official maps set this to 0
|
return true;
|
||||||
gfxWorld->dpvs.usageCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxWorldLinker::cleanGfxWorld(GfxWorld* gfxWorld)
|
void GfxWorldLinker::cleanGfxWorld(GfxWorld* gfxWorld)
|
||||||
@@ -245,6 +255,9 @@ namespace BSP
|
|||||||
// checksum is generated by the game
|
// checksum is generated by the game
|
||||||
gfxWorld->checksum = 0;
|
gfxWorld->checksum = 0;
|
||||||
|
|
||||||
|
// official maps set this to 0
|
||||||
|
gfxWorld->dpvs.usageCount = 0;
|
||||||
|
|
||||||
// Remove Coronas
|
// Remove Coronas
|
||||||
gfxWorld->coronaCount = 0;
|
gfxWorld->coronaCount = 0;
|
||||||
gfxWorld->coronas = nullptr;
|
gfxWorld->coronas = nullptr;
|
||||||
@@ -735,7 +748,8 @@ namespace BSP
|
|||||||
if (!loadMapSurfaces(bsp, gfxWorld))
|
if (!loadMapSurfaces(bsp, gfxWorld))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
loadXModels(bsp, gfxWorld);
|
if (!loadXModels(bsp, gfxWorld))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
if (!loadLightmapData(gfxWorld))
|
if (!loadLightmapData(gfxWorld))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace BSP
|
|||||||
|
|
||||||
void loadDrawData(BSPData* projInfo, GfxWorld* gfxWorld);
|
void loadDrawData(BSPData* projInfo, GfxWorld* gfxWorld);
|
||||||
bool loadMapSurfaces(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 cleanGfxWorld(GfxWorld* gfxWorld);
|
||||||
void loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld);
|
void loadGfxLights(BSPData* bsp, GfxWorld* gfxWorld);
|
||||||
void loadLightGrid(GfxWorld* gfxWorld);
|
void loadLightGrid(GfxWorld* gfxWorld);
|
||||||
|
|||||||
Reference in New Issue
Block a user