#ifndef _JSON_H #define _JSON_H #define JSON_NO_IO #include #include "gl.h" using json = nlohmann::json; #define json_str_vec4(s, v) sscanf(s, "%f %f %f %f", &(v)[0], &(v)[1], &(v)[2], &(v)[3]) #define json_str_vec3(s, v) sscanf(s, "%f %f %f", &(v)[0], &(v)[1], &(v)[2]) #define json_str_vec2(s, v) sscanf(s, "%f %f", &(v)[0], &(v)[1]) #define parse_fail(obj) do { \ delete obj; \ return nullptr; \ } while (0) namespace Mauri { enum JsonValueType { INT = 0, FLOAT, VEC2, VEC3, VEC4, BOOL, STRING }; struct JsonValue { void *v; JsonValueType type; std::string name; }; class Parser { public: Parser() = default; ~Parser() = default; template static auto parse_value(const json &root, const std::string &name, void *out, const T &default_value) -> void { *((T *)out) = default_value; const json &value = (!name.empty() && root.contains(name)) ? root[name] : root; if constexpr (std::is_same::value) { if (value.is_number()) *((u32 *)out) = value.get(); } else if constexpr (std::is_same::value) { if (value.is_number()) *((s32 *)out) = value.get(); } else if constexpr (std::is_same::value) { if (value.is_number()) *((f32 *)out) = value.get(); } else if constexpr (std::is_same::value) { if (value.is_string()) *((std::string *)out) = value.get(); } else if constexpr (std::is_same::value) { if (value.is_string()) json_str_vec2(value.get().c_str(), *((vec2 *)out)); } else if constexpr (std::is_same::value) { if (value.is_string()) json_str_vec3(value.get().c_str(), *((vec3 *)out)); } else if constexpr (std::is_same::value) { // Some uniforms are saved as a single number. if (value.is_number()) (*((vec4 *)out))[0] = value.get(); else if (value.is_string()) json_str_vec4(value.get().c_str(), *((vec4 *)out)); } else if constexpr (std::is_same::value) { if (value.is_boolean()) *((bool *)out) = value.get(); } } template auto map_value(const json &root, const std::string &name, void *out, const T &default_value) -> void { const json &value = (!name.empty() && root.contains(name)) ? root[name] : root; std::string user = "root"; if (value.is_object()) { if (value.contains("user")) { const json &user_value = value["user"]; if (user_value.is_string()) user = user_value; } this->parse_value(value, "value", out, default_value); } else { this->parse_value(root, name, out, default_value); } JsonValueType type; if constexpr (std::is_same::value) type = INT; else if constexpr (std::is_same::value) type = INT; else if constexpr (std::is_same::value) type = FLOAT; else if constexpr (std::is_same::value) type = STRING; else if constexpr (std::is_same::value) type = VEC2; else if constexpr (std::is_same::value) type = VEC3; else if constexpr (std::is_same::value) type = VEC4; else if constexpr (std::is_same::value) type = BOOL; this->values[user].emplace_back(JsonValue{out, type, name}); } std::unordered_map> values; }; } // namespace Mauri #endif // _JSON_H