diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 3aade0dd..2c6f86cc 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -253,9 +253,13 @@ namespace Components Utils::Hook(0x5BB650, AssetHandler::AddAssetStub, HOOK_JUMP).Install()->Quick(); // Register asset interfaces + AssetHandler::RegisterInterface(new Assets::IXModel()); AssetHandler::RegisterInterface(new Assets::IRawFile()); AssetHandler::RegisterInterface(new Assets::IGfxImage()); AssetHandler::RegisterInterface(new Assets::IMaterial()); + AssetHandler::RegisterInterface(new Assets::IPhysPreset()); + AssetHandler::RegisterInterface(new Assets::IPhysCollmap()); + AssetHandler::RegisterInterface(new Assets::IXModelSurfs()); AssetHandler::RegisterInterface(new Assets::ILocalizedEntry()); AssetHandler::RegisterInterface(new Assets::IMaterialPixelShader()); AssetHandler::RegisterInterface(new Assets::IMaterialTechniqueSet()); diff --git a/src/Components/Modules/AssetHandler.hpp b/src/Components/Modules/AssetHandler.hpp index 7e0abb0d..9e5b06ad 100644 --- a/src/Components/Modules/AssetHandler.hpp +++ b/src/Components/Modules/AssetHandler.hpp @@ -56,9 +56,13 @@ namespace Components }; } +#include "AssetInterfaces\IXModel.hpp" #include "AssetInterfaces\IRawFile.hpp" #include "AssetInterfaces\IGfxImage.hpp" #include "AssetInterfaces\IMaterial.hpp" +#include "AssetInterfaces\IPhysPreset.hpp" +#include "AssetInterfaces\IPhysCollmap.hpp" +#include "AssetInterfaces\IXModelSurfs.hpp" #include "AssetInterfaces\ILocalizedEntry.hpp" #include "AssetInterfaces\IMaterialPixelShader.hpp" #include "AssetInterfaces\IMaterialTechniqueSet.hpp" diff --git a/src/Components/Modules/AssetInterfaces/IPhysCollmap.cpp b/src/Components/Modules/AssetInterfaces/IPhysCollmap.cpp new file mode 100644 index 00000000..3d6164b4 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IPhysCollmap.cpp @@ -0,0 +1,130 @@ +#include + +namespace Assets +{ + void IPhysCollmap::Save_BrushWrapper(Components::ZoneBuilder::Zone* builder, Game::BrushWrapper* brush) + { + Assert_Size(Game::BrushWrapper, 68); + + Utils::Stream* buffer = builder->GetBuffer(); + + Game::BrushWrapper* destBrush = buffer->Dest(); + buffer->Save(brush, sizeof(Game::BrushWrapper)); + + // Save_cbrushWrapper_t + { + Assert_Size(Game::cbrushWrapper_t, 36); + + if (brush->brush.brushSide) + { + Assert_Size(Game::cbrushside_t, 8); + + buffer->Align(Utils::Stream::ALIGN_4); + + Game::cbrushside_t* destBrushSide = buffer->Dest(); + buffer->SaveArray(brush->brush.brushSide, brush->brush.count); + + // Save_cbrushside_tArray + for (short i = 0; i < brush->brush.count; ++i) + { + Game::cbrushside_t* destSide = &destBrushSide[i]; + Game::cbrushside_t* side = &brush->brush.brushSide[i]; + + if (side->side) + { + if (builder->HasPointer(side->side)) + { + destSide->side = builder->GetPointer(side->side); + } + else + { + buffer->Align(Utils::Stream::ALIGN_4); + builder->StorePointer(side->side); + + buffer->Save(side->side, sizeof(Game::cplane_t)); + destSide->side = reinterpret_cast(-1); + } + } + } + + destBrush->brush.brushSide = reinterpret_cast(-1); + } + + if (brush->brush.brushEdge) + { + buffer->Save(brush->brush.brushEdge, brush->totalEdgeCount); + destBrush->brush.brushEdge = reinterpret_cast(-1); + } + } + + if (brush->planes) + { + Assert_Size(Game::cplane_t, 20); + + if (builder->HasPointer(brush->planes)) + { + destBrush->planes = builder->GetPointer(brush->planes); + } + else + { + buffer->Align(Utils::Stream::ALIGN_4); + builder->StorePointer(brush->planes); + + buffer->Save(brush->planes, sizeof(Game::cplane_t)); + destBrush->planes = reinterpret_cast(-1); + } + } + } + + void IPhysCollmap::Save_PhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count) + { + Assert_Size(Game::PhysGeomInfo, 68); + + Utils::Stream* buffer = builder->GetBuffer(); + + Game::PhysGeomInfo* destGeoms = buffer->Dest(); + buffer->SaveArray(geoms, count); + + for (unsigned int i = 0; i < count; ++i) + { + Game::PhysGeomInfo* destGeom = &destGeoms[i]; + Game::PhysGeomInfo* geom = &geoms[i]; + + if (geom->brush) + { + buffer->Align(Utils::Stream::ALIGN_4); + + IPhysCollmap::Save_BrushWrapper(builder, geom->brush); + destGeom->brush = reinterpret_cast(-1); + } + } + } + + void IPhysCollmap::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Assert_Size(Game::XModel, 304); + + Utils::Stream* buffer = builder->GetBuffer(); + Game::PhysCollmap* asset = header.physCollmap; + Game::PhysCollmap* dest = buffer->Dest(); + buffer->Save(asset, sizeof(Game::PhysCollmap)); + + buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL); + + if (asset->name) + { + buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name)); + dest->name = reinterpret_cast(-1); + } + + if (asset->geoms) + { + buffer->Align(Utils::Stream::ALIGN_4); + + IPhysCollmap::Save_PhysGeomInfoArray(builder, asset->geoms, asset->count); + dest->geoms = reinterpret_cast(-1); + } + + buffer->PopBlock(); + } +} diff --git a/src/Components/Modules/AssetInterfaces/IPhysCollmap.hpp b/src/Components/Modules/AssetInterfaces/IPhysCollmap.hpp new file mode 100644 index 00000000..06891515 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IPhysCollmap.hpp @@ -0,0 +1,13 @@ +namespace Assets +{ + class IPhysCollmap : public Components::AssetHandler::IAsset + { + virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP; }; + + virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + + private: + void Save_PhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count); + void Save_BrushWrapper(Components::ZoneBuilder::Zone* builder, Game::BrushWrapper* brush); + }; +} diff --git a/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp b/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp new file mode 100644 index 00000000..3483af6a --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp @@ -0,0 +1,32 @@ +#include + +namespace Assets +{ + void IPhysPreset::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Assert_Size(Game::PhysPreset, 44); + + Utils::Stream* buffer = builder->GetBuffer(); + Game::PhysPreset* asset = header.physPreset; + Game::PhysPreset* dest = buffer->Dest(); + buffer->Save(asset, sizeof(Game::PhysPreset)); + + buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL); + + // TODO: I think we have to write them, even if they are NULL + + if (asset->name) + { + buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name)); + dest->name = reinterpret_cast(-1); + } + + if (asset->sndAliasPrefix) + { + buffer->SaveString(asset->sndAliasPrefix); + dest->sndAliasPrefix = reinterpret_cast(-1); + } + + buffer->PopBlock(); + } +} diff --git a/src/Components/Modules/AssetInterfaces/IPhysPreset.hpp b/src/Components/Modules/AssetInterfaces/IPhysPreset.hpp new file mode 100644 index 00000000..3d059c31 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IPhysPreset.hpp @@ -0,0 +1,9 @@ +namespace Assets +{ + class IPhysPreset : public Components::AssetHandler::IAsset + { + virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_PHYSPRESET; }; + + virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + }; +} diff --git a/src/Components/Modules/AssetInterfaces/IXModel.cpp b/src/Components/Modules/AssetInterfaces/IXModel.cpp new file mode 100644 index 00000000..c5f574b0 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IXModel.cpp @@ -0,0 +1,184 @@ +#include + +namespace Assets +{ + void IXModel::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Game::XModel* asset = header.model; + + if (asset->boneNames) + { + for (char i = 0; i < asset->numBones; ++i) + { + builder->AddScriptString(asset->boneNames[i]); + } + } + + for (int i = 0; i < 4; ++i) + { + if (asset->lods[i].surfaces) + { + builder->LoadAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lods[i].surfaces->name); + } + } + + if (asset->physPreset) + { + builder->LoadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset->name); + } + + if (asset->physPreset) + { + builder->LoadAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap->name); + } + } + + void IXModel::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Assert_Size(Game::XModel, 304); + + Utils::Stream* buffer = builder->GetBuffer(); + Game::XModel* asset = header.model; + Game::XModel* dest = buffer->Dest(); + buffer->Save(asset, sizeof(Game::XModel)); + + buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL); + + if (asset->name) + { + buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name)); + dest->name = reinterpret_cast(-1); + } + + if (asset->boneNames) + { + buffer->Align(Utils::Stream::ALIGN_2); + + unsigned short* destBoneNames = buffer->Dest(); + buffer->SaveArray(asset->boneNames, asset->numBones); + + for (char i = 0; i < asset->numBones; ++i) + { + builder->MapScriptString(&destBoneNames[i]); + } + + dest->boneNames = reinterpret_cast(-1); + } + + if (asset->parentList) + { + buffer->Save(asset->parentList, asset->numBones - asset->numRootBones); + dest->parentList = reinterpret_cast(-1); + } + + if (asset->tagAngles) + { + Assert_Size(Game::XModelAngle, 8); + + buffer->Align(Utils::Stream::ALIGN_2); + buffer->Save(asset->tagAngles, sizeof(Game::XModelAngle), asset->numBones - asset->numRootBones); + dest->tagAngles = reinterpret_cast(-1); + } + + if (asset->tagPositions) + { + Assert_Size(Game::XModelTagPos, 12); + + buffer->Align(Utils::Stream::ALIGN_4); + buffer->Save(asset->tagPositions, sizeof(Game::XModelTagPos), asset->numBones - asset->numRootBones); + dest->tagPositions = reinterpret_cast(-1); + } + + if (asset->partClassification) + { + buffer->Save(asset->partClassification,asset->numBones); + dest->partClassification = reinterpret_cast(-1); + } + + if (asset->animMatrix) + { + Assert_Size(Game::DObjAnimMat, 32); + + buffer->Align(Utils::Stream::ALIGN_4); + buffer->Save(asset->animMatrix, sizeof(Game::DObjAnimMat), asset->numBones); + dest->animMatrix = reinterpret_cast(-1); + } + + if (asset->materials) + { + buffer->Align(Utils::Stream::ALIGN_4); + + Game::Material** destMaterials = buffer->Dest(); + buffer->Save(asset->materials, sizeof(Game::Material*), asset->numSurfaces); + + for (char i = 0; i < asset->numSurfaces; ++i) + { + if (asset->materials[i]) + { + destMaterials[i] = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materials[i]->name).material; + } + } + + dest->materials = reinterpret_cast(-1); + } + + // Save_XModelLodInfoArray() + { + Assert_Size(Game::XModelLodInfo, 44); + + for (int i = 0; i < 4; ++i) + { + if (asset->lods[i].surfaces) + { + dest->lods[i].surfaces = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lods[i].surfaces->name).surfaces; + } + } + } + + // Save_XModelCollSurfArray + if (asset->colSurf) + { + Assert_Size(Game::XModelCollSurf, 44); + + buffer->Align(Utils::Stream::ALIGN_4); + + Game::XModelCollSurf* destColSurfs = buffer->Dest(); + buffer->Save(asset->colSurf, asset->numColSurfs); + + for (int i = 0; i < asset->numColSurfs; ++i) + { + Game::XModelCollSurf* destColSurf = &destColSurfs[i]; + Game::XModelCollSurf* colSurf = &asset->colSurf[i]; + + if (colSurf->tris) + { + buffer->Align(Utils::Stream::ALIGN_4); + buffer->Save(colSurf->tris, 48, colSurf->count); + destColSurf->tris = reinterpret_cast(-1); + } + } + + dest->colSurf = reinterpret_cast(-1); + } + + if (asset->boneInfo) + { + buffer->Align(Utils::Stream::ALIGN_4); + + buffer->Save(asset->boneInfo, 28, asset->numBones); + dest->boneInfo = reinterpret_cast(-1); + } + + if (asset->physPreset) + { + dest->physPreset = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset->name).physPreset; + } + + if (asset->physPreset) + { + dest->physPreset = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap->name).physPreset; + } + + buffer->PopBlock(); + } +} diff --git a/src/Components/Modules/AssetInterfaces/IXModel.hpp b/src/Components/Modules/AssetInterfaces/IXModel.hpp new file mode 100644 index 00000000..bfa80350 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IXModel.hpp @@ -0,0 +1,10 @@ +namespace Assets +{ + class IXModel : public Components::AssetHandler::IAsset + { + virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_XMODEL; }; + + virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + virtual void Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + }; +} diff --git a/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp b/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp new file mode 100644 index 00000000..245d025a --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp @@ -0,0 +1,39 @@ +#include + +namespace Assets +{ + void IXModelSurfs::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Assert_Size(Game::XModelSurfs, 36); + + Utils::Stream* buffer = builder->GetBuffer(); + Game::XModelSurfs* asset = header.surfaces; + Game::XModelSurfs* dest = buffer->Dest(); + buffer->Save(asset, sizeof(Game::PhysPreset)); + + buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL); + + if (asset->name) + { + buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name)); + dest->name = reinterpret_cast(-1); + } + + if (asset->surfaces) + { + Assert_Size(Game::XSurface, 64); + + buffer->Align(Utils::Stream::ALIGN_4); + buffer->SaveArray(asset->surfaces, asset->numSurfaces); + + for (int i = 0; i < asset->numSurfaces; ++i) + { + + } + + dest->surfaces = reinterpret_cast(-1); + } + + buffer->PopBlock(); + } +} diff --git a/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp b/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp new file mode 100644 index 00000000..eddb1ed6 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp @@ -0,0 +1,9 @@ +namespace Assets +{ + class IXModelSurfs : public Components::AssetHandler::IAsset + { + virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_XMODELSURFS; }; + + virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + }; +} diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index e661c4c9..d1b229c0 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1226,6 +1226,204 @@ namespace Game int error; } structuredDataFindState_t; + struct XModelAngle + { + short x; + short y; + short z; + short base; // defines the 90-degree point for the shorts + }; + + struct XModelTagPos + { + float x; + float y; + float z; + }; + + struct XSurfaceCollisionTree + { + char pad[24]; + int numNode; + char* node; // el size 16 + int numLeaf; + short* leaf; + }; + + struct XRigidVertList + { + int pad; + int pad2; + XSurfaceCollisionTree* entry; + }; + + struct GfxPackedVertex + { + float x; + float y; + float z; + DWORD color; + WORD texCoords[2]; + float normal[3]; + }; + + struct Face + { + unsigned short v1; + unsigned short v2; + unsigned short v3; + }; + + struct XSurface + { + short pad; // +0 + unsigned short numVertices; // +2 + unsigned short numPrimitives; // +4 + unsigned char streamHandle; // something to do with buffers, +6 + char pad2; // +7 + int pad3; // +8 + Face* indexBuffer; // +12 + short blendNum1; // +16 + short blendNum2; // +18 + short blendNum3; // +20 + short blendNum4; // +22 + char* blendInfo; // +24 + GfxPackedVertex* vertexBuffer; // +28 + int numCT; // +32 + XRigidVertList* ct; // +36 + char pad5[24]; // +40 + // pad5 matches XModelSurfaces pad + // total size, 64 + }; + + struct XModelSurfs + { + const char* name; + XSurface* surfaces; + int numSurfaces; + char pad[24]; + }; + + struct XModelLodInfo + { + char pad[8]; + XModelSurfs* surfaces; + char pad2[32]; + }; + + struct cplane_t + { + vec3_t a; + float dist; + int type; + }; + + struct cbrushside_t + { + cplane_t* side; + short texInfo; + short dispInfo; + }; + + struct cbrushWrapper_t + { + short count; + cbrushside_t* brushSide; + char * brushEdge; + char pad[24]; + }; + +#pragma pack(push, 4) + struct BrushWrapper + { + float mins[3]; + float maxs[3]; + cbrushWrapper_t brush; + int totalEdgeCount; + cplane_t *planes; + }; +#pragma pack(pop) + + struct PhysGeomInfo + { + BrushWrapper *brush; + int type; + float orientation[3][3]; + float offset[3]; + float halfLengths[3]; + }; + + struct PhysMass + { + float centerOfMass[3]; + float momentsOfInertia[3]; + float productsOfInertia[3]; + }; + + struct PhysCollmap + { + const char * name; + unsigned int count; + PhysGeomInfo *geoms; + char unknown[0x18]; + PhysMass mass; + }; + + struct DObjAnimMat + { + float quat[4]; + float trans[3]; + float transWeight; + }; + + struct XModelCollSurf + { + void* tris; // +0, sizeof 48 + int count; // +4 + char pad[36]; // +8 + }; // +44 + + struct PhysPreset + { + const char *name; + int type; + float mass; + float bounce; + float friction; + float bulletForceScale; + float explosiveForceScale; + const char *sndAliasPrefix; + float piecesSpreadFraction; + float piecesUpwardVelocity; + bool tempDefaultToCylinder; + }; + + struct XModel + { + char* name; // +0 + char numBones; // +4 + char numRootBones; // +5 + char numSurfaces; // +6 + char pad2; // +7 + char pad3[28]; // +8 + short* boneNames; // +36 + char* parentList; // +40 + XModelAngle* tagAngles; // +44, element size 8 + XModelTagPos* tagPositions; // +48, element size 12 + char* partClassification; // +52 + DObjAnimMat* animMatrix; // +56, element size 32 + Material** materials; // +60 + XModelLodInfo lods[4]; // +64 + int pad4; // +240 + XModelCollSurf* colSurf; // +244 + int numColSurfs; // +248 + int pad6; + char* boneInfo; // bone count, +256, element size 28 + char pad5[36]; + PhysPreset* physPreset; + PhysCollmap* physCollmap; + }; // total size 304 + union XAssetHeader { void *data; @@ -1244,6 +1442,10 @@ namespace Game MaterialVertexShader *vertexShader; MaterialPixelShader *pixelShader; structuredDataDef_t* structuredData; + XModel* model; + PhysPreset* physPreset; + PhysCollmap* physCollmap; + XModelSurfs* surfaces; }; struct XAsset