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

#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;
}