diff --git a/include/cbreader/rmesh.h b/include/cbreader/rmesh.h index cb3d2c0..221417b 100644 --- a/include/cbreader/rmesh.h +++ b/include/cbreader/rmesh.h @@ -7,167 +7,177 @@ class BufferStream; -constexpr std::uint32_t MAX_SOUND_EMITTERS = 16; - -struct Header +namespace rmesh { - // Length prefixed string - std::string header; - /** Defines whether or not the RMesh file has any triggers embedded within the file. */ - bool hasTriggerBox = false; + constexpr std::uint32_t MAX_SOUND_EMITTERS = 16; - /** NTF Mod specific property. */ - bool hasNoColl = false; -}; + struct Header + { + // Length prefixed string + std::string header; -struct Texture -{ - std::byte blendType; + /** Defines whether or not the RMesh file has any triggers embedded within the file. */ + bool hasTriggerBox = false; - std::string textureName; -}; + /** NTF Mod specific property. */ + bool hasNoColl = false; + }; -struct Vertex -{ - Vector3 vertex; - Vector2 uv; + struct Texture + { + std::byte blendType; - float unk1{}; - float unk2{}; + std::string textureName; + }; - std::byte r{}; - std::byte g{}; - std::byte b{}; -}; + struct Vertex + { + Vector3 vertex; + Vector2 uv; -struct Surface -{ - Texture textures[2]; + float unk1{}; + float unk2{}; - std::vector vertices; + std::byte r{}; + std::byte g{}; + std::byte b{}; + }; - std::vector triangles; -}; + struct Surface + { + Texture textures[2]; -struct Mesh -{ - std::vector surfaces; - - /** Only valid for TriggerBoxes */ - std::string name; -}; - -/** -* @class Entity -* -* Root entity class embedded in RMesh files -*/ -struct Entity -{ - std::string className; + std::vector vertices; - /** This is read per entity. It would be ideal to read it in Entity, but EntityModel is special in that it has the model file name THEN the position. */ - Vector3 position; - Vector3 rotation; - Vector3 scale; + std::vector triangles; + }; - virtual ~Entity() = default; + /** + * @class Mesh + * + * A collection of surfaces that make up the visual and collision mesh for RMesh + */ + struct Mesh + { + std::vector surfaces; - virtual void Read(BufferStream& stream, std::string _className); -}; + /** Only valid for TriggerBoxes */ + std::string name; + }; -struct EntityScreen : public Entity -{ - std::string imgPath; + /** + * @class Entity + * + * Root entity class embedded in RMesh files + */ + struct Entity + { + std::string className; - void Read(BufferStream& stream, std::string _className) override; -}; + /** This is read per entity. It would be ideal to read it in Entity, but EntityModel is special in that it has the model file name THEN the position. */ + Vector3 position; + Vector3 rotation; + Vector3 scale; -struct EntityWaypoint : public Entity -{ - void Read(BufferStream& stream, std::string _className) override; -}; + virtual ~Entity() = default; -struct EntityLight : public Entity -{ - /** SCP:CB calculates this as range/2000.0 in the RMesh code*/ - float range = 0.f; + virtual void Read(BufferStream& stream, std::string _className); + }; - /** Space delimited color string. Color is 3 ints, and multiplied by intensity when reading. */ - std::string color; + struct EntityScreen : public Entity + { + std::string imgPath; - /** SCP:CB calculates this as Min(intensity*0.8,1)*/ - float intensity = 0.f; + void Read(BufferStream& stream, std::string _className) override; + }; - void Read(BufferStream& stream, std::string _className) override; -}; + struct EntityWaypoint : public Entity + { + void Read(BufferStream& stream, std::string _className) override; + }; -struct EntitySpotLight : public EntityLight -{ - std::string angles; + struct EntityLight : public Entity + { + /** SCP:CB calculates this as range/2000.0 in the RMesh code*/ + float range = 0.f; - std::uint32_t innerConeAngle = 0; - std::uint32_t outerConeAngle = 0; + /** Space delimited color string. Color is 3 ints, and multiplied by intensity when reading. */ + std::string color; - void Read(BufferStream& stream, std::string _className) override; -}; + /** SCP:CB calculates this as Min(intensity*0.8,1)*/ + float intensity = 0.f; -struct EntitySoundEmitter : public Entity -{ - void Read(BufferStream& stream, std::string _className) override; + void Read(BufferStream& stream, std::string _className) override; + }; - // https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/MapSystem.bb#L181 - std::uint32_t sound = 0; - float range = 0.f; -}; + struct EntitySpotLight : public EntityLight + { + std::string angles; -struct EntityPlayerStart : public Entity -{ - std::string angles; + std::uint32_t innerConeAngle = 0; + std::uint32_t outerConeAngle = 0; - void Read(BufferStream& stream, std::string _className) override; -}; + void Read(BufferStream& stream, std::string _className) override; + }; -struct EntityModel : public Entity -{ - std::string path; - - void Read(BufferStream& stream, std::string _className) override; -}; - -/** -* @class RMesh -* RMesh is the main room mesh format in SCP: Containment Breach -* -* @todo Maybe move Read to the constructor instead -*/ -struct RMesh -{ - Header header; + struct EntitySoundEmitter : public Entity + { + void Read(BufferStream& stream, std::string _className) override; + + // https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/MapSystem.bb#L181 + std::uint32_t sound = 0; + float range = 0.f; + }; - Mesh drawnMesh; - Mesh collisionMesh; + struct EntityPlayerStart : public Entity + { + std::string angles; - std::vector triggerBoxes; + void Read(BufferStream& stream, std::string _className) override; + }; - std::vector screenEntities; - std::vector waypointEntities; - std::vector lightEntities; - std::vector spotlightEntities; - std::vector soundEmitterEntities; - std::vector playerStartEntities; - std::vector modelEntities; + struct EntityModel : public Entity + { + std::string path; + + void Read(BufferStream& stream, std::string _className) override; + }; /** - * Reads the specified RMesh file - * - * @param path The file path you wish to open - * - * @returns Whether the RMesh file was read correctly. + * @class RMesh + * RMesh is the main room mesh format in SCP: Containment Breach + * + * @todo Maybe move Read to the constructor instead */ - bool Read(const std::string& path); - - static Mesh ReadDrawnMesh(BufferStream& stream); - static Mesh ReadCollisionMesh(BufferStream& stream); -}; \ No newline at end of file + struct RMesh + { + Header header; + + Mesh drawnMesh; + Mesh collisionMesh; + + std::vector triggerBoxes; + + std::vector screenEntities; + std::vector waypointEntities; + std::vector lightEntities; + std::vector spotlightEntities; + std::vector soundEmitterEntities; + std::vector playerStartEntities; + std::vector modelEntities; + + /** + * Reads the specified RMesh file + * + * @param path The file path you wish to open + * + * @returns Whether the RMesh file was read correctly. + */ + bool Read(const std::string& path); + + static Mesh ReadDrawnMesh(BufferStream& stream); + static Mesh ReadCollisionMesh(BufferStream& stream); + }; + +} \ No newline at end of file diff --git a/src/rmesh.cpp b/src/rmesh.cpp index e51aa4c..47a287e 100644 --- a/src/rmesh.cpp +++ b/src/rmesh.cpp @@ -6,6 +6,8 @@ #include #include +using namespace rmesh; + bool RMesh::Read(const std::string& path) { std::ifstream file(path, std::ios::binary | std::ios::ate); diff --git a/test/test_rmesh.cpp b/test/test_rmesh.cpp index 0b6ff17..bd978a7 100644 --- a/test/test_rmesh.cpp +++ b/test/test_rmesh.cpp @@ -8,7 +8,7 @@ TEST(RMesh, read_triggerboxes) { std::string path = RESOURCES_ROOT_PATH "/173_opt.rmesh"; - RMesh rmesh; + rmesh::RMesh rmesh; // Check if the RMesh file loaded EXPECT_TRUE(rmesh.Read(path));