#pragma once #include #include #include #include "KingSystem/Physics/physDefines.h" #include "KingSystem/Utils/BitField.h" namespace ksys::phys { union MaterialMaskData { // FIXME: incomplete SEAD_ENUM(CustomFlag, _0) constexpr explicit MaterialMaskData(u32 raw_ = 0) : raw(raw_) {} constexpr MaterialMaskData(const MaterialMaskData&) = default; constexpr MaterialMaskData& operator=(const MaterialMaskData& other) { raw = other.raw; return *this; } static constexpr bool isValidSubMaterialIdx(int idx) { return u32(idx) < (1 << decltype(sub_material)::NumBits()); } Material getMaterial() const { return int(material.Value()); } int getSubMaterialIndex() const { return int(sub_material.Value()); } FloorCode getFloorCode() const { return int(floor.Value()); } WallCode getWallCode() const { return int(wall.Value()); } void setFlag31(bool b) { if (!b) clearFlag31(); else setFlag31(); } void setFlag31() { flag31 = 1; } void clearFlag31() { flag31 = 0; } void setCustomFlag(CustomFlag custom_flag) { raw |= 1 << (decltype(custom_flags)::StartBit() + custom_flag); } bool getCustomFlag(CustomFlag custom_flag) const { return (raw & 1 << (decltype(custom_flags)::StartBit() + custom_flag)) != 0; } u32 raw; util::BitField<0, 6, u32> material; util::BitField<6, 4, int, u32> sub_material; util::BitField<10, 5, u32> floor; util::BitField<15, 5, u32> wall; // TODO: rename once we figure out what these flags are util::BitField<23, 7, u32> custom_flags; util::BitField<30, 1, u32> flag30; util::BitField<31, 1, u32> flag31; }; static_assert(sizeof(MaterialMaskData) == sizeof(u32)); class MaterialMask { public: MaterialMask(); explicit MaterialMask(u32 data); explicit MaterialMask(u64 havok_user_data) : MaterialMask(static_cast(havok_user_data)) {} MaterialMask(Material mat, FloorCode floor, WallCode wall, bool flag = false); MaterialMask(Material mat, const char* submat_name, FloorCode floor, WallCode wall, bool flag = false); MaterialMask(Material mat, int submat_idx, FloorCode floor, WallCode wall, bool flag = false); MaterialMask(const MaterialMask& other) : mData(other.mData) {} // XXX: this doesn't need to be virtual. virtual ~MaterialMask(); MaterialMask& operator=(const MaterialMask& other) { set(other.mData); return *this; } MaterialMask& operator=(MaterialMaskData data) { set(data); return *this; } MaterialMaskData& getData() { return mData; } const MaterialMaskData& getData() const { return mData; } u32 getRawData() const { return mData.raw; } Material getMaterial() const { return mData.getMaterial(); } int getSubMaterialIdx() const { return mData.getSubMaterialIndex(); } FloorCode getFloorCode() const { return mData.getFloorCode(); } WallCode getWallCode() const { return mData.getWallCode(); } const char* getMaterialName() const; const char* getSubMaterialName() const; void set(MaterialMaskData data) { mData = data; mSubMaterialNameCache = nullptr; } void set(u32 data) { set(MaterialMaskData{data}); } void reset() { set(0); } void setMaterial(Material mat); static int getSubMaterialIdx(Material mat, const sead::SafeString& submat_name); static const sead::SafeString& getSubMaterialName(Material mat, int submat_idx); static int getNumSubMaterials(Material mat); static const sead::SafeString& getSubMaterialName(int mat, int submat_idx); private: MaterialMaskData mData{}; /// Fetching the name of a sub-material from the MaterialTable is an expensive operation, /// so it is only done once and the result is cached. mutable const char* mSubMaterialNameCache{}; }; } // namespace ksys::phys