Loading...
Searching...
No Matches
SerializerUtils.h
Go to the documentation of this file.
1//
2// Created by denzel on 08/12/2025.
3//
4
5#pragma once
6#include <optional>
7
8#include "glm/glm.hpp"
9#include "glm/gtc/quaternion.hpp"
10#include "hellfire/graphics/Vertex.h"
11#include "nlohmann/json.hpp"
12
13namespace hellfire {
14 /// Binary I/O
15 template<typename T>
16 void write_binary(std::ostream &out, const T &val) {
17 static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
18 out.write(reinterpret_cast<const char *>(&val), sizeof(T));
19 }
20
21 template<typename T>
22 bool read_binary(std::istream &in, T &val) {
23 static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
24 in.read(reinterpret_cast<char *>(&val), sizeof(T));
25 return in.good();
26 }
27
28 template<typename T>
29 void write_binary_vector(std::ostream &out, const std::vector<T> &vec) {
30 static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
31 const uint32_t size = static_cast<uint32_t>(vec.size());
32 write_binary(out, size);
33 if (size > 0) {
34 out.write(reinterpret_cast<const char *>(vec.data()), size * sizeof(T));
35 }
36 }
37
38 template<typename T>
39 bool read_binary_vector(std::istream &in, std::vector<T> &vec) {
40 static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
41 uint32_t size;
42 if (!read_binary(in, size)) return false;
43 vec.resize(size);
44 if (size > 0) {
45 in.read(reinterpret_cast<char *>(vec.data()), size * sizeof(T));
46 }
47 return in.good();
48 }
49
50 inline void write_binary_string(std::ostream &out, const std::string &str) {
51 const uint32_t length = static_cast<uint32_t>(str.size());
52 write_binary(out, length);
53 if (length > 0) {
54 out.write(str.data(), length);
55 }
56 }
57
58 inline bool read_binary_string(std::istream &in, std::string &str) {
59 uint32_t length;
60 if (!read_binary(in, length)) return false;
61 str.resize(length);
62 if (length > 0) {
63 in.read(str.data(), length);
64 }
65 return in.good();
66 }
67
68
69
70 /// GLM Binary I/O
71 inline void write_binary(std::ostream &out, const glm::vec2 &v) {
72 out.write(reinterpret_cast<const char *>(&v.x), sizeof(float) * 2);
73 }
74
75 inline void write_binary(std::ostream &out, const glm::vec3 &v) {
76 out.write(reinterpret_cast<const char *>(&v.x), sizeof(float) * 3);
77 }
78
79 inline void write_binary(std::ostream &out, const glm::vec4 &v) {
80 out.write(reinterpret_cast<const char *>(&v.x), sizeof(float) * 4);
81 }
82
83 inline void write_binary(std::ostream &out, const glm::quat &q) {
84 out.write(reinterpret_cast<const char *>(&q.x), sizeof(float) * 4);
85 }
86
87 inline void write_binary(std::ostream &out, const glm::mat4 &m) {
88 out.write(reinterpret_cast<const char *>(&m[0][0]), sizeof(float) * 16);
89 }
90
91 inline void write_binary(std::ostream &out, const glm::mat3 &m) {
92 out.write(reinterpret_cast<const char *>(&m[0][0]), sizeof(float) * 9);
93 }
94
95 inline bool read_binary(std::istream &in, glm::vec2 &v) {
96 in.read(reinterpret_cast<char *>(&v.x), sizeof(float) * 2);
97 return in.good();
98 }
99
100 inline bool read_binary(std::istream &in, glm::vec3 &v) {
101 in.read(reinterpret_cast<char *>(&v.x), sizeof(float) * 3);
102 return in.good();
103 }
104
105 inline bool read_binary(std::istream &in, glm::vec4 &v) {
106 in.read(reinterpret_cast<char *>(&v.x), sizeof(float) * 4);
107 return in.good();
108 }
109
110 inline bool read_binary(std::istream &in, glm::quat &q) {
111 in.read(reinterpret_cast<char *>(&q.x), sizeof(float) * 4);
112 return in.good();
113 }
114
115 inline bool read_binary(std::istream &in, glm::mat4 &m) {
116 in.read(reinterpret_cast<char *>(&m[0][0]), sizeof(float) * 16);
117 return in.good();
118 }
119
120 inline bool read_binary(std::istream &in, glm::mat3 &m) {
121 in.read(reinterpret_cast<char *>(&m[0][0]), sizeof(float) * 9);
122 return in.good();
123 }
124
125 /// Vertex I/O
126 inline void write_binary(std::ostream& out, const Vertex& v) {
127 write_binary(out, v.position);
128 write_binary(out, v.normal);
129 write_binary(out, v.texCoords);
130 write_binary(out, v.color);
131 write_binary(out, v.tangent);
132 write_binary(out, v.bitangent);
133 }
134
135 inline bool read_binary(std::istream& in, Vertex& v) {
136 if (!read_binary(in, v.position)) return false;
137 if (!read_binary(in, v.normal)) return false;
138 if (!read_binary(in, v.texCoords)) return false;
139 if (!read_binary(in, v.color)) return false;
140 if (!read_binary(in, v.tangent)) return false;
141 if (!read_binary(in, v.bitangent)) return false;
142 return true;
143 }
144
145 // Vector of vertices (can't use the template version)
146 inline void write_vertex_vector(std::ostream& out, const std::vector<Vertex>& vec) {
147 const uint32_t size = static_cast<uint32_t>(vec.size());
148 write_binary(out, size);
149 for (const auto& v : vec) {
150 write_binary(out, v);
151 }
152 }
153
154 inline bool read_vertex_vector(std::istream& in, std::vector<Vertex>& vec) {
155 uint32_t size;
156 if (!read_binary(in, size)) return false;
157 vec.resize(size);
158 for (auto& v : vec) {
159 if (!read_binary(in, v)) return false;
160 }
161 return true;
162 }
163
164 /// JSON Helpers
165 inline std::optional<glm::vec2> json_get_vec2(const nlohmann::json &j, const std::string &key) {
166 if (!j.contains(key) || !j[key].is_array() || j[key].size() < 2) {
167 return std::nullopt;
168 }
169 return glm::vec2(j[key][0].get<float>(), j[key][1].get<float>());
170 }
171
172 inline std::optional<glm::vec3> json_get_vec3(const nlohmann::json &j, const std::string &key) {
173 if (!j.contains(key) || !j[key].is_array() || j[key].size() < 3) {
174 return std::nullopt;
175 }
176 return glm::vec3(
177 j[key][0].get<float>(),
178 j[key][1].get<float>(),
179 j[key][2].get<float>()
180 );
181 }
182
183 inline std::optional<glm::vec3> json_to_vec3(const nlohmann::json &j) {
184 if (!j.is_array() || j.size() != 3) return std::nullopt;
185
186 for (const auto &elem: j) {
187 if (!elem.is_number()) return std::nullopt;
188 }
189
190 return glm::vec3(j[0].get<float>(), j[1].get<float>(), j[2].get<float>());
191 }
192
193 inline std::optional<glm::vec4> json_get_vec4(const nlohmann::json &j, const std::string &key) {
194 if (!j.contains(key) || !j[key].is_array() || j[key].size() < 4) {
195 return std::nullopt;
196 }
197 return glm::vec4(
198 j[key][0].get<float>(),
199 j[key][1].get<float>(),
200 j[key][2].get<float>(),
201 j[key][3].get<float>()
202 );
203 }
204
205 inline nlohmann::json vec2_to_json(const glm::vec2 &v) {
206 return {v.x, v.y};
207 }
208
209 inline nlohmann::json vec3_to_json(const glm::vec3 &v) {
210 return {v.x, v.y, v.z};
211 }
212
213 inline nlohmann::json vec4_to_json(const glm::vec4 &v) {
214 return {v.x, v.y, v.z, v.w};
215 }
216
217
218 /// File Header Validation
219 struct FileHeader {
220 uint32_t magic;
221 uint32_t version;
222 };
223
224 inline bool write_header(std::ostream &out, uint32_t magic, uint32_t version) {
225 write_binary(out, magic);
226 write_binary(out, version);
227 return out.good();
228 }
229
230 inline bool read_and_validate_header(std::istream &in, uint32_t expected_magic, uint32_t max_version,
231 uint32_t &out_version) {
232 uint32_t magic;
233 if (!read_binary(in, magic) || magic != expected_magic) {
234 return false;
235 }
236
237 if (!read_binary(in, out_version) || out_version > max_version) {
238 return false;
239 }
240
241 return true;
242 }
243} // namespace hellfire
244
245namespace glm {
246 /// GLM Helper extensions
247 inline void to_json(nlohmann::json &j, const vec3 &v) {
248 j = {v.x, v.y, v.z};
249 }
250
251 inline void from_json(const nlohmann::json &j, vec3 &v) {
252 v = {j[0].get<float>(), j[1].get<float>(), j[2].get<float>()};
253 }
254} // namespace glm
void import_all_pending()
Import all unprocessed assets in registry.
Registry for storing assets.
void set_intensity(const float intensity)
LightType get_light_type() const
void set_range(const float range)
void set_attenuation(const float attenuation)
void set_cast_shadows(const bool cast_shadows)
void set_light_type(const LightType type)
void set_mesh_asset(AssetID id)
const std::string & get_name() const
Definition Project.h:50
std::unique_ptr< AssetManager > asset_manager_
Definition Project.h:62
const ProjectMetadata & get_metadata() const
Definition Project.h:47
ProjectMetadata & get_metadata()
Definition Project.h:48
std::filesystem::path get_assets_path() const
Definition Project.cpp:136
std::filesystem::path get_settings_path() const
Definition Project.cpp:144
AssetRegistry * get_asset_registry() const
Definition Project.h:54
void cleanup_managers()
Definition Project.cpp:196
std::unique_ptr< SceneManager > scene_manager_
Definition Project.h:60
std::vector< std::filesystem::path > recent_scenes_
Definition Project.h:65
void initialize_default_assets()
Definition Project.cpp:157
static std::unique_ptr< Project > create(const std::string &name, const std::filesystem::path &location)
Definition Project.cpp:37
const std::string & get_version() const
Definition Project.h:51
static std::unique_ptr< Project > load_data(const std::filesystem::path &project_file)
Definition Project.cpp:61
std::unique_ptr< Renderer > scene_renderer_
Definition Project.h:63
std::unique_ptr< AssetRegistry > asset_registry_
Definition Project.h:61
Project(const ProjectMetadata &metadata)
Definition Project.cpp:31
SceneManager * get_scene_manager() const
Definition Project.h:53
ProjectMetadata metadata_
Definition Project.h:56
void create_directory_structure() const
Definition Project.cpp:148
std::filesystem::path project_root_path_
Definition Project.h:57
std::filesystem::path project_file_path_
Definition Project.h:58
Project(const std::string &name)
Definition Project.cpp:21
void initialize_managers()
Definition Project.cpp:161
std::filesystem::path get_scenes_path() const
Definition Project.cpp:140
std::filesystem::path get_project_root() const
Definition Project.cpp:132
static std::string get_current_timestamp()
Definition Project.cpp:204
void set_position(float x, float y, float z)
void set_rotation(float x, float y, float z)
void from_json(const nlohmann::json &j, vec3 &v)
void to_json(nlohmann::json &j, const vec3 &v)
GLM Helper extensions.
bool read_binary_vector(std::istream &in, std::vector< T > &vec)
bool write_header(std::ostream &out, uint32_t magic, uint32_t version)
std::optional< glm::vec4 > json_get_vec4(const nlohmann::json &j, const std::string &key)
bool read_binary_string(std::istream &in, std::string &str)
void write_binary_string(std::ostream &out, const std::string &str)
std::optional< glm::vec2 > json_get_vec2(const nlohmann::json &j, const std::string &key)
JSON Helpers.
bool read_vertex_vector(std::istream &in, std::vector< Vertex > &vec)
bool read_binary(std::istream &in, glm::vec2 &v)
void write_vertex_vector(std::ostream &out, const std::vector< Vertex > &vec)
bool read_binary(std::istream &in, Vertex &v)
nlohmann::json vec3_to_json(const glm::vec3 &v)
void write_binary(std::ostream &out, const glm::vec2 &v)
GLM Binary I/O.
bool read_binary(std::istream &in, T &val)
void write_binary(std::ostream &out, const T &val)
Binary I/O.
bool read_and_validate_header(std::istream &in, uint32_t expected_magic, uint32_t max_version, uint32_t &out_version)
std::optional< glm::vec3 > json_get_vec3(const nlohmann::json &j, const std::string &key)
std::optional< glm::vec3 > json_to_vec3(const nlohmann::json &j)
nlohmann::json vec4_to_json(const glm::vec4 &v)
nlohmann::json vec2_to_json(const glm::vec2 &v)
void write_binary_vector(std::ostream &out, const std::vector< T > &vec)
void write_binary(std::ostream &out, const Vertex &v)
Vertex I/O.
constexpr AssetID INVALID_ASSET_ID
Definition Vertex.h:5
File Header Validation.
std::filesystem::path renderer_settings
Definition Project.h:23
std::optional< AssetID > last_scene
Definition Project.h:21
std::string created_at
Definition Project.h:19
std::string last_opened
Definition Project.h:20
std::string engine_version
Definition Project.h:18
std::filesystem::path default_scene
Definition Project.h:22
static bool serialize(std::ostream &output, const ProjectMetadata *obj)
static bool deserialize(std::istream &input, ProjectMetadata *obj)