diff --git a/deps/protobuf b/deps/protobuf index 401e07d3..fba7976f 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 401e07d3726e91659228dff8ed9f7cb02026c47e +Subproject commit fba7976f5d6f1be69d4219a7c485c93b8b28bf65 diff --git a/src/Components/Modules/AssetInterfaces/IMaterial.cpp b/src/Components/Modules/AssetInterfaces/IMaterial.cpp index 4d1e5e0f..9b96529d 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterial.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterial.cpp @@ -93,8 +93,8 @@ namespace Assets textureDef.semantic = 0; // No water image textureDef.sampleState = -30; - textureDef.nameEnd = map.string_value().data()[map.string_value().size() - 1]; - textureDef.nameStart = map.string_value().data()[0]; + textureDef.nameEnd = map.string_value().back(); + textureDef.nameStart = map.string_value().front(); textureDef.nameHash = Game::R_HashString(map.string_value().data()); textureDef.info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image; diff --git a/src/Components/Modules/AssetInterfaces/IXModel.cpp b/src/Components/Modules/AssetInterfaces/IXModel.cpp index 64505d2a..24ff21db 100644 --- a/src/Components/Modules/AssetInterfaces/IXModel.cpp +++ b/src/Components/Modules/AssetInterfaces/IXModel.cpp @@ -2,6 +2,147 @@ namespace Assets { + void IXModel::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) + { + Components::FileSystem::File modelFile(Utils::VA("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()->AllocateArray(); + memcpy(model, baseModel, sizeof(Game::XModel)); + + Utils::Stream::Reader reader(builder->GetAllocator(), modelFile.GetBuffer()); + + model->name = reader.ReadCString(); + model->numBones = reader.ReadByte(); + model->numRootBones = reader.ReadByte(); + model->numSurfaces = reader.ReadByte(); + model->numColSurfs = reader.Read(); + + // Read bone names + model->boneNames = builder->GetAllocator()->AllocateArray(model->numBones); + for (int i = 0; i < model->numBones; ++i) + { + model->boneNames[i] = Game::SL_GetString(reader.ReadCString(), 0); + } + + // Bone count + int boneCount = (model->numBones - model->numRootBones); + + // Read bone data + model->parentList = reader.ReadArray(boneCount); + model->tagAngles = reader.ReadArray(boneCount); + model->tagPositions = reader.ReadArray(boneCount); + model->partClassification = reader.ReadArray(boneCount); + model->animMatrix = reader.ReadArray(boneCount); + + // Prepare surfaces + Game::XSurface* baseSurface = &baseModel->lods[0].surfaces[0].surfaces[0]; + Game::XModelSurfs* surf = builder->GetAllocator()->AllocateArray(); + + memcpy(surf, baseModel->lods[0].surfaces, sizeof(Game::XModelSurfs)); + surf->name = builder->GetAllocator()->DuplicateString(Utils::VA("%s1", model->name)); + surf->surfaces = builder->GetAllocator()->AllocateArray(model->numSurfaces); + surf->numSurfaces = model->numSurfaces; + + model->lods[0].numSurfs = model->numSurfaces; + model->lods[0].surfaces = surf; + + // Reset surfaces in remaining lods + for (unsigned int i = 1; i < 4; ++i) + { + model->lods[i].numSurfs = 0; + model->lods[i].surfaces = nullptr; + } + + // Read surfaces + for (int i = 0; i < surf->numSurfaces; ++i) + { + Game::XSurface* surface = &surf->surfaces[i]; + memcpy(surface, baseSurface, sizeof(Game::XSurface)); + + surface->numVertices = reader.Read(); + surface->numPrimitives = reader.Read(); + surface->numCT = reader.Read(); + + surface->blendNum1 = reader.Read(); + surface->blendNum2 = reader.Read(); + surface->blendNum3 = reader.Read(); + surface->blendNum4 = reader.Read(); + + surface->blendInfo = reinterpret_cast(reader.Read(2, surface->blendNum1 + (3 * surface->blendNum2) + (5 * surface->blendNum3) + (7 * surface->blendNum4))); + + surface->vertexBuffer = reader.ReadArray(surface->numVertices); + surface->indexBuffer = reader.ReadArray(surface->numPrimitives); + + // Read vert list + if (reader.ReadByte()) + { + surface->ct = reader.ReadArray(surface->numCT); + + for (int j = 0; j < surface->numCT; ++j) + { + Game::XRigidVertList* vertList = &surface->ct[j]; + + vertList->entry = reader.ReadArray(); + vertList->entry->node = reinterpret_cast(reader.Read(16, vertList->entry->numNode)); + vertList->entry->leaf = reader.ReadArray(vertList->entry->numLeaf); + } + } + else + { + surface->ct = nullptr; + } + } + + // Read materials + model->materials = builder->GetAllocator()->AllocateArray(model->numSurfaces); + for (char i = 0; i < model->numSurfaces; ++i) + { + model->materials[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.ReadString(), builder).material; + model->materials[i] = baseModel->materials[0]; + } + + // Read collision surfaces + if (reader.ReadByte()) + { + model->colSurf = reader.ReadArray(model->numColSurfs); + + for (int i = 0; i < model->numColSurfs; ++i) + { + if (model->colSurf[i].tris) + { + model->colSurf[i].tris = reader.Read(48, model->colSurf[i].count); + } + } + } + else + { + model->colSurf = nullptr; + } + + // Read bone info + if (reader.ReadByte()) + { + model->boneInfo = reader.ReadArray(model->numBones); + } + else + { + model->boneInfo = nullptr; + } + + if (!reader.End()) + { + Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data()); + } + + header->model = model; + } + } + void IXModel::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) { Game::XModel* asset = header.model; @@ -186,10 +327,12 @@ namespace Assets if (asset->boneInfo) { + Assert_Size(Game::XBoneInfo, 28); + buffer->Align(Utils::Stream::ALIGN_4); - buffer->Save(asset->boneInfo, 28, asset->numBones); - dest->boneInfo = reinterpret_cast(-1); + buffer->SaveArray(asset->boneInfo, asset->numBones); + dest->boneInfo = reinterpret_cast(-1); } if (asset->physPreset) diff --git a/src/Components/Modules/AssetInterfaces/IXModel.hpp b/src/Components/Modules/AssetInterfaces/IXModel.hpp index 41ef6498..3a2f9129 100644 --- a/src/Components/Modules/AssetInterfaces/IXModel.hpp +++ b/src/Components/Modules/AssetInterfaces/IXModel.hpp @@ -7,5 +7,6 @@ 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; }; } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index e6443899..6dc93e86 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1304,7 +1304,8 @@ namespace Game struct XSurfaceCollisionTree { - char pad[24]; + float trans[3]; + float scale[3]; int numNode; char* node; // el size 16 int numLeaf; @@ -1313,8 +1314,10 @@ namespace Game struct XRigidVertList { - int pad; - int pad2; + unsigned short boneOffset; + unsigned short vertCount; + unsigned short triOffset; + unsigned short triCount; XSurfaceCollisionTree* entry; }; @@ -1371,7 +1374,9 @@ namespace Game short numSurfs; // +4 short pad2;// +6 XModelSurfs* surfaces; // +8 - char pad3[32]; // +12 + char pad3[24]; + XSurface* surfs; + char pad4[4]; // +12 }; struct cplane_t @@ -1461,9 +1466,15 @@ namespace Game bool tempDefaultToCylinder; }; + struct XBoneInfo + { + float bounds[2][3]; + float radiusSquared; + }; + struct XModel { - char* name; // +0 + const char* name; // +0 char numBones; // +4 char numRootBones; // +5 char numSurfaces; // +6 @@ -1477,16 +1488,52 @@ namespace Game DObjAnimMat* animMatrix; // +56, element size 32 Material** materials; // +60 XModelLodInfo lods[4]; // +64 - int pad4; // +240 + char pad4; + char numLods; + short collLod; XModelCollSurf* colSurf; // +244 int numColSurfs; // +248 - int pad6; - char* boneInfo; // bone count, +256, element size 28 - char pad5[36]; + int contents; + XBoneInfo* boneInfo; // bone count, +256, element size 28 + char pad7[36]; PhysPreset* physPreset; PhysCollmap* physCollmap; }; // total size 304 + struct DSkelPartBits + { + int anim[4]; + int control[4]; + int skel[4]; + }; + + struct DSkel + { + DSkelPartBits partBits; + int timeStamp; + DObjAnimMat *mat; + }; + +#pragma pack(push, 2) + struct DObj + { + /*XAnimTree_s*/void *tree; + unsigned __int16 duplicateParts; + unsigned __int16 entnum; + char duplicatePartsSize; + char numModels; + char numBones; + char pad; + unsigned int ignoreCollision; + volatile int locked; + DSkel skel; + float radius; + int hidePartBits[4]; + char pad2[56]; + XModel **models; + }; +#pragma pack(pop) + union XAnimDynamicIndices { char _1[1]; diff --git a/src/Utils/Stream.hpp b/src/Utils/Stream.hpp index 143df90d..be9fe557 100644 --- a/src/Utils/Stream.hpp +++ b/src/Utils/Stream.hpp @@ -24,6 +24,17 @@ namespace Utils { return reinterpret_cast(Read(sizeof(T), count)); } + template T Read() + { + T obj; + + for (unsigned int i = 0; i < sizeof(T); ++i) + { + reinterpret_cast(&obj)[i] = ReadByte(); + } + + return obj; + } bool End(); void Seek(unsigned int position);