2016-07-11 11:14:58 -04:00
|
|
|
#include <STDInclude.hpp>
|
|
|
|
|
2017-01-01 14:04:20 -05:00
|
|
|
#define IW4X_MODEL_VERSION 3
|
2016-12-07 12:39:12 -05:00
|
|
|
|
2016-07-11 11:14:58 -04:00
|
|
|
namespace Assets
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
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()));
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
if (modelFile.exists())
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
|
|
|
Game::XModel* baseModel = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_XMODEL, "viewmodel_mp5k").model;
|
|
|
|
|
|
|
|
// Allocate new model and copy the base data to it
|
2016-11-20 08:09:07 -05:00
|
|
|
Game::XModel* model = builder->getAllocator()->allocate<Game::XModel>();
|
2016-07-11 11:14:58 -04:00
|
|
|
std::memcpy(model, baseModel, sizeof(Game::XModel));
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
Utils::Stream::Reader reader(builder->getAllocator(), modelFile.getBuffer());
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-12-07 12:39:12 -05: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-02 16:35:55 -05:00
|
|
|
ZeroMemory(model->noScalePartBits, sizeof model->noScalePartBits);
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
model->name = reader.readCString();
|
|
|
|
model->numBones = reader.readByte();
|
|
|
|
model->numRootBones = reader.readByte();
|
2017-01-02 16:35:55 -05:00
|
|
|
model->numsurfs = reader.read<unsigned char>();
|
|
|
|
model->numCollSurfs = reader.read<int>();
|
2017-01-01 14:04:20 -05:00
|
|
|
model->numLods = static_cast<char>(reader.read<short>());
|
2017-01-02 16:35:55 -05:00
|
|
|
model->collLod = static_cast<char>(reader.read<short>());
|
2016-07-11 11:14:58 -04:00
|
|
|
|
|
|
|
// Read bone names
|
2017-01-02 16:35:55 -05:00
|
|
|
model->boneNames = builder->getAllocator()->allocateArray<unsigned short>(model->numBones);
|
2016-07-11 11:14:58 -04:00
|
|
|
for (int i = 0; i < model->numBones; ++i)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
model->boneNames[i] = Game::SL_GetString(reader.readCString(), 0);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bone count
|
|
|
|
int boneCount = (model->numBones - model->numRootBones);
|
|
|
|
|
|
|
|
// Read bone data
|
2016-11-20 08:09:07 -05:00
|
|
|
model->parentList = reader.readArray<char>(boneCount);
|
2017-01-02 16:35:55 -05:00
|
|
|
model->quats = reader.readArray<short>(boneCount * 4);
|
|
|
|
model->trans = reader.readArray<float>(boneCount * 3);
|
2016-11-20 08:09:07 -05:00
|
|
|
model->partClassification = reader.readArray<char>(boneCount);
|
2017-01-02 16:35:55 -05:00
|
|
|
model->baseMat = reader.readArray<Game::DObjAnimMat>(boneCount);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
|
|
|
// Prepare surfaces
|
2017-01-01 14:04:20 -05:00
|
|
|
Game::XModelSurfs surf;
|
|
|
|
Utils::Memory::Allocator allocator;
|
2017-01-02 16:35:55 -05:00
|
|
|
Game::XSurface* baseSurface = &baseModel->lodInfo[0].modelSurfs[0].surfaces[0];
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2017-01-02 16:35:55 -05:00
|
|
|
std::memcpy(&surf, baseModel->lodInfo[0].modelSurfs, sizeof(Game::XModelSurfs));
|
|
|
|
surf.surfaces = allocator.allocateArray<Game::XSurface>(model->numsurfs);
|
|
|
|
surf.numSurfaces = model->numsurfs;
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2017-01-01 14:04:20 -05:00
|
|
|
for (int i = 0; i < 4; ++i)
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2017-01-02 16:35:55 -05:00
|
|
|
model->lodInfo[i].dist = reader.read<float>();
|
|
|
|
model->lodInfo[i].numsurfs = reader.read<unsigned short>();
|
|
|
|
model->lodInfo[i].surfIndex = reader.read<unsigned short>();
|
|
|
|
|
|
|
|
model->lodInfo[i].partBits[0] = reader.read<int>();
|
|
|
|
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;
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read surfaces
|
2017-01-01 14:04:20 -05:00
|
|
|
for (int i = 0; i < surf.numSurfaces; ++i)
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2017-01-01 14:04:20 -05:00
|
|
|
Game::XSurface* surface = &surf.surfaces[i];
|
2016-07-11 11:14:58 -04:00
|
|
|
std::memcpy(surface, baseSurface, sizeof(Game::XSurface));
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->tileMode = reader.read<char>();
|
|
|
|
surface->deformed = reader.read<char>();
|
2016-11-05 21:24:30 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->streamHandle = reader.read<unsigned char>();
|
2016-12-20 12:15:28 -05:00
|
|
|
surface->partBits[0] = reader.read<int>();
|
|
|
|
surface->partBits[1] = reader.read<int>();
|
|
|
|
surface->partBits[2] = reader.read<int>();
|
|
|
|
surface->partBits[3] = reader.read<int>();
|
2017-01-01 14:04:20 -05:00
|
|
|
surface->partBits[4] = 0;
|
|
|
|
surface->partBits[5] = 0;
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-12-20 12:15:28 -05:00
|
|
|
surface->baseTriIndex = reader.read<unsigned __int16>();
|
|
|
|
surface->baseVertIndex = reader.read<unsigned __int16>();
|
2016-11-05 21:24:30 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->numVertices = reader.read<unsigned short>();
|
|
|
|
surface->numPrimitives = reader.read<unsigned short>();
|
|
|
|
surface->numCT = reader.read<int>();
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->blendNum1 = reader.read<short>();
|
|
|
|
surface->blendNum2 = reader.read<short>();
|
|
|
|
surface->blendNum3 = reader.read<short>();
|
|
|
|
surface->blendNum4 = reader.read<short>();
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->blendInfo = reinterpret_cast<char*>(reader.read(2, surface->blendNum1 + (3 * surface->blendNum2) + (5 * surface->blendNum3) + (7 * surface->blendNum4)));
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->vertexBuffer = reader.readArray<Game::GfxPackedVertex>(surface->numVertices);
|
|
|
|
surface->indexBuffer = reader.readArray<Game::Face>(surface->numPrimitives);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
|
|
|
// Read vert list
|
2016-11-20 08:09:07 -05:00
|
|
|
if (reader.readByte())
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
surface->ct = reader.readArray<Game::XRigidVertList>(surface->numCT);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
|
|
|
for (int j = 0; j < surface->numCT; ++j)
|
|
|
|
{
|
|
|
|
Game::XRigidVertList* vertList = &surface->ct[j];
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
vertList->entry = reader.readArray<Game::XSurfaceCollisionTree>();
|
|
|
|
vertList->entry->node = reinterpret_cast<char*>(reader.read(16, vertList->entry->numNode));
|
|
|
|
vertList->entry->leaf = reader.readArray<short>(vertList->entry->numLeaf);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
surface->ct = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-01 14:04:20 -05:00
|
|
|
// When all surfaces are loaded, split them up.
|
|
|
|
for (char i = 0; i < model->numLods; ++i)
|
|
|
|
{
|
|
|
|
Game::XModelSurfs* realSurf = builder->getAllocator()->allocate<Game::XModelSurfs>();
|
|
|
|
|
|
|
|
// 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));
|
|
|
|
|
2017-01-02 16:35:55 -05:00
|
|
|
realSurf->numSurfaces = model->lodInfo[i].numsurfs;
|
2017-01-01 14:04:20 -05:00
|
|
|
realSurf->surfaces = builder->getAllocator()->allocateArray<Game::XSurface>(realSurf->numSurfaces);
|
|
|
|
|
2017-01-02 16:35:55 -05:00
|
|
|
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));
|
2017-01-01 14:04:20 -05:00
|
|
|
|
2017-01-02 16:35:55 -05:00
|
|
|
model->lodInfo[i].modelSurfs = realSurf;
|
|
|
|
model->lodInfo[i].surfs = realSurf->surfaces;
|
2017-01-01 14:04:20 -05:00
|
|
|
|
|
|
|
// Store surfs for later writing
|
|
|
|
Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, { realSurf });
|
|
|
|
}
|
|
|
|
|
2016-07-11 11:14:58 -04:00
|
|
|
// Read materials
|
2017-01-02 16:35:55 -05:00
|
|
|
model->materialHandles = builder->getAllocator()->allocateArray<Game::Material*>(model->numsurfs);
|
|
|
|
for (char i = 0; i < model->numsurfs; ++i)
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2017-01-02 16:35:55 -05:00
|
|
|
model->materialHandles[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString(), builder).material;
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read collision surfaces
|
2016-11-20 08:09:07 -05:00
|
|
|
if (reader.readByte())
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2017-01-02 16:35:55 -05:00
|
|
|
model->collSurfs = reader.readArray<Game::XModelCollSurf_s>(model->numCollSurfs);
|
2016-12-23 01:42:56 -05:00
|
|
|
|
2017-01-02 16:35:55 -05:00
|
|
|
for (int i = 0; i < model->numCollSurfs; ++i)
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2017-01-02 16:35:55 -05:00
|
|
|
if (model->collSurfs[i].collTris)
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2017-01-02 16:35:55 -05:00
|
|
|
model->collSurfs[i].collTris = reader.readArray<Game::XModelCollTri_s>(model->collSurfs[i].numCollTris);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-01-02 16:35:55 -05:00
|
|
|
model->collSurfs = nullptr;
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read bone info
|
2016-11-20 08:09:07 -05:00
|
|
|
if (reader.readByte())
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
model->boneInfo = reader.readArray<Game::XBoneInfo>(model->numBones);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
model->boneInfo = nullptr;
|
|
|
|
}
|
|
|
|
|
2016-11-20 08:09:07 -05: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());
|
|
|
|
}
|
|
|
|
|
|
|
|
header->model = model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-20 08:09:07 -05: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)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
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-02 16:35:55 -05:00
|
|
|
for (unsigned 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)
|
|
|
|
{
|
2016-12-23 15:01:56 -05:00
|
|
|
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (asset->physCollmap)
|
|
|
|
{
|
2016-12-23 15:01:56 -05:00
|
|
|
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
void IXModel::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
2016-07-11 11:14:58 -04:00
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
AssertSize(Game::XModel, 304);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
Utils::Stream* buffer = builder->getBuffer();
|
2016-07-11 11:14:58 -04:00
|
|
|
Game::XModel* asset = header.model;
|
2016-11-20 08:09:07 -05:00
|
|
|
Game::XModel* dest = buffer->dest<Game::XModel>();
|
|
|
|
buffer->save(asset);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
|
|
|
if (asset->name)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
|
2016-07-11 11:14:58 -04:00
|
|
|
Utils::Stream::ClearPointer(&dest->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asset->boneNames)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->align(Utils::Stream::ALIGN_2);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
unsigned short* destBoneNames = buffer->dest<unsigned short>();
|
|
|
|
buffer->saveArray(asset->boneNames, asset->numBones);
|
2016-12-23 01:42:56 -05:00
|
|
|
|
2016-07-11 11:14:58 -04:00
|
|
|
for (char i = 0; i < asset->numBones; ++i)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
builder->mapScriptString(&destBoneNames[i]);
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Utils::Stream::ClearPointer(&dest->boneNames);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asset->parentList)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
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
|
|
|
{
|
2016-11-20 08:09:07 -05: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
|
|
|
{
|
2016-11-20 08:09:07 -05: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)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
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
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
AssertSize(Game::DObjAnimMat, 32);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05: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
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->align(Utils::Stream::ALIGN_4);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05: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-02 16:35:55 -05:00
|
|
|
for (unsigned 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
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
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
|
|
|
|
2016-11-20 08:09:07 -05: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
|
|
|
{
|
2016-11-20 08:09:07 -05: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)
|
|
|
|
{
|
2016-11-20 08:09:07 -05:00
|
|
|
AssertSize(Game::XBoneInfo, 28);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->align(Utils::Stream::ALIGN_4);
|
2016-07-11 11:14:58 -04:00
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->saveArray(asset->boneInfo, asset->numBones);
|
2016-07-11 11:14:58 -04:00
|
|
|
Utils::Stream::ClearPointer(&dest->boneInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asset->physPreset)
|
|
|
|
{
|
2016-12-23 01:42:56 -05:00
|
|
|
dest->physPreset = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset).physPreset;
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (asset->physCollmap)
|
|
|
|
{
|
2016-12-23 01:42:56 -05:00
|
|
|
dest->physCollmap = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap).physCollmap;
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
|
2016-11-20 08:09:07 -05:00
|
|
|
buffer->popBlock();
|
2016-07-11 11:14:58 -04:00
|
|
|
}
|
|
|
|
}
|