#include #include #include #include #include #include #include "aixlog.hpp" #include "entity.h" #include "hexgrid.h" #include "hexlib.h" #include "mesh.h" #include "util.h" #include "scene_loader.h" struct slSceneDoc { rapidjson::Document* doc; }; // forward declarations bool parseFile(rapidjson::Document* doc, const char* data_dir, const char* file_name); glm::vec3 parseVec3(const rapidjson::Value& node); glm::vec4 parseVec4(const rapidjson::Value& node); uint32 parseHex32(std::string s); bool validateScene(rapidjson::Document* schema_doc, rapidjson::Document* scene_doc, const char* scene_file); // interface slSceneDoc* slLoadFile(const char* data_dir, const char* scene_file, const char* schema_file) { LOG(INFO) << "Loading scene file: " << scene_file << "\n"; rapidjson::Document schema_doc; slSceneDoc* sd = UTIL_ALLOC(1, slSceneDoc); sd->doc = new rapidjson::Document(); bool retDoc = parseFile(sd->doc, data_dir, scene_file); bool retSchema = parseFile(&schema_doc, data_dir, schema_file); if (!retDoc || !retSchema || !validateScene(&schema_doc, sd->doc, scene_file)) { slFreeSceneDoc(sd); return nullptr; } return sd; } void slFreeSceneDoc(slSceneDoc* sd) { if (sd->doc != nullptr) { delete sd->doc; sd->doc = nullptr; } utilSafeFree(sd); } bool slParseEntities( slSceneDoc* sd, Entity* entity_array, uint& entity_count, uint max_entities, const char* data_dir) { const rapidjson::Value& entities = (*sd->doc)["entities"]; if (entities.Size() > max_entities) { LOG(ERROR) << "entity count: " << entities.Size() << ", was more than max_entities: " << max_entities << "\n"; return false; } for (uint i = 0; i < entities.Size(); i++) { meMeshGroup mg; std::string model_path; model_path.append(data_dir).append("/").append(entities[i]["model_file"].GetString()); if (meLoadFromFile(data_dir, model_path.c_str(), mg)) { Entity& e = entity_array[i]; e.mesh_group = mg; e.scale = parseVec3(entities[i]["scale"]); e.translation = parseVec3(entities[i]["position"]); } else { LOG(ERROR) << "Error loading mesh file\n"; meFreeMeshGroup(mg); return false; } entity_count++; } return true; } void slParseCamera(slSceneDoc* sd, camera& cam) { const rapidjson::Value& json_cam = (*sd->doc)["camera"]; cameraInitPerspective(cam, parseVec3(json_cam["position"]), parseVec3(json_cam["target"]), parseVec3(json_cam["world_up"]) ); } void slParseHexGrid(slSceneDoc* sd, hexgrid& hg) { const rapidjson::Value& json_grid = (*sd->doc)["hex_grid"]; std::string grid_type_str = json_grid["grid_type"].GetString(); if (grid_type_str == "hexagon") hg.gridT = HEXAGON; else if (grid_type_str == "parallelogram") hg.gridT = PARALLELOGRAM; else if (grid_type_str == "rhombus") hg.gridT = RHOMBUS; else if (grid_type_str == "hash_map") hg.gridT = HASH_MAP; hg.hex_size = json_grid["hex_size"].GetInt(); glm::vec3 pos = parseVec3(json_grid["position"]); hg.position.x = pos.x; hg.position.y = pos.y; hg.position.z = pos.z; std::string fill_color_str = json_grid["fill_color"].GetString(); hg.fill_color = std::stoul(fill_color_str, nullptr, 16); std::string selected_fill_color_str = json_grid["selected_fill_color"].GetString(); hg.selected_fill_color = std::stoul(selected_fill_color_str, nullptr, 16); std::string hex_line_color_str = json_grid["hex_line_color"].GetString(); hg.hex_line_color = std::stoul(hex_line_color_str, nullptr, 16); std::string orientation_str = json_grid["hexlib_orientation"].GetString(); hg.hexlib_orientation = (orientation_str == "layout_flat") ? layout_flat : layout_pointy; Layout lo(hg.hexlib_orientation, Point(hg.hex_size, hg.hex_size), Point(hg.position.x, hg.position.y)); hg.hexlib_layout = lo; if (hg.gridT == HEXAGON) { hg.hex_radius = json_grid["hex_radius"].GetInt(); } hgCreateHexes(hg); } bool slParseLights(slSceneDoc* sd, rg_point_light* lights, uint& num_lights, uint max_lights) { const rapidjson::Value& json_lights = (*sd->doc)["lights"]; if (json_lights.Size() > max_lights) { LOG(ERROR) << "Too many lights\n"; return false; } num_lights = json_lights.Size(); for (uint i = 0; i < num_lights; i++) { lights[i].position = parseVec3(json_lights[i]["position"]); } return true; } // internal bool parseFile(rapidjson::Document* doc, const char* data_dir, const char* file_name) { bool ret = true; std::string file_path; file_path.append(data_dir).append("/").append(file_name); char* contents = utilDumpTextFile(file_path.c_str()); if (contents == nullptr) { LOG(ERROR) << "Error reading file: " << file_name << "\n"; ret = false; } rapidjson::ParseResult pr = doc->Parse(contents/*, rapidjson::kParseStopWhenDoneFlag*/); if (!pr || !doc->IsObject()) { LOG(ERROR) << "Error parrsing scene file: " << file_name << "\n"; LOG(ERROR) << "Error desscription: " << rapidjson::GetParseError_En(pr.Code()) << " (" << pr.Offset() << ")\n"; ret = false; } utilSafeFree(contents); return ret; } bool validateScene(rapidjson::Document* schema_doc, rapidjson::Document* scene_doc, const char* scene_file) { rapidjson::SchemaDocument schema(*schema_doc); rapidjson::SchemaValidator validator(schema); if (!scene_doc->Accept(validator)) { LOG(ERROR) << "Error validating scene file: " << scene_file << "\n"; rapidjson::StringBuffer sb; validator.GetInvalidSchemaPointer().StringifyUriFragment(sb); LOG(ERROR) << "Invalid schema: " << sb.GetString() << "\n"; LOG(ERROR) << "Invalid keyword:" << validator.GetInvalidSchemaKeyword() << "\n"; sb.Clear(); validator.GetInvalidDocumentPointer().StringifyUriFragment(sb); LOG(ERROR) << "Invalid Document: " << sb.GetString() << "\n"; return false; } LOG(INFO) << "scene file: " << scene_file << " passed schema validation\n"; return true; } glm::vec3 parseVec3(const rapidjson::Value& node) { glm::vec3 v3; v3.x = node["x"].GetFloat(); v3.y = node["y"].GetFloat(); v3.z = node["z"].GetFloat(); return v3; } glm::vec4 parseVec4(const rapidjson::Value& node) { glm::vec4 v4; v4.x = node["x"].GetFloat(); v4.y = node["y"].GetFloat(); v4.z = node["z"].GetFloat(); v4.w = node["w"].GetFloat(); return v4; }