diff --git a/src/Components/Modules/AssetInterfaces/IXModel.cpp b/src/Components/Modules/AssetInterfaces/IXModel.cpp index b7746e07..e007e7d7 100644 --- a/src/Components/Modules/AssetInterfaces/IXModel.cpp +++ b/src/Components/Modules/AssetInterfaces/IXModel.cpp @@ -1,21 +1,83 @@ #include -#define IW4X_MODEL_VERSION 3 +#define IW4X_MODEL_VERSION 4 namespace Assets { + void IXModel::loadXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Utils::Stream::Reader* reader) + { + if (entry->nodes) + { + entry->nodes = reader->readArray(entry->nodeCount); + } + + if (entry->leafs) + { + entry->leafs = reader->readArray(entry->leafCount); + } + } + + void IXModel::loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader) + { + if (surf->vertInfo.vertsBlend) + { + surf->vertInfo.vertsBlend = reader->readArray(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(surf->vertCount); + } + + // Save_XRigidVertListArray + if (surf->vertList) + { + surf->vertList = reader->readArray(surf->vertListCount); + + for (unsigned int i = 0; i < surf->vertListCount; ++i) + { + Game::XRigidVertList* rigidVertList = &surf->vertList[i]; + + if (rigidVertList->collisionTree) + { + rigidVertList->collisionTree = reader->readObject(); + this->loadXSurfaceCollisionTree(rigidVertList->collisionTree, reader); + } + } + } + + // Access index block + if (surf->triIndices) + { + surf->triIndices = reader->readArray(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(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) { Components::FileSystem::File modelFile(fmt::sprintf("xmodel/%s.iw4xModel", name.data())); 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(); - std::memcpy(model, baseModel, sizeof(Game::XModel)); - Utils::Stream::Reader reader(builder->getAllocator(), modelFile.getBuffer()); 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); } - ZeroMemory(model->noScalePartBits, sizeof model->noScalePartBits); + Game::XModel* asset = reader.readObject(); - model->name = reader.readCString(); - model->numBones = reader.readByte(); - model->numRootBones = reader.readByte(); - model->numsurfs = reader.read(); - model->numCollSurfs = reader.read(); - model->numLods = static_cast(reader.read()); - model->collLod = static_cast(reader.read()); - - // Read bone names - model->boneNames = builder->getAllocator()->allocateArray(model->numBones); - for (char i = 0; i < model->numBones; ++i) + if (asset->name) { - model->boneNames[i] = Game::SL_GetString(reader.readCString(), 0); + asset->name = reader.readCString(); } - // Bone count - int boneCount = (model->numBones - model->numRootBones); - - // Read bone data - model->parentList = reader.readArray(boneCount); - model->quats = reader.readArray(boneCount * 4); - model->trans = reader.readArray(boneCount * 3); - model->partClassification = reader.readArray(boneCount); - model->baseMat = reader.readArray(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(model->numsurfs); - surf.numSurfaces = model->numsurfs; - - for (int i = 0; i < 4; ++i) + if (asset->boneNames) { - model->lodInfo[i].dist = reader.read(); - model->lodInfo[i].numsurfs = reader.read(); - model->lodInfo[i].surfIndex = reader.read(); + asset->boneNames = builder->getAllocator()->allocateArray(asset->numBones); - model->lodInfo[i].partBits[0] = reader.read(); - model->lodInfo[i].partBits[1] = reader.read(); - model->lodInfo[i].partBits[2] = reader.read(); - model->lodInfo[i].partBits[3] = reader.read(); - 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(); - surface->deformed = reader.read(); - - surface->zoneHandle = reader.read(); - surface->partBits[0] = reader.read(); - surface->partBits[1] = reader.read(); - surface->partBits[2] = reader.read(); - surface->partBits[3] = reader.read(); - surface->partBits[4] = 0; - surface->partBits[5] = 0; - - surface->baseTriIndex = reader.read(); - surface->baseVertIndex = reader.read(); - - surface->vertCount = reader.read(); - surface->triCount = reader.read(); - surface->vertListCount = reader.read(); - - surface->vertInfo.vertCount[0] = reader.read(); - surface->vertInfo.vertCount[1] = reader.read(); - surface->vertInfo.vertCount[2] = reader.read(); - surface->vertInfo.vertCount[3] = reader.read(); - - surface->vertInfo.vertsBlend = reader.readArray(surface->vertInfo.vertCount[0] + (3 * surface->vertInfo.vertCount[1]) + (5 * surface->vertInfo.vertCount[2]) + (7 * surface->vertInfo.vertCount[3])); - - surface->verts0 = reader.readArray(surface->vertCount); - surface->triIndices = reader.readArray(3 * surface->triCount); - - // Read vert list - if (reader.readByte()) + for (char i = 0; i < asset->numBones; ++i) { - surface->vertList = reader.readArray(surface->vertListCount); - - for (unsigned int j = 0; j < surface->vertListCount; ++j) - { - Game::XRigidVertList* vertList = &surface->vertList[j]; - - vertList->collisionTree = reader.readArray(); - vertList->collisionTree->nodes = reader.readArray(vertList->collisionTree->nodeCount); - vertList->collisionTree->leafs = reader.readArray(vertList->collisionTree->leafCount); - } - } - else - { - surface->vertList = nullptr; + asset->boneNames[i] = Game::SL_GetString(reader.readCString(), 0); } } - // When all surfaces are loaded, split them up. - for (char i = 0; i < model->numLods; ++i) + if (asset->parentList) { - Game::XModelSurfs* realSurf = builder->getAllocator()->allocate(); - - // 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(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 }); + asset->parentList = reader.readArray(asset->numBones - asset->numRootBones); } - // Read materials - model->materialHandles = builder->getAllocator()->allocateArray(model->numsurfs); - for (char i = 0; i < model->numsurfs; ++i) + if (asset->quats) { - model->materialHandles[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString(), builder).material; + asset->quats = reader.readArray((asset->numBones - asset->numRootBones) * 4); } - // Read collision surfaces - if (reader.readByte()) + if (asset->trans) { - model->collSurfs = reader.readArray(model->numCollSurfs); + asset->trans = reader.readArray((asset->numBones - asset->numRootBones) * 3); + } - for (int i = 0; i < model->numCollSurfs; ++i) + if (asset->partClassification) + { + asset->partClassification = reader.readArray(asset->numBones); + } + + if (asset->baseMat) + { + asset->baseMat = reader.readArray(asset->numBones); + } + + if (asset->materialHandles) + { + asset->materialHandles = reader.readArray(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(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(); + this->loadXModelSurfs(asset->lodInfo[i].modelSurfs, &reader); + Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, { asset->lodInfo[i].modelSurfs }); + } + } } - // Read bone info - if (reader.readByte()) + // Save_XModelCollSurfArray + if (asset->collSurfs) { - model->boneInfo = reader.readArray(model->numBones); + asset->collSurfs = reader.readArray(asset->numCollSurfs); + + for (int i = 0; i < asset->numCollSurfs; ++i) + { + Game::XModelCollSurf_s* collSurf = &asset->collSurfs[i]; + + if (collSurf->collTris) + { + collSurf->collTris = reader.readArray(collSurf->numCollTris); + } + } } - else + + if (asset->boneInfo) { - model->boneInfo = nullptr; + asset->boneInfo = reader.readArray(asset->numBones); + } + + if (asset->physPreset) + { + // TODO + asset->physPreset = nullptr; + } + + if (asset->physCollmap) + { + // TODO + asset->physCollmap = nullptr; } if (!reader.end()) @@ -194,7 +197,7 @@ namespace Assets Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data()); } - header->model = model; + header->model = asset; } } diff --git a/src/Components/Modules/AssetInterfaces/IXModel.hpp b/src/Components/Modules/AssetInterfaces/IXModel.hpp index 54d9959c..7c87891a 100644 --- a/src/Components/Modules/AssetInterfaces/IXModel.hpp +++ b/src/Components/Modules/AssetInterfaces/IXModel.hpp @@ -8,5 +8,10 @@ namespace Assets virtual void save(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; + + 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); }; } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 2f6b4fa4..6bfdfb79 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1663,7 +1663,7 @@ namespace Game struct PhysCollmap { - const char * name; + const char *name; unsigned int count; PhysGeomInfo *geoms; char unknown[0x18];