iw4x-client/src/Components/Modules/AssetInterfaces/IXModel.cpp

402 lines
10 KiB
C++
Raw Normal View History

2016-07-11 11:14:58 -04:00
#include <STDInclude.hpp>
2017-01-03 16:04:10 -05:00
#define IW4X_MODEL_VERSION 4
2016-07-11 11:14:58 -04:00
namespace Assets
{
2017-01-03 16:04:10 -05:00
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)
2016-07-11 11:14:58 -04:00
{
Components::FileSystem::File modelFile(fmt::sprintf("xmodel/%s.iw4xModel", name.data()));
if (modelFile.exists())
2016-07-11 11:14:58 -04:00
{
Utils::Stream::Reader reader(builder->getAllocator(), modelFile.getBuffer());
2016-07-11 11:14:58 -04:00
if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xModl"))
{
Components::Logger::Error(0, "Reading model '%s' failed, header is invalid!", name.data());
}
int version = reader.read<int>();
if (version != IW4X_MODEL_VERSION)
{
Components::Logger::Error(0, "Reading model '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_MODEL_VERSION, version);
}
2017-01-03 16:04:10 -05:00
Game::XModel* asset = reader.readObject<Game::XModel>();
2016-07-11 11:14:58 -04:00
2017-01-03 16:04:10 -05:00
if (asset->name)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
asset->name = reader.readCString();
2016-07-11 11:14:58 -04:00
}
2017-01-03 16:04:10 -05:00
if (asset->boneNames)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
asset->boneNames = builder->getAllocator()->allocateArray<unsigned short>(asset->numBones);
2017-01-02 16:35:55 -05:00
2017-01-03 16:04:10 -05:00
for (char i = 0; i < asset->numBones; ++i)
{
asset->boneNames[i] = Game::SL_GetString(reader.readCString(), 0);
}
2016-07-11 11:14:58 -04:00
}
2017-01-03 16:04:10 -05:00
if (asset->parentList)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
asset->parentList = reader.readArray<char>(asset->numBones - asset->numRootBones);
}
2016-07-11 11:14:58 -04:00
2017-01-03 16:04:10 -05:00
if (asset->quats)
{
asset->quats = reader.readArray<short>((asset->numBones - asset->numRootBones) * 4);
}
2016-11-05 21:24:30 -04:00
2017-01-03 16:04:10 -05:00
if (asset->trans)
{
asset->trans = reader.readArray<float>((asset->numBones - asset->numRootBones) * 3);
}
2016-07-11 11:14:58 -04:00
2017-01-03 16:04:10 -05:00
if (asset->partClassification)
{
asset->partClassification = reader.readArray<char>(asset->numBones);
}
2016-07-11 11:14:58 -04:00
2017-01-03 16:04:10 -05:00
if (asset->baseMat)
{
asset->baseMat = reader.readArray<Game::DObjAnimMat>(asset->numBones);
}
2016-07-11 11:14:58 -04:00
2017-01-03 16:04:10 -05:00
if (asset->materialHandles)
{
asset->materialHandles = reader.readArray<Game::Material*>(asset->numsurfs);
2016-07-11 11:14:58 -04:00
2017-01-03 16:04:10 -05:00
for (char i = 0; i < asset->numsurfs; ++i)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
if (asset->materialHandles[i])
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
asset->materialHandles[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString(), builder).material;
2016-07-11 11:14:58 -04:00
}
}
}
2017-01-03 16:04:10 -05:00
// Save_XModelLodInfoArray
2017-01-01 14:04:20 -05:00
{
2017-01-03 16:04:10 -05:00
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 });
2017-01-03 17:19:04 -05:00
asset->lodInfo[i].surfs = asset->lodInfo[i].modelSurfs->surfaces;
// Zero that for now, it breaks the models.
// TODO: Figure out how that can be converted
asset->lodInfo[i].smcBaseIndexPlusOne = 0;
asset->lodInfo[i].smcSubIndexMask = 0;
asset->lodInfo[i].smcBucket = 0;
2017-01-03 16:04:10 -05:00
}
}
2016-07-11 11:14:58 -04:00
}
2017-01-03 16:04:10 -05:00
// Save_XModelCollSurfArray
if (asset->collSurfs)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
asset->collSurfs = reader.readArray<Game::XModelCollSurf_s>(asset->numCollSurfs);
2017-01-03 16:04:10 -05:00
for (int i = 0; i < asset->numCollSurfs; ++i)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
Game::XModelCollSurf_s* collSurf = &asset->collSurfs[i];
if (collSurf->collTris)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
collSurf->collTris = reader.readArray<Game::XModelCollTri_s>(collSurf->numCollTris);
2016-07-11 11:14:58 -04:00
}
}
}
2017-01-03 16:04:10 -05:00
if (asset->boneInfo)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
asset->boneInfo = reader.readArray<Game::XBoneInfo>(asset->numBones);
2016-07-11 11:14:58 -04:00
}
2017-01-03 16:04:10 -05:00
if (asset->physPreset)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
// TODO
asset->physPreset = nullptr;
2016-07-11 11:14:58 -04:00
}
2017-01-03 16:04:10 -05:00
if (asset->physCollmap)
2016-07-11 11:14:58 -04:00
{
2017-01-03 16:04:10 -05:00
// TODO
asset->physCollmap = nullptr;
2016-07-11 11:14:58 -04:00
}
if (!reader.end())
2016-07-11 11:14:58 -04:00
{
Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data());
}
2017-01-03 16:04:10 -05:00
header->model = asset;
2016-07-11 11:14:58 -04:00
}
}
void IXModel::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
2016-07-11 11:14:58 -04:00
{
Game::XModel* asset = header.model;
if (asset->boneNames)
{
for (char i = 0; i < asset->numBones; ++i)
{
builder->addScriptString(asset->boneNames[i]);
2016-07-11 11:14:58 -04:00
}
}
2017-01-02 16:35:55 -05:00
if (asset->materialHandles)
2016-07-11 11:14:58 -04:00
{
2017-01-03 14:09:38 -05:00
for (char i = 0; i < asset->numsurfs; ++i)
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
if (asset->materialHandles[i])
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materialHandles[i]);
2016-07-11 11:14:58 -04:00
}
}
}
for (int i = 0; i < 4; ++i)
{
2017-01-02 16:35:55 -05:00
if (asset->lodInfo[i].modelSurfs)
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lodInfo[i].modelSurfs);
2016-07-11 11:14:58 -04:00
}
}
if (asset->physPreset)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset);
2016-07-11 11:14:58 -04:00
}
if (asset->physCollmap)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap);
2016-07-11 11:14:58 -04:00
}
}
void IXModel::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
2016-07-11 11:14:58 -04:00
{
AssertSize(Game::XModel, 304);
2016-07-11 11:14:58 -04:00
Utils::Stream* buffer = builder->getBuffer();
2016-07-11 11:14:58 -04:00
Game::XModel* asset = header.model;
Game::XModel* dest = buffer->dest<Game::XModel>();
buffer->save(asset);
2016-07-11 11:14:58 -04:00
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
2016-07-11 11:14:58 -04:00
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
2016-07-11 11:14:58 -04:00
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->boneNames)
{
buffer->align(Utils::Stream::ALIGN_2);
2016-07-11 11:14:58 -04:00
unsigned short* destBoneNames = buffer->dest<unsigned short>();
buffer->saveArray(asset->boneNames, asset->numBones);
2016-07-11 11:14:58 -04:00
for (char i = 0; i < asset->numBones; ++i)
{
builder->mapScriptString(&destBoneNames[i]);
2016-07-11 11:14:58 -04:00
}
Utils::Stream::ClearPointer(&dest->boneNames);
}
if (asset->parentList)
{
buffer->save(asset->parentList, asset->numBones - asset->numRootBones);
2016-07-11 11:14:58 -04:00
Utils::Stream::ClearPointer(&dest->parentList);
}
2017-01-02 16:35:55 -05:00
if (asset->quats)
2016-07-11 11:14:58 -04:00
{
buffer->align(Utils::Stream::ALIGN_2);
2017-01-02 16:35:55 -05:00
buffer->saveArray(asset->quats, (asset->numBones - asset->numRootBones) * 4);
Utils::Stream::ClearPointer(&dest->quats);
2016-07-11 11:14:58 -04:00
}
2017-01-02 16:35:55 -05:00
if (asset->trans)
2016-07-11 11:14:58 -04:00
{
buffer->align(Utils::Stream::ALIGN_4);
2017-01-02 16:35:55 -05:00
buffer->saveArray(asset->trans, (asset->numBones - asset->numRootBones) * 3);
Utils::Stream::ClearPointer(&dest->trans);
2016-07-11 11:14:58 -04:00
}
if (asset->partClassification)
{
buffer->save(asset->partClassification, asset->numBones);
2016-07-11 11:14:58 -04:00
Utils::Stream::ClearPointer(&dest->partClassification);
}
2017-01-02 16:35:55 -05:00
if (asset->baseMat)
2016-07-11 11:14:58 -04:00
{
AssertSize(Game::DObjAnimMat, 32);
2016-07-11 11:14:58 -04:00
buffer->align(Utils::Stream::ALIGN_4);
2017-01-02 16:35:55 -05:00
buffer->saveArray(asset->baseMat, asset->numBones);
Utils::Stream::ClearPointer(&dest->baseMat);
2016-07-11 11:14:58 -04:00
}
2017-01-02 16:35:55 -05:00
if (asset->materialHandles)
2016-07-11 11:14:58 -04:00
{
buffer->align(Utils::Stream::ALIGN_4);
2016-07-11 11:14:58 -04:00
Game::Material** destMaterials = buffer->dest<Game::Material*>();
2017-01-02 16:35:55 -05:00
buffer->saveArray(asset->materialHandles, asset->numsurfs);
2016-07-11 11:14:58 -04:00
2017-01-03 14:09:38 -05:00
for (char i = 0; i < asset->numsurfs; ++i)
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
if (asset->materialHandles[i])
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
destMaterials[i] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materialHandles[i]).material;
2016-07-11 11:14:58 -04:00
}
}
2017-01-02 16:35:55 -05:00
Utils::Stream::ClearPointer(&dest->materialHandles);
2016-07-11 11:14:58 -04:00
}
// Save_XModelLodInfoArray
{
AssertSize(Game::XModelLodInfo, 44);
2016-07-11 11:14:58 -04:00
for (int i = 0; i < 4; ++i)
{
2017-01-02 16:35:55 -05:00
if (asset->lodInfo[i].modelSurfs)
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
dest->lodInfo[i].modelSurfs = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lodInfo[i].modelSurfs).surfaces;
2016-07-11 11:14:58 -04:00
}
}
}
// Save_XModelCollSurfArray
2017-01-02 16:35:55 -05:00
if (asset->collSurfs)
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
AssertSize(Game::XModelCollSurf_s, 44);
2016-07-11 11:14:58 -04:00
buffer->align(Utils::Stream::ALIGN_4);
2016-07-11 11:14:58 -04:00
2017-01-02 16:35:55 -05:00
Game::XModelCollSurf_s* destColSurfs = buffer->dest<Game::XModelCollSurf_s>();
buffer->saveArray(asset->collSurfs, asset->numCollSurfs);
2016-07-11 11:14:58 -04:00
2017-01-02 16:35:55 -05:00
for (int i = 0; i < asset->numCollSurfs; ++i)
2016-07-11 11:14:58 -04:00
{
2017-01-02 16:35:55 -05:00
Game::XModelCollSurf_s* destCollSurf = &destColSurfs[i];
Game::XModelCollSurf_s* collSurf = &asset->collSurfs[i];
2016-07-11 11:14:58 -04:00
2017-01-02 16:35:55 -05:00
if (collSurf->collTris)
2016-07-11 11:14:58 -04:00
{
buffer->align(Utils::Stream::ALIGN_4);
2016-07-11 11:14:58 -04:00
2017-01-02 16:35:55 -05:00
buffer->save(collSurf->collTris, 48, collSurf->numCollTris);
Utils::Stream::ClearPointer(&destCollSurf->collTris);
2016-07-11 11:14:58 -04:00
}
}
2017-01-02 16:35:55 -05:00
Utils::Stream::ClearPointer(&dest->collSurfs);
2016-07-11 11:14:58 -04:00
}
if (asset->boneInfo)
{
AssertSize(Game::XBoneInfo, 28);
2016-07-11 11:14:58 -04:00
buffer->align(Utils::Stream::ALIGN_4);
2016-07-11 11:14:58 -04:00
buffer->saveArray(asset->boneInfo, asset->numBones);
2016-07-11 11:14:58 -04:00
Utils::Stream::ClearPointer(&dest->boneInfo);
}
if (asset->physPreset)
{
dest->physPreset = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset).physPreset;
2016-07-11 11:14:58 -04:00
}
if (asset->physCollmap)
{
dest->physCollmap = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap).physCollmap;
2016-07-11 11:14:58 -04:00
}
buffer->popBlock();
2016-07-11 11:14:58 -04:00
}
}