You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
6.2 KiB
245 lines
6.2 KiB
|
|
#include <string> |
|
|
|
#include <glm/glm.hpp> |
|
#include <rapidjson/document.h> |
|
#include <rapidjson/schema.h> |
|
#include <rapidjson/stringbuffer.h> |
|
#include <rapidjson/error/en.h> |
|
#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; |
|
}
|
|
|