From 88771849fb6de48b32af671d2f1d78510d3b7d85 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 5 Jan 2022 20:14:32 +0100 Subject: [PATCH] Add base for physcollmap dumper --- src/Common/Game/IW4/IW4_Assets.h | 14 ++ .../Dumping/MapFile/MapFileDumper.cpp | 175 ++++++++++++++++++ .../Dumping/MapFile/MapFileDumper.h | 71 +++++++ .../AssetDumpers/AssetDumperPhysCollmap.cpp | 84 +++++++++ .../IW4/AssetDumpers/AssetDumperPhysCollmap.h | 16 ++ src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp | 3 +- 6 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 src/ObjWriting/Dumping/MapFile/MapFileDumper.cpp create mode 100644 src/ObjWriting/Dumping/MapFile/MapFileDumper.h create mode 100644 src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.cpp create mode 100644 src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.h diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index b2522c34..71325344 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -237,6 +237,20 @@ namespace IW4 cplane_s* planes; }; + enum PhysicsGeomType + { + PHYS_GEOM_NONE = 0x0, + PHYS_GEOM_BOX = 0x1, + PHYS_GEOM_BRUSHMODEL = 0x2, + PHYS_GEOM_BRUSH = 0x3, + PHYS_GEOM_COLLMAP = 0x4, + PHYS_GEOM_CYLINDER = 0x5, + PHYS_GEOM_CAPSULE = 0x6, + PHYS_GEOM_GLASS = 0x7, + + PHYS_GEOM_COUNT, + }; + struct PhysGeomInfo { BrushWrapper* brushWrapper; diff --git a/src/ObjWriting/Dumping/MapFile/MapFileDumper.cpp b/src/ObjWriting/Dumping/MapFile/MapFileDumper.cpp new file mode 100644 index 00000000..cebb9606 --- /dev/null +++ b/src/ObjWriting/Dumping/MapFile/MapFileDumper.cpp @@ -0,0 +1,175 @@ +#include "MapFileDumper.h" + +#include +#include + +MapFileDumper::Vec3::Vec3(const float x, const float y, const float z) + : v{} +{ + m_x = x; + m_y = y; + m_z = z; +} + +MapFileDumper::Vec3::Vec3(float v[3]) + : v{v[0], v[1], v[2]} +{ +} + +MapFileDumper::PhysicsBox::PhysicsBox(const Vec3 middlePoint, const Vec3 halfSize, const Vec3 orientationX, const Vec3 orientationY, const Vec3 orientationZ) + : m_middle_point(middlePoint), + m_half_size(halfSize), + m_orientation{orientationX, orientationY, orientationZ} +{ +} + +MapFileDumper::PhysicsCylinder::PhysicsCylinder(const Vec3 middlePoint, const float radius, const float height, const Vec3 orientation) + : m_middle_point(middlePoint), + m_radius(radius), + m_height(height), + m_orientation(orientation) +{ +} + +MapFileDumper::MapFileDumper(std::ostream& stream) + : m_stream(stream), + m_flags{}, + m_indent(0u), + m_entity_index(0u), + m_brush_index(0u) +{ +} + +void MapFileDumper::Indent() const +{ + for (auto i = 0u; i < m_indent; i++) + m_stream << " "; +} + +void MapFileDumper::IncIndent() +{ + ++m_indent; +} + +void MapFileDumper::DecIndent() +{ + assert(m_indent > 0); + if (m_indent > 0) + m_indent--; +} + +void MapFileDumper::Init() const +{ + m_stream << "iwmap 4\n"; + m_stream << "\"000_Global\" flags active\n"; + m_stream << "\"The Map\" flags\n"; +} + +void MapFileDumper::BeginEntity() +{ + assert(!m_flags.m_in_entity); + if (m_flags.m_in_entity) + return; + + Indent(); + m_stream << "// entity " << m_entity_index << "\n"; + + Indent(); + m_stream << "{\n"; + + IncIndent(); + m_entity_index++; + m_brush_index = 0; + m_flags.m_in_entity = true; +} + +void MapFileDumper::EndEntity() +{ + assert(m_flags.m_in_entity); + if (!m_flags.m_in_entity) + return; + + DecIndent(); + Indent(); + m_stream << "}\n"; + m_flags.m_in_entity = false; +} + +void MapFileDumper::BeginBrush() +{ + assert(m_flags.m_in_entity && !m_flags.m_in_brush); + if (m_flags.m_in_brush) + return; + + Indent(); + m_stream << "// brush " << m_brush_index << "\n"; + + Indent(); + m_stream << "{\n"; + + IncIndent(); + m_brush_index++; + m_flags.m_in_brush = true; +} + +void MapFileDumper::EndBrush() +{ + assert(m_flags.m_in_entity && m_flags.m_in_brush); + if (!m_flags.m_in_brush) + return; + + DecIndent(); + Indent(); + m_stream << "}\n"; + m_flags.m_in_brush = false; +} + +void MapFileDumper::WriteKeyValue(const std::string& key, const std::string& value) const +{ + assert(m_flags.m_in_brush || m_flags.m_in_entity); + + Indent(); + m_stream << "\"" << key << "\" \"" << value << "\"\n"; +} + +void MapFileDumper::WritePhysicsBox(const PhysicsBox box) +{ + Indent(); + m_stream << "physics_box\n"; + Indent(); + m_stream << "{\n"; + IncIndent(); + + Indent(); + m_stream << std::fixed << std::setprecision(6) + << box.m_orientation[0].m_x << " " << box.m_orientation[0].m_y << " " << box.m_orientation[0].m_z + << " " << box.m_orientation[1].m_x << " " << box.m_orientation[1].m_y << " " << box.m_orientation[1].m_z + << " " << box.m_orientation[2].m_x << " " << box.m_orientation[2].m_y << " " << box.m_orientation[2].m_z + << " " << box.m_middle_point.m_x << " " << box.m_middle_point.m_y << " " << box.m_middle_point.m_z + << " " << box.m_half_size.m_x << " " << box.m_half_size.m_y << " " << box.m_half_size.m_z + << "\n"; + + DecIndent(); + Indent(); + m_stream << "}\n"; +} + +void MapFileDumper::WritePhysicsCylinder(PhysicsCylinder cylinder) +{ + Indent(); + m_stream << "physics_cylinder\n"; + Indent(); + m_stream << "{\n"; + IncIndent(); + + Indent(); + m_stream << std::fixed << std::setprecision(6) + << cylinder.m_orientation.m_x << " " << cylinder.m_orientation.m_y << " " << cylinder.m_orientation.m_z + << " " << cylinder.m_middle_point.m_x << " " << cylinder.m_middle_point.m_y << " " << cylinder.m_middle_point.m_z + << " " << cylinder.m_height << " " << cylinder.m_radius + << "\n"; + + DecIndent(); + Indent(); + m_stream << "}\n"; +} diff --git a/src/ObjWriting/Dumping/MapFile/MapFileDumper.h b/src/ObjWriting/Dumping/MapFile/MapFileDumper.h new file mode 100644 index 00000000..14934bf4 --- /dev/null +++ b/src/ObjWriting/Dumping/MapFile/MapFileDumper.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +class MapFileDumper +{ +public: + union Vec3 + { + struct + { + float m_x; + float m_y; + float m_z; + }; + float v[3]; + + Vec3(float x, float y, float z); + explicit Vec3(float v[3]); + }; + + struct PhysicsBox + { + Vec3 m_middle_point; + Vec3 m_half_size; + Vec3 m_orientation[3]; + + PhysicsBox(Vec3 middlePoint, Vec3 halfSize, Vec3 orientationX, Vec3 orientationY, Vec3 orientationZ); + }; + + struct PhysicsCylinder + { + Vec3 m_middle_point; + float m_radius; + float m_height; + Vec3 m_orientation; + + PhysicsCylinder(Vec3 middlePoint, float radius, float height, Vec3 orientation); + }; + +private: + std::ostream& m_stream; + + struct + { + bool m_in_entity : 1; + bool m_in_brush : 1; + } m_flags; + size_t m_indent; + size_t m_entity_index; + size_t m_brush_index; + + void Indent() const; + void IncIndent(); + void DecIndent(); + +public: + explicit MapFileDumper(std::ostream& stream); + + void Init() const; + + void BeginEntity(); + void EndEntity(); + + void BeginBrush(); + void EndBrush(); + + void WriteKeyValue(const std::string& key, const std::string& value) const; + void WritePhysicsBox(PhysicsBox box); + void WritePhysicsCylinder(PhysicsCylinder cylinder); +}; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.cpp new file mode 100644 index 00000000..546fd99b --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.cpp @@ -0,0 +1,84 @@ +#include "AssetDumperPhysCollmap.h" + +#include +#include + +#include "Dumping/MapFile/MapFileDumper.h" + +using namespace IW4; + +std::string AssetDumperPhysCollmap::GetAssetFilename(const std::string& assetName) +{ + std::ostringstream ss; + + ss << "phys_collmaps/" << assetName << ".map"; + + return ss.str(); +} + +bool AssetDumperPhysCollmap::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperPhysCollmap::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto* physCollmap = asset->Asset(); + const auto assetFile = context.OpenAssetFile(GetAssetFilename(asset->m_name)); + + if (!assetFile) + return; + + MapFileDumper mapFileDumper(*assetFile); + mapFileDumper.Init(); + + if (physCollmap->count <= 0 || physCollmap->geoms == nullptr) + return; + + mapFileDumper.BeginEntity(); + + mapFileDumper.WriteKeyValue("classname", "worldspawn"); + + for (auto i = 0u; i < physCollmap->count; i++) + { + const auto& geom = physCollmap->geoms[i]; + mapFileDumper.BeginBrush(); + + switch (geom.type) + { + case PHYS_GEOM_NONE: + break; + case PHYS_GEOM_BOX: + mapFileDumper.WritePhysicsBox({ + {geom.bounds.midPoint[0], geom.bounds.midPoint[1], geom.bounds.midPoint[2]}, + {geom.bounds.halfSize[0], geom.bounds.halfSize[1], geom.bounds.halfSize[2]}, + {geom.orientation[0][0], geom.orientation[0][1], geom.orientation[0][2]}, + {geom.orientation[1][0], geom.orientation[1][1], geom.orientation[1][2]}, + {geom.orientation[2][0], geom.orientation[2][1], geom.orientation[2][2]} + }); + break; + + case PHYS_GEOM_CYLINDER: + mapFileDumper.WritePhysicsCylinder({ + {geom.bounds.midPoint[0], geom.bounds.midPoint[1], geom.bounds.midPoint[2]}, + geom.bounds.halfSize[0], + geom.bounds.halfSize[2] * 2, + {geom.orientation[0][0], geom.orientation[0][1], geom.orientation[0][2]} + }); + break; + + case PHYS_GEOM_BRUSHMODEL: + case PHYS_GEOM_BRUSH: + case PHYS_GEOM_COLLMAP: + case PHYS_GEOM_CAPSULE: + case PHYS_GEOM_GLASS: + default: + assert(false); + break; + } + + mapFileDumper.EndBrush(); + } + + mapFileDumper.EndEntity(); +} diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.h new file mode 100644 index 00000000..22bde883 --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysCollmap.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW4/IW4.h" + +namespace IW4 +{ + class AssetDumperPhysCollmap final : public AbstractAssetDumper + { + static std::string GetAssetFilename(const std::string& assetName); + + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} diff --git a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp index 52da4a6a..b15ec83c 100644 --- a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp @@ -11,6 +11,7 @@ #include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperMenuDef.h" #include "AssetDumpers/AssetDumperMenuList.h" +#include "AssetDumpers/AssetDumperPhysCollmap.h" #include "AssetDumpers/AssetDumperPhysPreset.h" #include "AssetDumpers/AssetDumperRawFile.h" #include "AssetDumpers/AssetDumperSndCurve.h" @@ -38,7 +39,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const const auto* assetPools = dynamic_cast(context.m_zone->m_pools.get()); DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset, ASSET_TYPE_PHYSPRESET) - // DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap, ASSET_TYPE_PHYSCOLLMAP) + DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap, ASSET_TYPE_PHYSCOLLMAP) // DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts, ASSET_TYPE_XANIMPARTS) DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel, ASSET_TYPE_XMODEL) // DUMP_ASSET_POOL(AssetDumperMaterial, m_material, ASSET_TYPE_MATERIAL)