10#include "hellfire/utilities/SerializerUtils.h"
14 std::ofstream file(filepath, std::ios::binary);
16 std::cerr <<
"MaterialSerializer: Cannot open file for writing: " << filepath << std::endl;
24 write_binary_string(file, mat.name);
27 write_binary(file, mat.diffuse_color);
28 write_binary(file, mat.ambient_color);
29 write_binary(file, mat.specular_color);
30 write_binary(file, mat.emissive_color);
39 write_binary(file, mat.uv_scale);
40 write_binary(file, mat.uv_offset);
48 const uint32_t texture_count =
static_cast<uint32_t>(mat.texture_assets.size());
49 write_binary(file, texture_count);
51 for (
const auto &[type, asset_id]: mat.texture_assets) {
52 write_binary(file,
static_cast<uint32_t>(type));
53 write_binary(file, asset_id);
60 std::ifstream file(filepath, std::ios::binary);
62 std::cerr <<
"MaterialSerializer: Cannot open file: " << filepath << std::endl;
68 if (!read_and_validate_header(file,
MAGIC,
VERSION, version)) {
69 std::cerr <<
"MaterialSerializer: Invalid file header: " << filepath << std::endl;
76 if (!read_binary_string(file, mat.name))
return std::nullopt;
79 if (!read_binary(file, mat.diffuse_color))
return std::nullopt;
80 if (!read_binary(file, mat.ambient_color))
return std::nullopt;
81 if (!read_binary(file, mat.specular_color))
return std::nullopt;
82 if (!read_binary(file, mat.emissive_color))
return std::nullopt;
85 if (!read_binary(file, mat
.opacity))
return std::nullopt;
86 if (!read_binary(file, mat
.shininess))
return std::nullopt;
87 if (!read_binary(file, mat
.metallic))
return std::nullopt;
88 if (!read_binary(file, mat
.roughness))
return std::nullopt;
91 if (!read_binary(file, mat.uv_scale))
return std::nullopt;
92 if (!read_binary(file, mat.uv_offset))
return std::nullopt;
95 if (!read_binary(file, mat
.double_sided))
return std::nullopt;
96 if (!read_binary(file, mat
.alpha_blend))
return std::nullopt;
97 if (!read_binary(file, mat
.alpha_cutoff))
return std::nullopt;
100 uint32_t texture_count;
101 if (!read_binary(file, texture_count))
return std::nullopt;
103 for (uint32_t i = 0; i < texture_count; i++) {
107 if (!read_binary(file, type_raw))
return std::nullopt;
108 if (!read_binary(file, asset_id))
return std::nullopt;
110 mat.texture_assets[
static_cast<
TextureType>(type_raw)] = asset_id;
113 std::cout <<
"Loaded material from: " << filepath << std::endl;
114 for (
const auto& [type, asset_id] : mat.texture_assets) {
115 std::cout <<
" " <<
static_cast<
int>(type) <<
" -> " << asset_id << std::endl;
131 default:
return "unknown";
150 j[
"name"] = mat.name;
153 {
"diffuse", vec3_to_json(mat.diffuse_color)},
154 {
"ambient", vec3_to_json(mat.ambient_color)},
155 {
"specular", vec3_to_json(mat.specular_color)},
156 {
"emissive", vec3_to_json(mat.emissive_color)}
167 {
"scale", vec2_to_json(mat.uv_scale)},
168 {
"offset", vec2_to_json(mat.uv_offset)}
178 nlohmann::json textures = nlohmann::json::object();
179 for (
const auto &[type, asset_id]: mat.texture_assets) {
180 textures[texture_type_to_string(type)] = asset_id;
182 j[
"textures"] = textures;
184 std::ofstream file(filepath);
185 if (!file)
return false;
192 std::ifstream file(filepath);
193 if (!file)
return std::nullopt;
201 mat.name = j.value(
"name",
"Material");
204 if (j.contains(
"colors")) {
205 const auto &colors = j[
"colors"];
206 if (
auto v = json_get_vec3(colors,
"diffuse")) mat.diffuse_color = *v;
207 if (
auto v = json_get_vec3(colors,
"ambient")) mat.ambient_color = *v;
208 if (
auto v = json_get_vec3(colors,
"specular")) mat.specular_color = *v;
209 if (
auto v = json_get_vec3(colors,
"emissive")) mat.emissive_color = *v;
213 if (j.contains(
"properties")) {
214 const auto &props = j[
"properties"];
215 mat
.opacity = props.value(
"opacity", 1.0f);
216 mat
.shininess = props.value(
"shininess", 32.0f);
217 mat
.metallic = props.value(
"metallic", 0.0f);
218 mat
.roughness = props.value(
"roughness", 0.5f);
222 if (j.contains(
"uv")) {
223 const auto &uv = j[
"uv"];
224 if (
auto v = json_get_vec2(uv,
"scale")) mat.uv_scale = *v;
225 if (
auto v = json_get_vec2(uv,
"offset")) mat.uv_offset = *v;
229 if (j.contains(
"flags")) {
230 const auto &flags = j[
"flags"];
237 if (j.contains(
"textures") && j[
"textures"].is_object()) {
238 for (
const auto &[key, value]: j[
"textures"].items()) {
239 TextureType type = string_to_texture_type(key);
240 AssetID asset_id = value.get<AssetID>();
241 mat.texture_assets[type] = asset_id;
246 }
catch (
const std::exception &e) {
247 std::cerr <<
"MaterialSerializer: JSON parse error: " << e.what() << std::endl;
static constexpr uint32_t VERSION
static constexpr uint32_t MAGIC
static bool save(const std::filesystem::path &filepath, const MaterialData &material)
static bool save_json(const std::filesystem::path &filepath, const MaterialData &material)
static const char * texture_type_to_string(TextureType type)
static TextureType string_to_texture_type(const std::string &str)
Serializable material data (separate from runtime Material class)