[IXModel] Finally XModels are correct

This commit is contained in:
momo5502 2017-01-03 22:04:10 +01:00
parent 6c9138c5a6
commit ff72493ce3
3 changed files with 146 additions and 138 deletions

View File

@ -1,21 +1,83 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#define IW4X_MODEL_VERSION 3 #define IW4X_MODEL_VERSION 4
namespace Assets namespace Assets
{ {
void IXModel::loadXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Utils::Stream::Reader* reader)
{
if (entry->nodes)
{
entry->nodes = reader->readArray<Game::XSurfaceCollisionNode>(entry->nodeCount);
}
if (entry->leafs)
{
entry->leafs = reader->readArray<Game::XSurfaceCollisionLeaf>(entry->leafCount);
}
}
void IXModel::loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader)
{
if (surf->vertInfo.vertsBlend)
{
surf->vertInfo.vertsBlend = reader->readArray<unsigned short>(surf->vertInfo.vertCount[0] + (surf->vertInfo.vertCount[1] * 3) + (surf->vertInfo.vertCount[2] * 5) + (surf->vertInfo.vertCount[3] * 7));
}
// Access vertex block
if (surf->verts0)
{
surf->verts0 = reader->readArray<Game::GfxPackedVertex>(surf->vertCount);
}
// Save_XRigidVertListArray
if (surf->vertList)
{
surf->vertList = reader->readArray<Game::XRigidVertList>(surf->vertListCount);
for (unsigned int i = 0; i < surf->vertListCount; ++i)
{
Game::XRigidVertList* rigidVertList = &surf->vertList[i];
if (rigidVertList->collisionTree)
{
rigidVertList->collisionTree = reader->readObject<Game::XSurfaceCollisionTree>();
this->loadXSurfaceCollisionTree(rigidVertList->collisionTree, reader);
}
}
}
// Access index block
if (surf->triIndices)
{
surf->triIndices = reader->readArray<unsigned short>(surf->triCount * 3);
}
}
void IXModel::loadXModelSurfs(Game::XModelSurfs* asset, Utils::Stream::Reader* reader)
{
if (asset->name)
{
asset->name = reader->readCString();
}
if (asset->surfaces)
{
asset->surfaces = reader->readArray<Game::XSurface>(asset->numSurfaces);
for (int i = 0; i < asset->numSurfaces; ++i)
{
this->loadXSurface(&asset->surfaces[i], reader);
}
}
}
void IXModel::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IXModel::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File modelFile(fmt::sprintf("xmodel/%s.iw4xModel", name.data())); Components::FileSystem::File modelFile(fmt::sprintf("xmodel/%s.iw4xModel", name.data()));
if (modelFile.exists()) if (modelFile.exists())
{ {
Game::XModel* baseModel = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_XMODEL, "viewmodel_mp5k").model;
// Allocate new model and copy the base data to it
Game::XModel* model = builder->getAllocator()->allocate<Game::XModel>();
std::memcpy(model, baseModel, sizeof(Game::XModel));
Utils::Stream::Reader reader(builder->getAllocator(), modelFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), modelFile.getBuffer());
if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xModl")) if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xModl"))
@ -29,164 +91,105 @@ namespace Assets
Components::Logger::Error(0, "Reading model '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_MODEL_VERSION, version); Components::Logger::Error(0, "Reading model '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_MODEL_VERSION, version);
} }
ZeroMemory(model->noScalePartBits, sizeof model->noScalePartBits); Game::XModel* asset = reader.readObject<Game::XModel>();
model->name = reader.readCString(); if (asset->name)
model->numBones = reader.readByte();
model->numRootBones = reader.readByte();
model->numsurfs = reader.read<unsigned char>();
model->numCollSurfs = reader.read<int>();
model->numLods = static_cast<char>(reader.read<short>());
model->collLod = static_cast<char>(reader.read<short>());
// Read bone names
model->boneNames = builder->getAllocator()->allocateArray<unsigned short>(model->numBones);
for (char i = 0; i < model->numBones; ++i)
{ {
model->boneNames[i] = Game::SL_GetString(reader.readCString(), 0); asset->name = reader.readCString();
} }
// Bone count if (asset->boneNames)
int boneCount = (model->numBones - model->numRootBones);
// Read bone data
model->parentList = reader.readArray<char>(boneCount);
model->quats = reader.readArray<short>(boneCount * 4);
model->trans = reader.readArray<float>(boneCount * 3);
model->partClassification = reader.readArray<char>(boneCount);
model->baseMat = reader.readArray<Game::DObjAnimMat>(boneCount);
// Prepare surfaces
Game::XModelSurfs surf;
Utils::Memory::Allocator allocator;
Game::XSurface* baseSurface = &baseModel->lodInfo[0].modelSurfs[0].surfaces[0];
std::memcpy(&surf, baseModel->lodInfo[0].modelSurfs, sizeof(Game::XModelSurfs));
surf.surfaces = allocator.allocateArray<Game::XSurface>(model->numsurfs);
surf.numSurfaces = model->numsurfs;
for (int i = 0; i < 4; ++i)
{ {
model->lodInfo[i].dist = reader.read<float>(); asset->boneNames = builder->getAllocator()->allocateArray<unsigned short>(asset->numBones);
model->lodInfo[i].numsurfs = reader.read<unsigned short>();
model->lodInfo[i].surfIndex = reader.read<unsigned short>();
model->lodInfo[i].partBits[0] = reader.read<int>(); for (char i = 0; i < asset->numBones; ++i)
model->lodInfo[i].partBits[1] = reader.read<int>();
model->lodInfo[i].partBits[2] = reader.read<int>();
model->lodInfo[i].partBits[3] = reader.read<int>();
model->lodInfo[i].partBits[4] = 0;
model->lodInfo[i].partBits[5] = 0;
}
// Read surfaces
for (int i = 0; i < surf.numSurfaces; ++i)
{
Game::XSurface* surface = &surf.surfaces[i];
std::memcpy(surface, baseSurface, sizeof(Game::XSurface));
surface->tileMode = reader.read<char>();
surface->deformed = reader.read<bool>();
surface->zoneHandle = reader.read<char>();
surface->partBits[0] = reader.read<int>();
surface->partBits[1] = reader.read<int>();
surface->partBits[2] = reader.read<int>();
surface->partBits[3] = reader.read<int>();
surface->partBits[4] = 0;
surface->partBits[5] = 0;
surface->baseTriIndex = reader.read<unsigned __int16>();
surface->baseVertIndex = reader.read<unsigned __int16>();
surface->vertCount = reader.read<unsigned short>();
surface->triCount = reader.read<unsigned short>();
surface->vertListCount = reader.read<unsigned int>();
surface->vertInfo.vertCount[0] = reader.read<short>();
surface->vertInfo.vertCount[1] = reader.read<short>();
surface->vertInfo.vertCount[2] = reader.read<short>();
surface->vertInfo.vertCount[3] = reader.read<short>();
surface->vertInfo.vertsBlend = reader.readArray<unsigned short>(surface->vertInfo.vertCount[0] + (3 * surface->vertInfo.vertCount[1]) + (5 * surface->vertInfo.vertCount[2]) + (7 * surface->vertInfo.vertCount[3]));
surface->verts0 = reader.readArray<Game::GfxPackedVertex>(surface->vertCount);
surface->triIndices = reader.readArray<unsigned __int16>(3 * surface->triCount);
// Read vert list
if (reader.readByte())
{ {
surface->vertList = reader.readArray<Game::XRigidVertList>(surface->vertListCount); asset->boneNames[i] = Game::SL_GetString(reader.readCString(), 0);
for (unsigned int j = 0; j < surface->vertListCount; ++j)
{
Game::XRigidVertList* vertList = &surface->vertList[j];
vertList->collisionTree = reader.readArray<Game::XSurfaceCollisionTree>();
vertList->collisionTree->nodes = reader.readArray<Game::XSurfaceCollisionNode>(vertList->collisionTree->nodeCount);
vertList->collisionTree->leafs = reader.readArray<Game::XSurfaceCollisionLeaf>(vertList->collisionTree->leafCount);
}
}
else
{
surface->vertList = nullptr;
} }
} }
// When all surfaces are loaded, split them up. if (asset->parentList)
for (char i = 0; i < model->numLods; ++i)
{ {
Game::XModelSurfs* realSurf = builder->getAllocator()->allocate<Game::XModelSurfs>(); asset->parentList = reader.readArray<char>(asset->numBones - asset->numRootBones);
// Usually, a binary representation is used for the index, but meh.
realSurf->name = builder->getAllocator()->duplicateString(fmt::sprintf("%s_lod%d", model->name, i & 0xFF));
realSurf->numSurfaces = model->lodInfo[i].numsurfs;
realSurf->surfaces = builder->getAllocator()->allocateArray<Game::XSurface>(realSurf->numSurfaces);
std::memcpy(realSurf->surfaces, &surf.surfaces[model->lodInfo[i].surfIndex], sizeof(Game::XSurface) * realSurf->numSurfaces);
std::memcpy(realSurf->partBits, model->lodInfo[i].partBits, sizeof(realSurf->partBits));
model->lodInfo[i].modelSurfs = realSurf;
model->lodInfo[i].surfs = realSurf->surfaces;
// Store surfs for later writing
Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, { realSurf });
} }
// Read materials if (asset->quats)
model->materialHandles = builder->getAllocator()->allocateArray<Game::Material*>(model->numsurfs);
for (char i = 0; i < model->numsurfs; ++i)
{ {
model->materialHandles[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString(), builder).material; asset->quats = reader.readArray<short>((asset->numBones - asset->numRootBones) * 4);
} }
// Read collision surfaces if (asset->trans)
if (reader.readByte())
{ {
model->collSurfs = reader.readArray<Game::XModelCollSurf_s>(model->numCollSurfs); asset->trans = reader.readArray<float>((asset->numBones - asset->numRootBones) * 3);
}
for (int i = 0; i < model->numCollSurfs; ++i) if (asset->partClassification)
{
asset->partClassification = reader.readArray<char>(asset->numBones);
}
if (asset->baseMat)
{
asset->baseMat = reader.readArray<Game::DObjAnimMat>(asset->numBones);
}
if (asset->materialHandles)
{
asset->materialHandles = reader.readArray<Game::Material*>(asset->numsurfs);
for (char i = 0; i < asset->numsurfs; ++i)
{ {
if (model->collSurfs[i].collTris) if (asset->materialHandles[i])
{ {
model->collSurfs[i].collTris = reader.readArray<Game::XModelCollTri_s>(model->collSurfs[i].numCollTris); asset->materialHandles[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString(), builder).material;
} }
} }
} }
else
// Save_XModelLodInfoArray
{ {
model->collSurfs = nullptr; for (int i = 0; i < 4; ++i)
{
if (asset->lodInfo[i].modelSurfs)
{
asset->lodInfo[i].modelSurfs = reader.readObject<Game::XModelSurfs>();
this->loadXModelSurfs(asset->lodInfo[i].modelSurfs, &reader);
Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, { asset->lodInfo[i].modelSurfs });
}
}
} }
// Read bone info // Save_XModelCollSurfArray
if (reader.readByte()) if (asset->collSurfs)
{ {
model->boneInfo = reader.readArray<Game::XBoneInfo>(model->numBones); asset->collSurfs = reader.readArray<Game::XModelCollSurf_s>(asset->numCollSurfs);
for (int i = 0; i < asset->numCollSurfs; ++i)
{
Game::XModelCollSurf_s* collSurf = &asset->collSurfs[i];
if (collSurf->collTris)
{
collSurf->collTris = reader.readArray<Game::XModelCollTri_s>(collSurf->numCollTris);
}
}
} }
else
if (asset->boneInfo)
{ {
model->boneInfo = nullptr; asset->boneInfo = reader.readArray<Game::XBoneInfo>(asset->numBones);
}
if (asset->physPreset)
{
// TODO
asset->physPreset = nullptr;
}
if (asset->physCollmap)
{
// TODO
asset->physCollmap = nullptr;
} }
if (!reader.end()) if (!reader.end())
@ -194,7 +197,7 @@ namespace Assets
Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data()); Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data());
} }
header->model = model; header->model = asset;
} }
} }

View File

@ -8,5 +8,10 @@ namespace Assets
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override; virtual void load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override;
private:
void loadXModelSurfs(Game::XModelSurfs* asset, Utils::Stream::Reader* reader);
void loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader);
void loadXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Utils::Stream::Reader* reader);
}; };
} }

View File

@ -1663,7 +1663,7 @@ namespace Game
struct PhysCollmap struct PhysCollmap
{ {
const char * name; const char *name;
unsigned int count; unsigned int count;
PhysGeomInfo *geoms; PhysGeomInfo *geoms;
char unknown[0x18]; char unknown[0x18];