From bedc7c635f465c43a0b6234edbc1d65c56af9870 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Sat, 19 Sep 2020 05:13:50 -0700 Subject: [PATCH] Make model loader support new model format --- src/game/bootloader.cpp | 4 +- src/game/systems/painting-system.cpp | 12 +- src/game/systems/tracking-system.cpp | 4 +- src/game/systems/ui-system.cpp | 2 +- src/renderer/vertex-attributes.hpp | 21 ++- src/resources/model-loader.cpp | 189 +++++++++++++++++++++++++-- 6 files changed, 199 insertions(+), 33 deletions(-) diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index 0f277a0..8a42ad3 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -694,7 +694,7 @@ void setup_scenes(game_context* ctx) //ctx->underworld_scene->add_object(ctx->lantern); //ctx->underworld_scene->add_object(ctx->subterrain_light); //ctx->underworld_scene->add_object(ctx->portal_billboard); - //model_instance* larva = new model_instance(ctx->resource_manager->load("larva.obj")); + //model_instance* larva = new model_instance(ctx->resource_manager->load("larva.mdl")); //ctx->underworld_scene->add_object(larva); // Setup UI scene @@ -787,7 +787,7 @@ void setup_systems(game_context* ctx) ctx->vegetation_system->set_terrain_patch_size(TERRAIN_PATCH_SIZE); ctx->vegetation_system->set_vegetation_patch_resolution(VEGETATION_PATCH_RESOLUTION); ctx->vegetation_system->set_vegetation_density(1.0f); - ctx->vegetation_system->set_vegetation_model(ctx->resource_manager->load("grass-tuft.obj")); + ctx->vegetation_system->set_vegetation_model(ctx->resource_manager->load("grass-tuft.mdl")); ctx->vegetation_system->set_scene(ctx->overworld_scene); // Setup camera system diff --git a/src/game/systems/painting-system.cpp b/src/game/systems/painting-system.cpp index e5a4479..cc07ac1 100644 --- a/src/game/systems/painting-system.cpp +++ b/src/game/systems/painting-system.cpp @@ -57,7 +57,7 @@ painting_system::painting_system(entt::registry& registry, ::event_dispatcher* e min_stroke_length_squared = min_stroke_length * min_stroke_length; max_stroke_segments = 4096; current_stroke_segment = 0; - vertex_size = 15; + vertex_size = 13; vertex_stride = sizeof(float) * vertex_size; vertex_count = max_stroke_segments * 6; @@ -72,8 +72,7 @@ painting_system::painting_system(entt::registry& registry, ::event_dispatcher* e stroke_model->get_vertex_array()->bind_attribute(VERTEX_POSITION_LOCATION, *stroke_vbo, 4, vertex_attribute_type::float_32, vertex_stride, 0); stroke_model->get_vertex_array()->bind_attribute(VERTEX_NORMAL_LOCATION, *stroke_vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 4); stroke_model->get_vertex_array()->bind_attribute(VERTEX_TEXCOORD_LOCATION, *stroke_vbo, 2, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 7); - stroke_model->get_vertex_array()->bind_attribute(VERTEX_TANGENT_LOCATION, *stroke_vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 9); - stroke_model->get_vertex_array()->bind_attribute(VERTEX_BITANGENT_LOCATION, *stroke_vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 12); + stroke_model->get_vertex_array()->bind_attribute(VERTEX_TANGENT_LOCATION, *stroke_vbo, 4, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 9); // Create stroke model instance stroke_model_instance = new model_instance(); @@ -214,7 +213,7 @@ void painting_system::update(double t, double dt) bitangents[i * 3 + 2] = bitangent; } - float vertex_data[15 * 12]; + float vertex_data[13 * 12]; float* v = &vertex_data[0]; for (int i = 0; i < 12; ++i) { @@ -233,10 +232,7 @@ void painting_system::update(double t, double dt) *(v++) = tangents[i].x; *(v++) = tangents[i].y; *(v++) = tangents[i].z; - - *(v++) = bitangents[i].x; - *(v++) = bitangents[i].y; - *(v++) = bitangents[i].z; + *(v++) = 0.0f; } std::size_t segment_size = sizeof(float) * vertex_size * 6; diff --git a/src/game/systems/tracking-system.cpp b/src/game/systems/tracking-system.cpp index ce4987b..9c999fc 100644 --- a/src/game/systems/tracking-system.cpp +++ b/src/game/systems/tracking-system.cpp @@ -42,10 +42,10 @@ tracking_system::tracking_system(entt::registry& registry, ::event_dispatcher* e registry.on_destroy().connect<&tracking_system::on_component_destroy>(this); // Load paint ball model - paint_ball_model = resource_manager->load("paint-ball.obj"); + paint_ball_model = resource_manager->load("paint-ball.mdl"); // Load tracker model - tracker_model = resource_manager->load("tracker.obj"); + tracker_model = resource_manager->load("tracker.mdl"); // Load paint ball materials paint_ball_materials = new material*[7]; diff --git a/src/game/systems/ui-system.cpp b/src/game/systems/ui-system.cpp index a216ade..a30aef1 100644 --- a/src/game/systems/ui-system.cpp +++ b/src/game/systems/ui-system.cpp @@ -47,7 +47,7 @@ ui_system::ui_system(::resource_manager* resource_manager): tool_selector_bg.set_scale({270, 270, 270}); // Setup energy symbol - energy_symbol.set_model(resource_manager->load("energy.obj")); + energy_symbol.set_model(resource_manager->load("energy.mdl")); energy_symbol.set_scale({30, 30, 30}); energy_symbol.update_tweens(); energy_symbol.set_active(false); diff --git a/src/renderer/vertex-attributes.hpp b/src/renderer/vertex-attributes.hpp index d653baf..124b61c 100644 --- a/src/renderer/vertex-attributes.hpp +++ b/src/renderer/vertex-attributes.hpp @@ -23,29 +23,26 @@ /// Vertex position (vec3) #define VERTEX_POSITION_LOCATION 0 -/// Vertex normal (vec3) -#define VERTEX_NORMAL_LOCATION 1 - /// Vertex texture coordinates (vec2) -#define VERTEX_TEXCOORD_LOCATION 2 +#define VERTEX_TEXCOORD_LOCATION 1 + +/// Vertex normal (vec3) +#define VERTEX_NORMAL_LOCATION 2 /// Vertex tangent (vec4) #define VERTEX_TANGENT_LOCATION 3 -/// Vertex bitangent (vec4) -#define VERTEX_BITANGENT_LOCATION 4 +/// Vertex color (vec4) +#define VERTEX_COLOR_LOCATION 4 /// Vertex bone indices (vec4) -#define VERTEX_BONE_INDICES_LOCATION 5 +#define VERTEX_BONE_INDEX_LOCATION 5 /// Vertex bone weights (vec4) -#define VERTEX_BONE_WEIGHTS_LOCATION 6 - -// Vertex color (vec4) -#define VERTEX_COLOR_LOCATION 7 +#define VERTEX_BONE_WEIGHT_LOCATION 6 /// Vertex barycentric coordinates (vec3) -#define VERTEX_BARYCENTRIC_LOCATION 8 +#define VERTEX_BARYCENTRIC_LOCATION 7 #endif // ANTKEEPER_VERTEX_ATTRIBUTES_HPP diff --git a/src/resources/model-loader.cpp b/src/resources/model-loader.cpp index e71d7e1..87529ed 100644 --- a/src/resources/model-loader.cpp +++ b/src/resources/model-loader.cpp @@ -28,14 +28,8 @@ #include #include #include - -struct material_group -{ - std::string name; - material* material; - std::size_t start_index; - std::size_t index_count; -}; +#include +#include static const float3 barycentric_coords[3] = { @@ -44,6 +38,7 @@ static const float3 barycentric_coords[3] = float3{0, 0, 1} }; +/* template <> model* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file) { @@ -359,4 +354,182 @@ model* resource_loader::load(resource_manager* resource_manager, PHYSFS_F return model; } +*/ + +static struct attribute_data +{ + std::string type; + std::size_t size; + std::vector data; +}; +template <> +model* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file) +{ + // Read file into buffer + std::size_t size = static_cast(PHYSFS_fileLength(file)); + std::vector buffer(size); + PHYSFS_readBytes(file, &buffer.front(), size); + + // Parse CBOR in file buffer + nlohmann::json json = nlohmann::json::from_cbor(buffer); + + // Find model name + std::string model_name; + if (auto it = json.find("name"); it != json.end()) + model_name = it.value(); + + // Load attributes + std::unordered_map>> attributes; + if (auto attributes_node = json.find("attributes"); attributes_node != json.end()) + { + for (const auto& attribute_node: attributes_node.value().items()) + { + // Look up attribute name + std::string attribute_name; + if (auto type_node = attribute_node.value().find("name"); type_node != attribute_node.value().end()) + attribute_name = type_node.value().get(); + + // Allocate attribute in attribute map + auto& attribute = attributes[attribute_name]; + std::size_t& attribute_size = std::get<0>(attribute); + std::vector& attribute_data = std::get<1>(attribute); + + // Look up attribute size (per vertex) + attribute_size = 0; + if (auto size_node = attribute_node.value().find("size"); size_node != attribute_node.value().end()) + attribute_size = size_node.value().get(); + + // Look up attribute data + if (auto data_node = attribute_node.value().find("data"); data_node != attribute_node.value().end()) + { + // Resize attribute data + attribute_data.resize(data_node.value().size()); + + // Fill attribute data + float* v = &attribute_data.front(); + for (const auto& element: data_node.value()) + *(v++) = element.get(); + } + } + } + + // Load bounds + aabb bounds = + { + {std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}, + {-std::numeric_limits::infinity(), -std::numeric_limits::infinity(), -std::numeric_limits::infinity()} + }; + if (auto bounds_node = json.find("bounds"); bounds_node != json.end()) + { + if (auto min_node = bounds_node.value().find("min"); min_node != bounds_node.value().end()) + { + float* v = &bounds.min_point.x; + for (const auto& element: min_node.value()) + *(v++) = element.get(); + } + + if (auto max_node = bounds_node.value().find("max"); max_node != bounds_node.value().end()) + { + float* v = &bounds.max_point.x; + for (const auto& element: max_node.value()) + *(v++) = element.get(); + } + } + + // Allocate a model + model* model = new ::model(); + + // Set the model bounds + model->set_bounds(bounds); + + // Calculate vertex size, count, and stride + std::size_t vertex_size = 0; + std::size_t vertex_count = 0; + for (auto it = attributes.begin(); it != attributes.end(); ++it) + { + vertex_size += std::get<0>(it->second); + vertex_count = std::get<1>(it->second).size() / std::get<0>(it->second); + } + std::size_t vertex_stride = sizeof(float) * vertex_size; + + // Build interleaved vertex data buffer + float* vertex_data = new float[vertex_size * vertex_count]; + float* v = &vertex_data[0]; + for (std::size_t i = 0; i < vertex_count; ++i) + { + for (auto it = attributes.begin(); it != attributes.end(); ++it) + { + std::size_t attribute_size = std::get<0>(it->second); + const float* a = &(std::get<1>(it->second)[i * attribute_size]); + + for (std::size_t j = 0; j < attribute_size; ++j) + *(v++) = *(a++); + } + } + + // Resize VBO and upload vertex data + vertex_buffer* vbo = model->get_vertex_buffer(); + vbo->resize(sizeof(float) * vertex_size * vertex_count, vertex_data); + + // Free interleaved vertex data buffer + delete[] vertex_data; + + // Map attribute names to locations + static const std::unordered_map attribute_location_map = + { + {"position", VERTEX_POSITION_LOCATION}, + {"texcoord", VERTEX_TEXCOORD_LOCATION}, + {"normal", VERTEX_NORMAL_LOCATION}, + {"tangent", VERTEX_TANGENT_LOCATION}, + {"color", VERTEX_COLOR_LOCATION}, + {"bone_index", VERTEX_BONE_INDEX_LOCATION}, + {"bone_weight", VERTEX_BONE_WEIGHT_LOCATION}, + {"barycentric", VERTEX_BARYCENTRIC_LOCATION} + }; + + // Bind attributes to VAO + vertex_array* vao = model->get_vertex_array(); + std::size_t offset = 0; + for (auto attribute_it = attributes.begin(); attribute_it != attributes.end(); ++attribute_it) + { + std::string attribute_name = attribute_it->first; + std::size_t attribute_size = std::get<0>(attribute_it->second); + + if (auto location_it = attribute_location_map.find(attribute_name); location_it != attribute_location_map.end()) + vao->bind_attribute(location_it->second, *vbo, attribute_size, vertex_attribute_type::float_32, vertex_stride, offset); + + offset += attribute_size * sizeof(float); + } + + // Load materials + if (auto materials_node = json.find("materials"); materials_node != json.end()) + { + for (const auto& material_node: materials_node.value().items()) + { + std::string group_name; + std::size_t group_offset = 0; + std::size_t group_size = 0; + material* group_material = nullptr; + + if (auto name_node = material_node.value().find("name"); name_node != material_node.value().end()) + group_name = name_node.value().get(); + if (auto offset_node = material_node.value().find("offset"); offset_node != material_node.value().end()) + group_offset = offset_node.value().get(); + if (auto size_node = material_node.value().find("size"); size_node != material_node.value().end()) + group_size = size_node.value().get(); + + std::cout << "MATERIAL: " << group_name << std::endl; + + group_material = resource_manager->load(group_name + ".mtl"); + + model_group* model_group = model->add_group(group_name); + model_group->set_drawing_mode(drawing_mode::triangles); + model_group->set_start_index(group_offset * 3); + model_group->set_index_count(group_size * 3); + model_group->set_material(group_material); + } + } + + return model; +}