diff --git a/data/scene_schema.json b/data/scene_schema.json new file mode 100644 index 0000000..83c44b5 --- /dev/null +++ b/data/scene_schema.json @@ -0,0 +1,76 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + + "definitions": { + "vector3": { + "type": "object", + "properties": { + "x": { "type": "number" }, + "y": { "type": "number" }, + "z": { "type": "number" } + }, + "required": ["x", "y", "z"] + }, + + "rgb": { + "type": "object", + "properties": { + "r": { "type": "number" }, + "g": { "type": "number" }, + "b": { "type": "number" } + }, + "required": ["r", "g", "b"] + }, + + "vector4": { + "type": "object", + "properties": { + "x": { "type": "number" }, + "y": { "type": "number" }, + "z": { "type": "number" }, + "w": { "type": "number" } + }, + "required": ["x", "y", "z", "w"] + } + }, + + "type": "object", + "properties": { + "camera": { + "type": "object", + "properties": { + "position" : { "$ref": "#/definitions/vector3" }, + "rotation" : { "$ref": "#/definitions/vector4" } + } + }, + + "hex_grid" : { + "type": "object", + "properties": { + "layout_type" : { "type": "string" }, + "hex_size" : { "type": "number" }, + "hex_radius" : { "type": "number" } + } + }, + + "entities": { + "type": "array", + "items": { + "name": { "type": "string" }, + "model_file": { "type": "string" }, + "position": { "$ref": "#/definitions/vector3" }, + "rotation": { "$ref": "#/definitions/vector4" }, + "scale": { "$ref": "#/definitions/vector3" } + } + }, + + "lights": { + "type": "array", + "items": { + "intensity": { "type": "number" }, + "color": { "type": "#/definitions/rgb" }, + "position": { "$ref": "#/definitions/vector3" } + } + } + } +} diff --git a/data/test_scene.json b/data/test_scene.json index 555f9e5..f414ccc 100644 --- a/data/test_scene.json +++ b/data/test_scene.json @@ -25,16 +25,20 @@ "name" : "catepillar 1", "model_file" : "catepillar.dae", "position" : { - "x" : 0, - "y" : 0, + "x" : 640, + "y" : 500, "z" : 0 }, - "rotation" : { "x" : 0, "y" : 0, "z" : 0, "w" : 0 + }, + "scale" : { + "x" : 10, + "y" : 10, + "z" : 10 } } ], diff --git a/src/hexgame.cpp b/src/hexgame.cpp index b505d0a..dd12197 100644 --- a/src/hexgame.cpp +++ b/src/hexgame.cpp @@ -1,28 +1,29 @@ -//----------------------------------------------------------------------------- -// TODO: -// - add a color buffer to hex_line and debug render groups to re-use -// fragment shaders and simplify draw rgDraw() -// - need to add normal buffer too -// - lighting -// - add light struct -// - pass all lights to render groups/shaders every frame -// - map generation -// - pathfinding -// - assimp animation -// - replace aixlog with custom logging iostream? -// - fix vector normalization in renderer.cpp when moving in 2 directions -// - may be fixed?? need to test by examining camera position between frames -// and compare the distance -// - add prefix to interface function names for eg) gooey.h, renderer.h -// - move hex logic to new file to leave only init glue in a main.cpp -// - move SDL input callbacks somewhere too? -// - think about combining mesh data and render_group data to save some memory -// - actually don't need to save the vertex/normal buffers after passing -// to opengl -// - replace calls to malloc/free with safe(r) function in util.h -// - add cpu perforcmace counters in render loop -// - check for memory leaks w/ valgrind -//----------------------------------------------------------------------------- +/******************************************************************************* + * TODO: + * - add a color buffer to hex_line and debug render groups to re-use + * fragment shaders and simplify draw rgDraw() + * - need to add normal buffer too + * - lighting + * - add light struct + * - pass all lights to render groups/shaders every frame + * - map generation + * - pathfinding + * - assimp animation + * - replace aixlog with custom logging iostream? + * - fix vector normalization in renderer.cpp when moving in 2 directions + * - may be fixed?? need to test by examining camera position between frames + * and compare the distance + * - add prefix to interface function names for eg) gooey.h, renderer.h + * - move hex logic to new file to leave only init glue in a main.cpp + * - move SDL input callbacks somewhere too? + * - think about combining mesh data and render_group data to save some memory + * - actually don't need to save the vertex/normal buffers after passing + * to opengl + * - use a storage pool for assimp meshes allowing reuse across entities + * - replace calls to malloc/free with safe(r) function in util.h + * - add cpu perforcmace counters in render loop + * - check for memory leaks w/ valgrind + ******************************************************************************/ // Some defaults for the game layout #define HEX_SIZE 10 @@ -36,8 +37,10 @@ #define CONE_ANGLE 30 #define VSYNC_ENABLED true -//testing -#define DEFAULT_SCENE_FILE "../data/test_scene.json" +// TODO: testing scene_loader +#define DATA_DIR "../data" +#define DEFAULT_SCENE_FILE "test_scene.json" +#define SCENE_SCHEMA_FILE "scene_schema.json" #include @@ -506,6 +509,9 @@ int main(int argc, char* argv[]) g_game_state->start_hex = 0x0; g_game_state->current_hex = 0x0; g_game_state->draw_mode = CONE_FILL; + // TODO: better entity memory management + // TODO: hard coded limit of 1000 entities here + g_game_state->entities = UTIL_ALLOC(1000, Entity); // init global render state g_render_state = new render_state(); @@ -548,42 +554,7 @@ int main(int argc, char* argv[]) } } - // TODO: better entity memory management - if (meInitAssimp()) { - // TODO: hard coded limit of 1000 entities here - game_state* g = g_game_state; - g->entities = (Entity*) std::calloc(1000, sizeof(Entity)); - -#if 0 - meMeshGroup mg1, mg2; - - // TODO: store these meMeshGroups serperately from entities to re-use them, - // and to make initializing easier, eg) appling translation has to happen after - // rgInitEntity() called from renderer createScene() - if (meLoadFromFile("../data/animated.block.dae", mg1)) { - Entity& e = g->entities[0]; - e.mesh_group = mg1; - e.scale = glm::vec3(100,100,100); - g->entity_count++; - } - else { - LOG(ERROR) << "Error loading file, exiting\n"; - return 1; - } - - if (meLoadFromFile("../data/catepillar.dae", mg2)) { - Entity& e = g->entities[1]; - e.mesh_group = mg2; - e.scale = glm::vec3(10,10,10); - e.translation = glm::vec3(640, 500, 0); - g->entity_count++; - } - else { - LOG(ERROR) << "Error loading file, exiting\n"; - return 1; - } -#endif - } else { + if (!meInitAssimp()) { LOG(ERROR) << "Error initializing assimp\n"; return 1; } @@ -591,10 +562,12 @@ int main(int argc, char* argv[]) // testing scene_loader - if (slLoadFile(DEFAULT_SCENE_FILE, g_game_state->entities, g_game_state->entity_count, 1000)) { + if (slLoadFile(DATA_DIR, DEFAULT_SCENE_FILE, SCENE_SCHEMA_FILE, + g_game_state->entities, g_game_state->entity_count, 1000)) + { // ??? } else { - LOG(ERROR) << "Error reading scene file, exiting\n"; + LOG(ERROR) << "Error loading scene, exiting\n"; return 1; } diff --git a/src/hexgame.h b/src/hexgame.h index 6f3e3bd..629af42 100644 --- a/src/hexgame.h +++ b/src/hexgame.h @@ -3,7 +3,7 @@ #include -#if defined (_WIN32) +#if defined (_WIN32) #include #else #include diff --git a/src/mesh.cpp b/src/mesh.cpp index 172826d..816f568 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -23,8 +23,8 @@ meInitAssimp() { LOG(INFO) << "Initializing Assimp\n"; /* get a handle to the predefined STDOUT log stream and attach - * it to the logging system. It remains active for all further - * calls to aiImportFile(Ex) and aiApplyPostProcessing. */ + * it to the logging system. It remains active for all further + * calls to aiImportFile(Ex) and aiApplyPostProcessing. */ aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); aiAttachLogStream(&stream); @@ -43,7 +43,7 @@ meLoadFromFile(const char* filename, meMeshGroup& mesh_group) } mesh_group.num_meshes = scene->mNumMeshes; - mesh_group.meshes = (meMeshInfo**) std::calloc(mesh_group.num_meshes, sizeof(meMeshInfo*)); + mesh_group.meshes = (meMeshInfo**) std::calloc(mesh_group.num_meshes, sizeof(meMeshInfo*)); mesh_group.use_normals = scene->mMeshes[0]->HasNormals(); for (uint i = 0; i < scene->mNumMeshes; i++) { diff --git a/src/scene_loader.cpp b/src/scene_loader.cpp index 6233d2b..136f78b 100644 --- a/src/scene_loader.cpp +++ b/src/scene_loader.cpp @@ -1,9 +1,10 @@ -#include -#include "rapidjson/document.h" -#include "rapidjson/writer.h" -#include "rapidjson/stringbuffer.h" +#include +#include +#include +#include +#include #include "aixlog.hpp" #include "entity.h" @@ -11,42 +12,118 @@ #include "util.h" #include "scene_loader.h" + +// forward declarations +bool parseFile(rapidjson::Document& doc, const char* data_dir, const char* file_name); +bool validateScene(rapidjson::Document& schema_doc, rapidjson::Document& scene_doc, + const char* scene_file); + + +// interface + bool -slLoadFile(const char* file_name, Entity* entity_array, uint& entity_count, uint max_entities) +slLoadFile( + const char* data_dir, + const char* scene_file, + const char* schema_file, + Entity* entity_array, + uint& entity_count, + uint max_entities) { if (entity_array == nullptr) { LOG(ERROR) << "entity array not initialized\n"; return false; } - rapidjson::Document doc; - char* contents = utilDumpTextFile(file_name); + LOG(INFO) << "Loading scene file: " << scene_file << "\n"; + rapidjson::Document doc, schema_doc; + bool retDoc = parseFile(doc, data_dir, scene_file); + bool retSchema = parseFile(schema_doc, data_dir, schema_file); + + if (!retDoc || !retSchema || !validateScene(schema_doc, doc, scene_file)) + return false; + + // camera + const rapidjson::Value& cam = doc["camera"]; + + + // hex grid + + // entities + const rapidjson::Value& e = doc["entities"]; + if (e.Size() > max_entities) { + LOG(ERROR) << "entity count: " << e.Size() << ", was more than max_entities: " + << max_entities << "\n"; + return false; + } + + for (uint i = 0; i < e.Size(); i++) { + meMeshGroup mg; + std::string model_path; + model_path.append(data_dir).append("/").append(e[i]["model_file"].GetString()); + + if (meLoadFromFile(model_path.c_str(), mg)) { + Entity& e = entity_array[entity_count]; + e.mesh_group = mg; + // + e.scale = glm::vec3(10,10,10); + e.translation = glm::vec3(640, 500, 0); + // + } else { + LOG(ERROR) << "Error loading mesh file\n"; + return false; + } + + entity_count++; + } + + // lights + + return true; +} + +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"; - return false; + ret = false; } if (doc.Parse(contents).HasParseError() || !doc.IsObject()) { LOG(ERROR) << "Error parrsing scene file: " << file_name << "\n"; - return false; + ret = false; } - // entities + utilSafeFree(contents); - if (doc.HasMember("entities")) { - const rapidjson::Value& e = doc["entities"]; - assert (e.IsArray()); + return ret; +} - for (uint i = 0; i < e.Size(); i++) { - assert(e[i].HasMember("name")); - assert(e[i]["name"].IsString()); - assert(i < max_entities); +bool +validateScene(rapidjson::Document& schema_doc, rapidjson::Document& scene_doc, const char* scene_file) +{ + rapidjson::SchemaDocument schema(schema_doc); + rapidjson::SchemaValidator validator(schema); - std::string s = e[i]["name"].GetString(); - LOG(INFO) << "e[" << i << "][\"name\"]: " << s << "\n"; - } + 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; } diff --git a/src/scene_loader.h b/src/scene_loader.h index d054bc0..e4148a9 100644 --- a/src/scene_loader.h +++ b/src/scene_loader.h @@ -4,4 +4,10 @@ /* * @param max_entities maximum size of array allocated */ -bool slLoadFile(const char* file_name, Entity* entity_array, uint& entity_count, uint max_entities); +bool slLoadFile( + const char* data_dir, + const char* scene_file, + const char* schema_file, + Entity* entity_array, + uint& entity_count, + uint max_entities);