diff --git a/Tests.cmake b/Tests.cmake index e16c4f69..3f06e075 100644 --- a/Tests.cmake +++ b/Tests.cmake @@ -40,4 +40,5 @@ add_dz_test(DZ_ImGuiTest tests/ImGui.cpp) add_dz_test(DZ_ECSTest tests/ECS.cpp) file(COPY images/Suzuho-Ueda.bmp DESTINATION ${CMAKE_BINARY_DIR}/images) file(COPY images/hi.bmp DESTINATION ${CMAKE_BINARY_DIR}/images) -file(COPY models/SaiyanOne.glb DESTINATION ${CMAKE_BINARY_DIR}/models) \ No newline at end of file +file(COPY models/SaiyanOne.glb DESTINATION ${CMAKE_BINARY_DIR}/models) +file(COPY models/GoldenSportsCar.glb DESTINATION ${CMAKE_BINARY_DIR}/models) \ No newline at end of file diff --git a/include/dz/ECS.hpp b/include/dz/ECS.hpp index 4aebadb7..a098f333 100644 --- a/include/dz/ECS.hpp +++ b/include/dz/ECS.hpp @@ -11,6 +11,7 @@ #include "State.hpp" #include "ECS/Provider.hpp" #include "ECS/Light.hpp" +#include "ECS/PhongLighting.hpp" #include "ECS/Scene.hpp" #include "ECS/Entity.hpp" #include "ECS/Mesh.hpp" @@ -30,10 +31,17 @@ namespace dz { inline static std::string Cameras_Str = "Cameras"; - inline static std::string Atlas_Str = "Atlas"; + inline static std::string AlbedoAtlas_Str = "AlbedoAtlas"; + inline static std::string NormalAtlas_Str = "NormalAtlas"; + inline static std::string RoughnessAtlas_Str = "RoughnessAtlas"; + inline static std::string MetalnessAtlas_Str = "MetalnessAtlas"; + inline static std::string MetalnessRoughnessAtlas_Str = "MetalnessRoughnessAtlas"; + inline static std::string ShininessAtlas_Str = "ShininessAtlas"; inline static std::string VertexPositions_Str = "VertexPositions"; inline static std::string VertexUV2s_Str = "VertexUV2s"; inline static std::string VertexNormals_Str = "VertexNormals"; + inline static std::string VertexTangents_Str = "VertexTangents"; + inline static std::string VertexBitangents_Str = "VertexBitangents"; template struct ECS : Restorable { @@ -62,6 +70,7 @@ namespace dz { std::string buffer_name; std::string sparse_name; std::string glsl_struct; + bool requires_buffer; std::unordered_map glsl_methods; std::unordered_map> glsl_layouts; std::string glsl_main; @@ -96,10 +105,17 @@ namespace dz { std::unordered_map>> priority_glsl_mains; // ! std::vector restricted_keys{ - Atlas_Str, + AlbedoAtlas_Str, + NormalAtlas_Str, + RoughnessAtlas_Str, + MetalnessAtlas_Str, + MetalnessRoughnessAtlas_Str, + ShininessAtlas_Str, VertexPositions_Str, VertexUV2s_Str, - VertexNormals_Str + VertexNormals_Str, + VertexTangents_Str, + VertexBitangents_Str }; // ! std::map registered_component_map; // ! bool components_registered = false; // ! @@ -124,7 +140,12 @@ namespace dz { bool material_browser_open = true; bool atlas_dirty = false; - ImagePack atlas_pack; + ImagePack albedo_atlas_pack; + ImagePack normal_atlas_pack; + ImagePack roughness_atlas_pack; + ImagePack metalness_atlas_pack; + ImagePack metalness_roughness_atlas_pack; + ImagePack shininess_atlas_pack; auto GenerateEntitysDrawFunction() { return [&](auto buffer_group, auto& draw_object) -> DrawTuples { @@ -251,33 +272,59 @@ namespace dz { EnableDrawInWindow(window_ptr); } + void UseAtlas(auto& pack, auto& str) { + auto atlas = pack.getAtlas(); + shader_use_image(main_shader, str, atlas); + shader_use_image(model_compute_shader, str, atlas); + shader_use_image(camera_mat_compute_shader, str, atlas); + } + void MarkReady() { - UpdateAtlas(); - auto atlas = atlas_pack.getAtlas(); - shader_use_image(main_shader, Atlas_Str, atlas); - shader_use_image(model_compute_shader, Atlas_Str, atlas); - shader_use_image(camera_mat_compute_shader, Atlas_Str, atlas); + UpdateAtlases(); + UseAtlas(albedo_atlas_pack, AlbedoAtlas_Str); + UseAtlas(normal_atlas_pack, NormalAtlas_Str); + UseAtlas(roughness_atlas_pack, RoughnessAtlas_Str); + UseAtlas(metalness_atlas_pack, MetalnessAtlas_Str); + UseAtlas(metalness_roughness_atlas_pack, MetalnessRoughnessAtlas_Str); + UseAtlas(shininess_atlas_pack, ShininessAtlas_Str); if (!buffer_initialized) { buffer_group_initialize(buffer_group); buffer_initialized = true; } - shader_update_descriptor_sets(main_shader); + else { + shader_update_descriptor_sets(main_shader); + shader_update_descriptor_sets(model_compute_shader); + shader_update_descriptor_sets(camera_mat_compute_shader); + } } - void UpdateAtlas() { - atlas_pack.check(); + void UpdatePackedRect(auto image, auto& image_pack, auto& atlas_pack) { + if (!image) + return; + auto& packed_rect = image_pack.findPackedRect(image); + (*(vec*)&atlas_pack[0]) = {packed_rect.w, packed_rect.h}; + (*(vec*)&atlas_pack[2]) = {packed_rect.x, packed_rect.y}; + } + + void UpdateAtlases() { + albedo_atlas_pack.check(); + normal_atlas_pack.check(); + roughness_atlas_pack.check(); + metalness_atlas_pack.check(); + metalness_roughness_atlas_pack.check(); + shininess_atlas_pack.check(); for (auto& material_group_sh_ptr : material_group_vector) { auto generic_group_ptr = material_group_sh_ptr.get(); auto material_group_ptr = dynamic_cast(generic_group_ptr); auto& material_group = *material_group_ptr; - if (!material_group.image) - continue; auto& material = GetMaterial(material_group.id); - auto& atlasImageSize = *(vec*)&material.atlas_pack[0]; - auto& atlasPackedRect = *(vec*)&material.atlas_pack[2]; - auto& packed_rect = atlas_pack.findPackedRect(material_group.image); - atlasImageSize = {packed_rect.w, packed_rect.h}; - atlasPackedRect = {packed_rect.x, packed_rect.y}; + // + UpdatePackedRect(material_group.albedo_image, albedo_atlas_pack, material.albedo_atlas_pack); + UpdatePackedRect(material_group.normal_image, normal_atlas_pack, material.normal_atlas_pack); + UpdatePackedRect(material_group.roughness_image, roughness_atlas_pack, material.roughness_atlas_pack); + UpdatePackedRect(material_group.metalness_image, metalness_atlas_pack, material.metalness_atlas_pack); + UpdatePackedRect(material_group.metalness_roughness_image, metalness_roughness_atlas_pack, material.metalness_roughness_atlas_pack); + UpdatePackedRect(material_group.shininess_image, shininess_atlas_pack, material.shininess_atlas_pack); continue; } } @@ -445,6 +492,7 @@ namespace dz { auto& glsl_methods = TProvider::GetGLSLMethods(); auto& glsl_layouts = TProvider::GetGLSLLayouts(); auto& priority_glsl_main = TProvider::GetGLSLMain(); + constexpr auto requires_buffer = TProvider::GetRequiresBuffer(); constexpr auto pid = TProvider::GetPID(); prioritized_provider_ids[priority].push_back(pid); auto provider_index = pid_provider_groups.size(); @@ -458,6 +506,7 @@ namespace dz { provider_group.glsl_methods = glsl_methods; provider_group.glsl_layouts = glsl_layouts; provider_group.is_component = TProvider::GetIsComponent(); + provider_group.requires_buffer = requires_buffer; for (auto& [main_priority, main_string, module_type] : priority_glsl_main) { priority_glsl_mains[module_type][main_priority].push_back(main_string); } @@ -539,7 +588,11 @@ namespace dz { group.cid = pid; group.id = ecs_id; - group.GetName() += (" #" + std::to_string(pro_id)); + auto& group_name = group.GetName(); + if (name.empty()) + group_name += (" #" + std::to_string(pro_id)); + else + group_name = name; auto& provider_group = pid_provider_groups[pid]; @@ -671,30 +724,65 @@ namespace dz { } template - int AddMaterial(const TMaterial& material_data, int& out_index) { - return AddProvider(-1, material_data, material_group_vector, out_index); + int AddMaterial(const TMaterial& material_data, int& out_index, const std::string& name = "") { + return AddProvider(-1, material_data, material_group_vector, out_index, name); } MaterialProviderT& GetMaterial(size_t material_id) { return GetProviderData(material_id); } - void SetMaterialImage(size_t material_id, Image* image) { + void SetMaterialImages(size_t material_id, const std::vector images_vec) { auto& material_group = GetGroupByID(material_id); - material_group.image = image; - - auto frame_ds_pair = image_create_descriptor_set(image); - material_group.frame_image_ds = frame_ds_pair.second; - atlas_pack.addImage(material_group.image); + for (auto& image_ptr : images_vec) { + auto frame_ds_pair = image_create_descriptor_set(image_ptr); + auto surfaceType = image_get_surface_type(image_ptr); + switch (surfaceType) { + case SurfaceType::BaseColor: + case SurfaceType::Diffuse: + material_group.albedo_image = image_ptr; + material_group.albedo_frame_image_ds = frame_ds_pair.second; + albedo_atlas_pack.addImage(image_ptr); + break; + case SurfaceType::DiffuseRoughness: + material_group.roughness_image = image_ptr; + material_group.roughness_frame_image_ds = frame_ds_pair.second; + roughness_atlas_pack.addImage(image_ptr); + break; + case SurfaceType::Metalness: + material_group.metalness_image = image_ptr; + material_group.metalness_frame_image_ds = frame_ds_pair.second; + metalness_atlas_pack.addImage(image_ptr); + break; + case SurfaceType::MetalnessRoughness: + material_group.metalness_roughness_image = image_ptr; + material_group.metalness_roughness_frame_image_ds = frame_ds_pair.second; + metalness_roughness_atlas_pack.addImage(image_ptr); + break; + case SurfaceType::Normal: + material_group.normal_image = image_ptr; + material_group.normal_frame_image_ds = frame_ds_pair.second; + normal_atlas_pack.addImage(image_ptr); + break; + case SurfaceType::Shininess: + material_group.shininess_image = image_ptr; + material_group.shininess_frame_image_ds = frame_ds_pair.second; + shininess_atlas_pack.addImage(image_ptr); + break; + } + } + if (buffer_initialized) - UpdateAtlas(); + UpdateAtlases(); } int AddMesh( const std::vector>& positions, const std::vector>& uv2s, const std::vector>& normals, + const std::vector>& tangents, + const std::vector>& bitangents, int material_index, int& out_index, const std::string& name = "" @@ -703,6 +791,8 @@ namespace dz { auto position_index = buffer_group_get_buffer_element_count(buffer_group, VertexPositions_Str); auto uv2_index = buffer_group_get_buffer_element_count(buffer_group, VertexUV2s_Str); auto normal_index = buffer_group_get_buffer_element_count(buffer_group, VertexNormals_Str); + auto tangent_index = buffer_group_get_buffer_element_count(buffer_group, VertexTangents_Str); + auto bitangent_index = buffer_group_get_buffer_element_count(buffer_group, VertexBitangents_Str); if (!positions.empty()) { mesh_data.vertex_count = positions.size(); @@ -712,6 +802,10 @@ namespace dz { mesh_data.uv2_offset = uv2_index; if (!normals.empty()) mesh_data.normal_offset = normal_index; + if (!tangents.empty()) + mesh_data.tangent_offset = tangent_index; + if (!bitangents.empty()) + mesh_data.bitangent_offset = bitangent_index; auto mesh_id = AddProvider(-1, mesh_data, mesh_group_vector, out_index, name); @@ -742,12 +836,43 @@ namespace dz { memcpy((void*)&normals_ptr[mesh_data.normal_offset], normals.data(), normals.size() * sizeof(vec)); } + if (mesh_data.tangent_offset != -1) { + buffer_group_set_buffer_element_count(buffer_group, VertexTangents_Str, mesh_data.tangent_offset + tangents.size()); + + auto tangents_sh_ptr = buffer_group_get_buffer_data_ptr(buffer_group, VertexTangents_Str); + auto tangents_ptr = (vec*)(tangents_sh_ptr.get()); + + memcpy((void*)&tangents_ptr[mesh_data.tangent_offset], tangents.data(), tangents.size() * sizeof(vec)); + } + + if (mesh_data.bitangent_offset != -1) { + buffer_group_set_buffer_element_count(buffer_group, VertexBitangents_Str, mesh_data.bitangent_offset + bitangents.size()); + + auto bitangents_sh_ptr = buffer_group_get_buffer_data_ptr(buffer_group, VertexBitangents_Str); + auto bitangents_ptr = (vec*)(bitangents_sh_ptr.get()); + + memcpy((void*)&bitangents_ptr[mesh_data.bitangent_offset], bitangents.data(), bitangents.size() * sizeof(vec)); + } + auto& mesh_group = GetGroupByID(mesh_id); mesh_group.material_index = material_index; return mesh_id; } + template + int AddLight(int parent_id, const TLight& light_data, const std::string& name = "") { + auto parent_group_ptr = FindParentGroupPtr(parent_id); + int out_index = -1; + return AddProvider(parent_id, light_data, + parent_group_ptr ? parent_group_ptr->GetChildren() : reflectable_group_root_vector, out_index, name); + } + + template + int AddLight(const TLight& light_data, const std::string& name = "") { + return AddLight(-1, light_data, name); + } + ReflectableGroup& GetGenericGroupByID(size_t id) { auto ptr = FindParentGroupPtr(id); if (ptr) @@ -993,7 +1118,12 @@ namespace dz { auto binding_index = 0; - shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D Atlas;\n"; + shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D AlbedoAtlas;\n"; + shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D NormalAtlas;\n"; + shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D RoughnessAtlas;\n"; + shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D MetalnessAtlas;\n"; + shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D MetalnessRoughnessAtlas;\n"; + shader_header += "\nlayout(binding = " + std::to_string(binding_index++) + ") uniform sampler2D ShininessAtlas;\n"; // Setup Structs for (auto& [priority, provider_ids] : prioritized_provider_ids) { @@ -1018,12 +1148,26 @@ layout(std430, binding = )" + std::to_string(binding_index++) + R"() buffer Vert layout(std430, binding = )" + std::to_string(binding_index++) + R"() buffer VertexNormalsBuffer { vec4 data[]; } VertexNormals; +)"; + shader_header += R"( +layout(std430, binding = )" + std::to_string(binding_index++) + R"() buffer VertexTangentsBuffer { + vec4 data[]; +} VertexTangents; +)"; + shader_header += R"( +layout(std430, binding = )" + std::to_string(binding_index++) + R"() buffer VertexBitangentsBuffer { + vec4 data[]; +} VertexBitangents; )"; // Setup Buffers for (auto& [priority, provider_ids] : prioritized_provider_ids) { for (auto& provider_id : provider_ids) { auto& provider_group = pid_provider_groups[provider_id]; + if (!provider_group.requires_buffer) { + shader_header += provider_group.glsl_methods[moduleType]; + continue; + } shader_header += R"( layout(std430, binding = )" + std::to_string(binding_index++) + ") buffer " + provider_group.struct_name + R"(Buffer { )" + provider_group.struct_name + R"( data[]; @@ -1130,12 +1274,14 @@ bool HasComponentWithType(in Entity entity, int entity_index, int type, out int #version 450 layout(location = 0) out int outID; layout(location = 1) out vec4 outColor; -layout(location = 2) out vec4 outPosition; +layout(location = 2) out vec3 outPosition; layout(location = 3) out vec3 outNormal; layout(location = 4) out vec3 outViewPosition; layout(location = 5) out vec2 outUV2; +layout(location = 6) out vec3 outTangent; +layout(location = 7) out vec3 outBitangent; )"; - int out_location = 6; + int out_location = 8; int in_location = 0; shader_string += GenerateShaderLayout(ShaderModuleType::Vertex, in_location, out_location); @@ -1164,7 +1310,7 @@ void main() { vec3 normal_vs = normalize(mat3(transpose(inverse(entity.model))) * mesh_normal); gl_Position = clip_position; outColor = final_color; - outPosition = entity.model * vertex_position; + outPosition = vec3(entity.model * vertex_position); outViewPosition = view_position.xyz; outNormal = normal_vs; outUV2 = mesh_uv2; @@ -1179,14 +1325,16 @@ void main() { #version 450 layout(location = 0) flat in int inID; layout(location = 1) in vec4 inColor; -layout(location = 2) in vec4 inPosition; +layout(location = 2) in vec3 inPosition; layout(location = 3) in vec3 inNormal; layout(location = 4) in vec3 inViewPosition; layout(location = 5) in vec2 inUV2; +layout(location = 6) in vec3 inTangent; +layout(location = 7) in vec3 inBitangent; layout(location = 0) out vec4 FragColor; )"; - int in_location = 6; + int in_location = 8; int out_location = 1; shader_string += GenerateShaderLayout(ShaderModuleType::Fragment, in_location, out_location); @@ -1205,6 +1353,7 @@ void main() { Entity entity = GetEntityData(submesh.parent_index); int t_component_index = -1; vec4 current_color = inColor; + vec3 current_normal = inNormal; )"; shader_string += GenerateShaderMain(ShaderModuleType::Fragment); diff --git a/include/dz/ECS/Camera.hpp b/include/dz/ECS/Camera.hpp index 08a02006..b1bd7153 100644 --- a/include/dz/ECS/Camera.hpp +++ b/include/dz/ECS/Camera.hpp @@ -1,6 +1,7 @@ #pragma once #include "Provider.hpp" +#include "../Reflectable.hpp" #include "../Framebuffer.hpp" #include "../Shader.hpp" #include "../math.hpp" @@ -28,6 +29,7 @@ namespace dz::ecs { int parent_cid = 0; int transform_dirty = 1; int is_active = 1; + inline static constexpr bool RequiresBuffer = true; inline static constexpr bool IsCameraProvider = true; inline static constexpr size_t PID = 5; inline static float Priority = 0.5f; @@ -126,7 +128,7 @@ void GetCameraModel(int camera_index, out mat4 out_model, out int parent_index, }; - struct CameraMetaReflectable : Reflectable { + struct CameraMetaReflectable : ::Reflectable { private: std::function get_camera_function; diff --git a/include/dz/ECS/Entity.hpp b/include/dz/ECS/Entity.hpp index 2ad75910..34673773 100644 --- a/include/dz/ECS/Entity.hpp +++ b/include/dz/ECS/Entity.hpp @@ -16,6 +16,7 @@ namespace dz::ecs { inline static constexpr size_t PID = 2; inline static float Priority = 0.5f; + inline static constexpr bool RequiresBuffer = true; inline static constexpr bool IsEntityProvider = true; inline static std::string ProviderName = "Entity"; inline static std::string StructName = "Entity"; diff --git a/include/dz/ECS/Light.hpp b/include/dz/ECS/Light.hpp index da5f7031..490e6aff 100644 --- a/include/dz/ECS/Light.hpp +++ b/include/dz/ECS/Light.hpp @@ -1,5 +1,6 @@ #pragma once #include "Provider.hpp" +#include "../Reflectable.hpp" #include "../math.hpp" namespace dz::ecs { struct Light : Provider { @@ -20,6 +21,7 @@ namespace dz::ecs { float outerCone; // for spot inline static constexpr size_t PID = 7; inline static float Priority = 3.5f; + inline static constexpr bool RequiresBuffer = true; inline static std::string ProviderName = "Light"; inline static std::string StructName = "Light"; inline static std::string GLSLStruct = R"( @@ -36,116 +38,131 @@ struct Light { float outerCone; }; )"; - inline static std::unordered_map GLSLMethods = { - {ShaderModuleType::Fragment, R"( -vec3 CalculateLight(in vec3 normal, vec3 frag_pos, vec3 view_dir, in Light light) { - vec3 light_dir; - float attenuation = 1.0; - if (light.type == 0) - { - light_dir = normalize(-light.direction); - } - else - { - light_dir = normalize(light.position - frag_pos); - float dist = length(light.position - frag_pos); - attenuation = clamp(1.0 - (dist / light.range), 0.0, 1.0); - } - - float diff = max(dot(normal, light_dir), 0.0); - vec3 reflect_dir = reflect(-light_dir, normal); - float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 4.0);//shininess); - - float spotlight_factor = 1.0; - if (light.type == 2) - { - float theta = dot(light_dir, normalize(-light.direction)); - float epsilon = light.innerCone - light.outerCone; - spotlight_factor = clamp((theta - light.outerCone) / epsilon, 0.0, 1.0); - } - - vec3 diffuse = diff * light.color * light.intensity; - vec3 specular = spec * light.color * light.intensity; - - return (diffuse + specular) * attenuation * spotlight_factor; -} -)" } - }; inline static std::vector> GLSLMain = { {3.5f, R"( - vec3 frag_pos = vec3(inPosition); + vec3 frag_pos = inPosition; vec3 view_dir = normalize(camera.position - frag_pos); int lights_size = Lights.data.length(); - vec3 light_color = vec3(0.0); - for (int light_index = 0; light_index < lights_size; light_index++) { - light_color += CalculateLight(inNormal, frag_pos, view_dir, Lights.data[light_index]); - } - current_color = vec4(light_color, 1.0) * current_color; )", ShaderModuleType::Fragment} }; - }; - struct LightMetaReflectable : Reflectable { - - private: - std::function get_light_function; - std::function reset_reflectables_function; - int uid; - std::string name; - inline static std::unordered_map> prop_name_indexes = { - { "type", {0, 0}}, - { "intensity", {1, 0}}, - { "range", {2, 0}}, - { "innerCone", {3, 0}}, - { "position", {4, 0}}, - { "direction", {5, 0}}, - { "color", {6, 0}}, - { "outerCone", {7, 0}} - }; - inline static std::unordered_map prop_index_names = { - { 0, "type" }, - { 1, "intensity"}, - { 2, "range"}, - { 3, "innerCone"}, - { 4, "position"}, - { 5, "direction"}, - { 6, "color"}, - { 7, "outerCone"} - }; - inline static std::vector prop_names = { - "type", - "intensity", - "range", - "innerCone", - "position", - "direction", - "color", - "outerCone" + struct LightMetaReflectable : Reflectable { + + private: + std::function get_light_function; + int uid; + std::string name; + inline static std::unordered_map> prop_name_indexes = { + { "type", {0, 0}}, + { "intensity", {1, 0}}, + { "range", {2, 0}}, + { "innerCone", {3, 0}}, + { "position", {4, 0}}, + { "direction", {5, 0}}, + { "color", {6, 0}}, + { "outerCone", {7, 0}} + }; + inline static std::unordered_map prop_index_names = { + { 0, "type" }, + { 1, "intensity"}, + { 2, "range"}, + { 3, "innerCone"}, + { 4, "position"}, + { 5, "direction"}, + { 6, "color"}, + { 7, "outerCone"} + }; + inline static std::vector prop_names = { + "type", + "intensity", + "range", + "innerCone", + "position", + "direction", + "color", + "outerCone" + }; + inline static const std::vector typeinfos = { + &typeid(Light::LightType), + &typeid(float), + &typeid(float), + &typeid(float), + &typeid(vec), + &typeid(vec), + &typeid(color_vec), + &typeid(float) + }; + + public: + LightMetaReflectable( + const std::function& get_light_function + ); + int GetID() override; + std::string& GetName() override; + DEF_GET_PROPERTY_INDEX_BY_NAME(prop_name_indexes); + DEF_GET_PROPERTY_NAMES(prop_names); + void* GetVoidPropertyByIndex(int prop_index) override; + DEF_GET_VOID_PROPERTY_BY_NAME; + DEF_GET_PROPERTY_TYPEINFOS(typeinfos); + void NotifyChange(int prop_index) override; }; - inline static const std::vector typeinfos = { - &typeid(Light::LightType), - &typeid(float), - &typeid(float), - &typeid(float), - &typeid(vec), - &typeid(vec), - &typeid(color_vec), - &typeid(float) + + struct LightReflectableGroup : ReflectableGroup { + BufferGroup* buffer_group = nullptr; + std::string name; + std::vector reflectables; + LightReflectableGroup(BufferGroup* buffer_group): + buffer_group(buffer_group), + name("Light") + {} + LightReflectableGroup(BufferGroup* buffer_group, Serial& serial): + buffer_group(buffer_group) + { + restore(serial); + } + ~LightReflectableGroup() { + ClearReflectables(); + } + GroupType GetGroupType() override { + return ReflectableGroup::Light; + } + std::string& GetName() override { + return name; + } + const std::vector& GetReflectables() override { + return reflectables; + } + void UpdateReflectables() { } + void ClearReflectables() { + if (reflectables.empty()) { + return; + } + delete reflectables[0]; + reflectables.clear(); + } + void UpdateChildren() override { + if (reflectables.empty()) { + reflectables.push_back(new LightMetaReflectable([&]() { + auto buffer = buffer_group_get_buffer_data_ptr(buffer_group, "Lights"); + return ((struct Light*)(buffer.get())) + index; + })); + } + } + bool backup(Serial& serial) const override { + if (!backup_internal(serial)) + return false; + serial << name; + return true; + } + bool restore(Serial& serial) override { + if (!restore_internal(serial)) + return false; + serial >> name; + return true; + } }; - public: - LightMetaReflectable( - const std::function& get_light_function, - const std::function& reset_reflectables_function - ); - int GetID() override; - std::string& GetName() override; - DEF_GET_PROPERTY_INDEX_BY_NAME(prop_name_indexes); - DEF_GET_PROPERTY_NAMES(prop_names); - void* GetVoidPropertyByIndex(int prop_index) override; - DEF_GET_VOID_PROPERTY_BY_NAME; - DEF_GET_PROPERTY_TYPEINFOS(typeinfos); - void NotifyChange(int prop_index) override; + using ReflectableGroup = LightReflectableGroup; }; } \ No newline at end of file diff --git a/include/dz/ECS/Material.hpp b/include/dz/ECS/Material.hpp index 6de2ed37..c2f8c696 100644 --- a/include/dz/ECS/Material.hpp +++ b/include/dz/ECS/Material.hpp @@ -1,5 +1,6 @@ #pragma once #include "Provider.hpp" +#include "../Reflectable.hpp" #include "../Image.hpp" namespace dz::ecs { @@ -9,75 +10,126 @@ namespace dz::ecs { }; struct Material : Provider { - vec atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; - vec albedo = {1.0f, 1.0f, 1.0f, 1.0f}; + vec albedo_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + vec normal_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + vec metalness_roughness_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + vec roughness_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + vec metalness_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + vec shininess_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + vec albedo_color = {1.0f, 1.0f, 1.0f, 1.0f}; inline static constexpr size_t PID = 6; inline static float Priority = 2.5f; + inline static constexpr bool RequiresBuffer = true; inline static constexpr bool IsMaterialProvider = true; inline static std::string ProviderName = "Material"; inline static std::string StructName = "Material"; inline static std::string GLSLStruct = R"( - struct Material { - vec4 atlas_pack; - vec4 albedo; - }; - )"; +struct Material { + vec4 albedo_atlas_pack; + vec4 normal_atlas_pack; + vec4 metalness_roughness_atlas_pack; + vec4 roughness_atlas_pack; + vec4 metalness_atlas_pack; + vec4 shininess_atlas_pack; + vec4 albedo_color; +}; +)"; inline static std::unordered_map GLSLMethods = { { ShaderModuleType::Vertex, R"( vec4 GetMaterialBaseColor(in SubMesh submesh) { - bool not_what = true; - for (int i = 0; i < 4; i++) { - if (Materials.data[submesh.material_index].atlas_pack[i] != -1.0) { - not_what = false; - break; - } - } - if (not_what) - return Materials.data[submesh.material_index].albedo; - outIsTexture = 1; + if (Materials.data[submesh.material_index].albedo_atlas_pack.x == -1.0) + return Materials.data[submesh.material_index].albedo_color; return vec4(1.0, 0.0, 1.0, 1.0); } +vec4 SampleAtlas(in vec2 inUV2, in vec2 image_size, in vec2 packed_rect, in sampler2D atlas) { + vec2 resolution = vec2(textureSize(atlas, 0)); + vec2 offset_uv = packed_rect / resolution; + vec2 scale_uv = image_size / resolution; + vec2 packed_uv = offset_uv + inUV2 * scale_uv; + return texture(atlas, packed_uv); +} +void EnsureMaterialNormal(in SubMesh submesh, in vec2 inUV2, inout vec3 current_normal) { + vec2 image_size = Materials.data[submesh.material_index].normal_atlas_pack.xy; + if (image_size.x == -1.0) + return; + vec2 packed_rect = Materials.data[submesh.material_index].normal_atlas_pack.zw; + current_normal = SampleAtlas(inUV2, image_size, packed_rect, NormalAtlas).xyz; + current_normal = normalize(current_normal * 2.0 - 1.0); +} )" }, { ShaderModuleType::Fragment, R"( +vec4 SampleAtlas(in vec2 image_size, in vec2 packed_rect, in sampler2D atlas) { + vec2 resolution = vec2(textureSize(atlas, 0)); + vec2 offset_uv = packed_rect / resolution; + vec2 scale_uv = image_size / resolution; + vec2 packed_uv = offset_uv + inUV2 * scale_uv; + return texture(atlas, packed_uv); +} void EnsureMaterialFragColor(in SubMesh submesh, inout vec4 current_color) { - if (inIsTexture != 1) + vec2 image_size = Materials.data[submesh.material_index].albedo_atlas_pack.xy; + if (image_size.x == -1.0) + return; + vec2 packed_rect = Materials.data[submesh.material_index].albedo_atlas_pack.zw; + current_color = SampleAtlas(image_size, packed_rect, AlbedoAtlas); +} +void EnsureMaterialNormal(in SubMesh submesh, inout vec3 current_normal) { + vec2 image_size = Materials.data[submesh.material_index].normal_atlas_pack.xy; + if (image_size.x == -1.0) + return; + vec2 packed_rect = Materials.data[submesh.material_index].normal_atlas_pack.zw; + vec3 tangentNormal = SampleAtlas(image_size, packed_rect, NormalAtlas).xyz; + tangentNormal = normalize(tangentNormal * 2.0 - 1.0); + mat3 TBN = mat3(inTangent, inBitangent, inNormal); + current_normal = normalize(TBN * tangentNormal); +} +void EnsureMaterialMetalnessRoughness(in SubMesh submesh, inout float metalness, inout float roughness) { + vec2 m_r_image_size = Materials.data[submesh.material_index].metalness_roughness_atlas_pack.xy; + if (m_r_image_size.x != -1.0) { + vec2 m_r_packed_rect = Materials.data[submesh.material_index].metalness_roughness_atlas_pack.zw; + vec4 m_r_vec = SampleAtlas(m_r_image_size, m_r_packed_rect, MetalnessRoughnessAtlas); + metalness = m_r_vec.r; + roughness = m_r_vec.g; return; - vec2 uv = inUV2; - Material material = Materials.data[submesh.material_index]; - vec2 atlas_image_size = material.atlas_pack.xy; - vec2 atlas_packed_rect = material.atlas_pack.zw; - - vec2 atlas_resolution = vec2(textureSize(Atlas, 0)); - vec2 offset_uv = atlas_packed_rect / atlas_resolution; - vec2 scale_uv = atlas_image_size / atlas_resolution; - vec2 packed_uv = offset_uv + uv * scale_uv; - - vec4 tex_color = texture(Atlas, packed_uv); - current_color = tex_color; + } + vec2 m_image_size = Materials.data[submesh.material_index].metalness_atlas_pack.xy; + if (m_image_size.x != -1.0) { + vec2 m_packed_rect = Materials.data[submesh.material_index].metalness_atlas_pack.zw; + metalness = SampleAtlas(m_image_size, m_packed_rect, MetalnessAtlas).r; + } + vec2 r_image_size = Materials.data[submesh.material_index].roughness_atlas_pack.xy; + if (r_image_size.x != -1.0) { + vec2 r_packed_rect = Materials.data[submesh.material_index].roughness_atlas_pack.zw; + roughness = SampleAtlas(r_image_size, r_packed_rect, RoughnessAtlas).r; + } } )" } }; inline static std::unordered_map> GLSLLayouts = { - { ShaderModuleType::Vertex, { - "layout(location = @OUT@) out int outIsTexture;" - } }, - { ShaderModuleType::Fragment, { - "layout(location = @IN@) in flat int inIsTexture;" - } } + // { ShaderModuleType::Vertex, { + // "layout(location = @OUT@) out int outIsTexture;" + // } }, + // { ShaderModuleType::Fragment, { + // "layout(location = @IN@) in flat int inIsTexture;" + // } } }; inline static std::vector> GLSLMain = { {0.5f, R"( final_color = GetMaterialBaseColor(submesh); + // EnsureMaterialNormal(submesh, mesh_uv2, mesh_normal); )", ShaderModuleType::Vertex}, {0.5f, R"( EnsureMaterialFragColor(submesh, current_color); + EnsureMaterialNormal(submesh, current_normal); + float metalness = 0.0; + float roughness = 0.0; + EnsureMaterialMetalnessRoughness(submesh, metalness, roughness); )", ShaderModuleType::Fragment} }; - struct MaterialReflectable : Reflectable { + struct MaterialReflectable : ::Reflectable { private: std::function get_material_function; @@ -112,8 +164,25 @@ void EnsureMaterialFragColor(in SubMesh submesh, inout vec4 current_color) { BufferGroup* buffer_group = nullptr; std::string name; std::vector reflectables; - Image* image = nullptr; - VkDescriptorSet frame_image_ds = VK_NULL_HANDLE; + + Image* albedo_image = nullptr; + VkDescriptorSet albedo_frame_image_ds = VK_NULL_HANDLE; + + Image* normal_image = nullptr; + VkDescriptorSet normal_frame_image_ds = VK_NULL_HANDLE; + + Image* metalness_roughness_image = nullptr; + VkDescriptorSet metalness_roughness_frame_image_ds = VK_NULL_HANDLE; + + Image* roughness_image = nullptr; + VkDescriptorSet roughness_frame_image_ds = VK_NULL_HANDLE; + + Image* metalness_image = nullptr; + VkDescriptorSet metalness_frame_image_ds = VK_NULL_HANDLE; + + Image* shininess_image = nullptr; + VkDescriptorSet shininess_frame_image_ds = VK_NULL_HANDLE; + MaterialReflectableGroup(BufferGroup* buffer_group): buffer_group(buffer_group), name("Material") diff --git a/include/dz/ECS/Mesh.hpp b/include/dz/ECS/Mesh.hpp index 6448cdff..4a87c808 100644 --- a/include/dz/ECS/Mesh.hpp +++ b/include/dz/ECS/Mesh.hpp @@ -1,5 +1,6 @@ #pragma once #include "Provider.hpp" +#include "../Reflectable.hpp" namespace dz::ecs { struct Mesh : Provider { @@ -8,8 +9,14 @@ namespace dz::ecs { int uv2_offset = -1; int normal_offset = -1; + int tangent_offset = -1; + int bitangent_offset = -1; + int padding1 = 0; + int padding2 = 0; + inline static constexpr size_t PID = 3; inline static float Priority = 0.5f; + inline static constexpr bool RequiresBuffer = true; inline static constexpr bool IsMeshProvider = true; inline static std::string ProviderName = "Mesh"; inline static std::string StructName = "Mesh"; @@ -19,6 +26,10 @@ struct Mesh { int position_offset; int uv2_offset; int normal_offset; + int tangent_offset; + int bitangent_offset; + int padding1; + int padding2; }; )"; inline static std::unordered_map GLSLMethods = { @@ -38,6 +49,16 @@ vec2 GetMeshUV2(in Mesh mesh) { return vec2(0.0); return VertexUV2s.data[mesh.uv2_offset + gl_VertexIndex]; } +vec3 GetMeshTangent(in Mesh mesh) { + if (mesh.tangent_offset == -1) + return vec3(0.0); + return VertexTangents.data[mesh.tangent_offset + gl_VertexIndex].xyz; +} +vec3 GetMeshBitangent(in Mesh mesh) { + if (mesh.bitangent_offset == -1) + return vec3(0.0); + return VertexBitangents.data[mesh.bitangent_offset + gl_VertexIndex].xyz; +} )" }, { ShaderModuleType::Fragment, R"( )" } @@ -48,10 +69,12 @@ vec2 GetMeshUV2(in Mesh mesh) { vec3 mesh_vertex = GetMeshVertex(mesh); vec3 mesh_normal = GetMeshNormal(mesh); vec2 mesh_uv2 = GetMeshUV2(mesh); + vec3 mesh_tangent = GetMeshTangent(mesh); + vec3 mesh_bitangent = GetMeshBitangent(mesh); )", ShaderModuleType::Vertex} }; - struct MeshReflectable : Reflectable { + struct MeshReflectable : ::Reflectable { private: std::function get_mesh_function; diff --git a/include/dz/ECS/PBRLighting.hpp b/include/dz/ECS/PBRLighting.hpp new file mode 100644 index 00000000..e69de29b diff --git a/include/dz/ECS/PhongLighting.hpp b/include/dz/ECS/PhongLighting.hpp new file mode 100644 index 00000000..3284e103 --- /dev/null +++ b/include/dz/ECS/PhongLighting.hpp @@ -0,0 +1,94 @@ +#pragma once +#include "Provider.hpp" +#include "../Reflectable.hpp" +#include "../math.hpp" +#include "../Shader.hpp" +namespace dz::ecs { + struct PhongLighting : Provider { + inline static constexpr size_t PID = 8; + inline static float Priority = 4.0f; + inline static constexpr bool RequiresBuffer = false; + inline static std::string ProviderName = "PhongLighting"; + inline static std::string StructName = "PhongLighting"; + inline static std::unordered_map GLSLMethods = { + {ShaderModuleType::Fragment, R"( +vec3 CalculatePhongLighting(in vec3 normal, vec3 frag_pos, vec3 view_dir, in Light light) { + vec3 light_dir; + float attenuation = 1.0; + + if (light.type == 0) + { + light_dir = normalize(-light.direction); + } + else + { + light_dir = normalize(light.position - frag_pos); + float dist = length(light.position - frag_pos); + attenuation = clamp(1.0 - (dist / light.range), 0.0, 1.0); + } + + float diff = max(dot(normal, light_dir), 0.0); + vec3 reflect_dir = reflect(-light_dir, normal); + float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 4.0);//shininess); + + float spotlight_factor = 1.0; + if (light.type == 2) + { + float theta = dot(light_dir, normalize(-light.direction)); + float epsilon = light.innerCone - light.outerCone; + spotlight_factor = clamp((theta - light.outerCone) / epsilon, 0.0, 1.0); + } + + vec3 diffuse = diff * light.color * light.intensity; + vec3 specular = spec * light.color * light.intensity; + + return (diffuse + specular) * attenuation * spotlight_factor; +} +)" } + }; + inline static std::vector> GLSLMain = { + {4.0f, R"( + vec3 light_color = vec3(0.0); + for (int light_index = 0; light_index < lights_size; light_index++) { + light_color += CalculatePhongLighting(current_normal, frag_pos, view_dir, Lights.data[light_index]); + } + current_color = vec4(light_color, 1.0) * current_color; +)", ShaderModuleType::Fragment} + }; + + struct PhongLightingReflectableGroup : ReflectableGroup { + BufferGroup* buffer_group = nullptr; + std::string name; + std::vector reflectables; + PhongLightingReflectableGroup(BufferGroup* buffer_group): + buffer_group(buffer_group), + name("PhongLighting") + {} + PhongLightingReflectableGroup(BufferGroup* buffer_group, Serial& serial): + buffer_group(buffer_group) + { + restore(serial); + } + GroupType GetGroupType() override { + return ReflectableGroup::Light; + } + std::string& GetName() override { + return name; + } + bool backup(Serial& serial) const override { + if (!backup_internal(serial)) + return false; + serial << name; + return true; + } + bool restore(Serial& serial) override { + if (!restore_internal(serial)) + return false; + serial >> name; + return true; + } + }; + + using ReflectableGroup = PhongLightingReflectableGroup; + }; +} \ No newline at end of file diff --git a/include/dz/ECS/Provider.hpp b/include/dz/ECS/Provider.hpp index c206f001..49671eed 100644 --- a/include/dz/ECS/Provider.hpp +++ b/include/dz/ECS/Provider.hpp @@ -30,6 +30,13 @@ namespace dz { return 0; } + inline static constexpr bool GetRequiresBuffer() { + if constexpr (requires { T::RequiresBuffer; } ) { + return T::RequiresBuffer; + } + return false; + } + inline static constexpr bool GetIsDrawProvider() { if constexpr (requires { T::IsDrawProvider; }) { return T::IsDrawProvider; diff --git a/include/dz/ECS/Scene.hpp b/include/dz/ECS/Scene.hpp index c480aa6a..836f3a05 100644 --- a/include/dz/ECS/Scene.hpp +++ b/include/dz/ECS/Scene.hpp @@ -1,5 +1,6 @@ #pragma once #include "Provider.hpp" +#include "../Reflectable.hpp" namespace dz::ecs { struct Scene : Provider { @@ -14,6 +15,7 @@ namespace dz::ecs { inline static constexpr size_t PID = 1; inline static float Priority = 0.5f; + inline static constexpr bool RequiresBuffer = true; inline static constexpr bool IsSceneProvider = true; inline static std::string ProviderName = "Scene"; inline static std::string StructName = "Scene"; @@ -80,7 +82,7 @@ void GetSceneModel(int scene_index, out mat4 out_model, out int parent_index, ou )"} }; - struct SceneTransformReflectable : Reflectable { + struct SceneTransformReflectable : ::Reflectable { private: std::function get_scene_function; int uid; diff --git a/include/dz/ECS/SubMesh.hpp b/include/dz/ECS/SubMesh.hpp index 615461ba..2c755895 100644 --- a/include/dz/ECS/SubMesh.hpp +++ b/include/dz/ECS/SubMesh.hpp @@ -2,6 +2,7 @@ #include "Provider.hpp" #include "Mesh.hpp" #include "Material.hpp" +#include "../Reflectable.hpp" namespace dz::ecs { inline static std::string Meshs_Str = "Meshs"; @@ -13,6 +14,7 @@ namespace dz::ecs { inline static constexpr size_t PID = 4; inline static float Priority = 0.5f; + inline static constexpr bool RequiresBuffer = true; inline static constexpr bool IsDrawProvider = true; inline static constexpr bool IsSubMeshProvider = true; inline static std::string ProviderName = "SubMesh"; @@ -32,7 +34,7 @@ struct SubMesh { return mesh.vertex_count; } - struct SubMeshReflectable : Reflectable { + struct SubMeshReflectable : ::Reflectable { private: std::function get_submesh_function; diff --git a/include/dz/Image.hpp b/include/dz/Image.hpp index 5f1221bb..0e76211c 100644 --- a/include/dz/Image.hpp +++ b/include/dz/Image.hpp @@ -9,6 +9,20 @@ namespace dz { struct Image; + + enum class SurfaceType { + BaseColor, + Diffuse, + Specular, + Normal, + Height, + AmbientOcclusion, + DiffuseRoughness, + Metalness, + Shininess, + MetalnessRoughness + }; + struct ImageCreateInfo { uint32_t width = 1; uint32_t height = 1; @@ -22,6 +36,7 @@ namespace dz VkSampleCountFlagBits multisampling = VK_SAMPLE_COUNT_1_BIT; bool is_framebuffer_attachment = false; void* data = nullptr; + SurfaceType surfaceType = SurfaceType::BaseColor; }; /** @@ -82,4 +97,9 @@ namespace dz * @returns the channels pixel stride in bytes */ size_t image_get_sizeof_channels(const std::vector& channels); + + /** + * @brief returns the underlying surface type of an Image + */ + SurfaceType image_get_surface_type(Image*); } \ No newline at end of file diff --git a/include/dz/ImagePack.hpp b/include/dz/ImagePack.hpp index af209636..8d4644ea 100644 --- a/include/dz/ImagePack.hpp +++ b/include/dz/ImagePack.hpp @@ -13,6 +13,7 @@ namespace dz { using spaces_type = rectpack2D::empty_spaces; using rect_type = rectpack2D::output_rect_t; Image* atlas = nullptr; + bool owns_atlas = true; std::vector image_vec; std::vector rect_vec; std::vector rgba_buffer; @@ -21,6 +22,8 @@ namespace dz { size_t findImageIndex(Image* image); public: + ~ImagePack(); + void SetOwnAtlas(bool owns = false); void addImage(Image* image); bool check(); Image* getAtlas(); diff --git a/include/dz/Loaders/Assimp_Loader.hpp b/include/dz/Loaders/Assimp_Loader.hpp index bb892931..07791af6 100644 --- a/include/dz/Loaders/Assimp_Loader.hpp +++ b/include/dz/Loaders/Assimp_Loader.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace dz::loaders { using MeshPair = std::pair; @@ -20,9 +21,14 @@ namespace dz::loaders { using TScale = vec; using TUV2 = vec; using TNormal = vec; + using TTangent = vec; + using TBitangent = vec; using AddSceneFunction = std::function; using AddEntityFunction = std::function; using AddMaterialFunction = std::function& )>; using AddMeshFunction = std::function&, const std::vector&, - const std::vector& + const std::vector&, + const std::vector&, + const std::vector& )>; struct Assimp_Info { ParentID parent_id = -1; @@ -52,6 +60,9 @@ namespace dz::loaders { std::filesystem::path path; std::shared_ptr bytes; size_t bytes_length = 0; + TPosition root_position = TPosition(0.0, 0.0, 0.0, 1.0); + TRotation root_rotation = TRotation(0.0, 0.0, 0.0, 1.0); + TScale root_scale = TScale(1.0, 1.0, 1.0, 1.0); }; struct Assimp_Loader { using value_type = SceneID; diff --git a/models/GoldenSportsCar.glb b/models/GoldenSportsCar.glb new file mode 100644 index 00000000..f09c25b2 Binary files /dev/null and b/models/GoldenSportsCar.glb differ diff --git a/models/SaiyanOne.glb b/models/SaiyanOne.glb index 298e35d2..d906fdf3 100644 Binary files a/models/SaiyanOne.glb and b/models/SaiyanOne.glb differ diff --git a/src/Assimp/Assimp.hpp b/src/Assimp/Assimp.hpp index 5906da97..d9377b74 100644 --- a/src/Assimp/Assimp.hpp +++ b/src/Assimp/Assimp.hpp @@ -59,6 +59,14 @@ R AssimpConvert(T val) return quat(val.w, val.x, val.y, val.z); } } + else if constexpr (std::is_same_v) { + if constexpr (std::is_same_v>) { + return vec(val.r, val.g, val.b); + } + else if constexpr (std::is_same_v>) { + return vec(val.r, val.g, val.b, val.a); + } + } R r; return r; } diff --git a/src/Directz.cpp.hpp b/src/Directz.cpp.hpp index 187a04b0..27ac5921 100644 --- a/src/Directz.cpp.hpp +++ b/src/Directz.cpp.hpp @@ -93,12 +93,21 @@ struct StateHolder { }; bool loaded = false; }; + +struct FormatsSupported { + bool R8_UNORM; + bool R8G8_UNORM; + bool R8G8B8_UNORM; + bool R8G8B8A8_UNORM; +}; + struct DirectRegistry { StateHolder stateHolder; uint8_t windowType; VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkPhysicalDeviceProperties physicalDeviceProperties; VkDevice device = VK_NULL_HANDLE; VkSurfaceFormatKHR firstSurfaceFormat = {}; VkRenderPass surfaceRenderPass = VK_NULL_HANDLE; @@ -120,6 +129,14 @@ struct DirectRegistry std::atomic window_count = 0; ImGuiLayer imguiLayer; std::queue layoutQueue; + std::unordered_map + > + > + > formats_supported_map; + FormatsSupported formats_supported; #ifdef _WIN32 HWND hwnd_root; #endif diff --git a/src/ECS/Light.cpp b/src/ECS/Light.cpp index 85c71473..a78c282b 100644 --- a/src/ECS/Light.cpp +++ b/src/ECS/Light.cpp @@ -1,25 +1,23 @@ #include #include -dz::ecs::LightMetaReflectable::LightMetaReflectable( - const std::function& get_light_function, - const std::function& reset_reflectables_function +dz::ecs::Light::LightMetaReflectable::LightMetaReflectable( + const std::function& get_light_function ): get_light_function(get_light_function), - reset_reflectables_function(reset_reflectables_function), uid(int(GlobalUID::GetNew("Reflectable"))), - name("Light Type") + name("Light Meta") {} -int dz::ecs::LightMetaReflectable::GetID() { +int dz::ecs::Light::LightMetaReflectable::GetID() { return uid; } -std::string& dz::ecs::LightMetaReflectable::GetName() { +std::string& dz::ecs::Light::LightMetaReflectable::GetName() { return name; } -void* dz::ecs::LightMetaReflectable::GetVoidPropertyByIndex(int prop_index) { +void* dz::ecs::Light::LightMetaReflectable::GetVoidPropertyByIndex(int prop_index) { auto light_ptr = get_light_function(); if (!light_ptr) return nullptr; @@ -37,7 +35,7 @@ void* dz::ecs::LightMetaReflectable::GetVoidPropertyByIndex(int prop_index) { } } -void dz::ecs::LightMetaReflectable::NotifyChange(int prop_index) { +void dz::ecs::Light::LightMetaReflectable::NotifyChange(int prop_index) { auto light_ptr = get_light_function(); if (!light_ptr) return; @@ -45,7 +43,6 @@ void dz::ecs::LightMetaReflectable::NotifyChange(int prop_index) { switch (prop_index) { default: // LightInit(light); - // reset_reflectables_function(); break; } } \ No newline at end of file diff --git a/src/ECS/Material.cpp b/src/ECS/Material.cpp index e6591cdd..053a1cf8 100644 --- a/src/ECS/Material.cpp +++ b/src/ECS/Material.cpp @@ -20,7 +20,7 @@ void* dz::ecs::Material::MaterialReflectable::GetVoidPropertyByIndex(int prop_in assert(material_ptr); auto& material = *material_ptr; switch (prop_index) { - case 0: return &material.albedo; + case 0: return &material.albedo_color; default: return nullptr; } } diff --git a/src/Image.cpp b/src/Image.cpp index fc02eb0a..a8023ff5 100644 --- a/src/Image.cpp +++ b/src/Image.cpp @@ -53,7 +53,8 @@ namespace dz { .tiling = info.tiling, .memory_properties = info.memory_properties, .multisampling = info.multisampling, - .data = info.data + .data = info.data, + .surfaceType = info.surfaceType }; return image_create_internal(internal_info); } @@ -61,7 +62,9 @@ namespace dz { void image_cpy_data(Image* image, void* data) { if (!data) return; - auto image_byte_size = image->width * image->height * image->depth * 4 * sizeof(char); + auto channels = image_get_channels_size_of_t(image); + auto pixel_stride = image_get_sizeof_channels(channels); + auto image_byte_size = image->width * image->height * image->depth * pixel_stride; image->data = std::shared_ptr(malloc(image_byte_size), free); memcpy(image->data.get(), data, image_byte_size); } @@ -77,7 +80,8 @@ namespace dz { .view_type = info.view_type, .tiling = info.tiling, .memory_properties = info.memory_properties, - .multisampling = info.multisampling + .multisampling = info.multisampling, + .surfaceType = info.surfaceType }; image_cpy_data(result, info.data); @@ -631,4 +635,8 @@ namespace dz { size += c; return size_t(size); } + + SurfaceType image_get_surface_type(Image* image_ptr) { + return image_ptr->surfaceType; + } } \ No newline at end of file diff --git a/src/Image.cpp.hpp b/src/Image.cpp.hpp index 96ae330b..3e565536 100644 --- a/src/Image.cpp.hpp +++ b/src/Image.cpp.hpp @@ -21,6 +21,7 @@ namespace dz { VkImageLayout current_layout = VK_IMAGE_LAYOUT_UNDEFINED; VkSampleCountFlagBits multisampling; std::shared_ptr data; + SurfaceType surfaceType = SurfaceType::BaseColor; }; struct ImageCreateInfoInternal @@ -36,6 +37,7 @@ namespace dz { VkMemoryPropertyFlags memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; VkSampleCountFlagBits multisampling = VK_SAMPLE_COUNT_1_BIT; void* data = nullptr; + SurfaceType surfaceType = SurfaceType::BaseColor; }; void upload_image_data(Image*); diff --git a/src/ImagePack.cpp b/src/ImagePack.cpp index 1999d083..9acdd25a 100644 --- a/src/ImagePack.cpp +++ b/src/ImagePack.cpp @@ -51,7 +51,7 @@ void dz::ImagePack::repack() if (image_vec_size > 1) { - const int max_side = 4096; + const int max_side = dr.physicalDeviceProperties.limits.maxImageDimension2D; const int discard_step = -4; auto report_successful = [](rect_type&) { return rectpack2D::callback_result::CONTINUE_PACKING; }; auto report_unsuccessful = [](rect_type&) { return rectpack2D::callback_result::ABORT_PACKING; }; @@ -234,6 +234,13 @@ size_t dz::ImagePack::findImageIndex(Image* image) else throw std::runtime_error("Image not found"); } +ImagePack::~ImagePack() { + if (owns_atlas) + image_free(atlas); +} +void ImagePack::SetOwnAtlas(bool owns) { + owns_atlas = owns; +} void dz::ImagePack::addImage(Image* image) { try diff --git a/src/Loaders/Assimp_Loader.cpp b/src/Loaders/Assimp_Loader.cpp index 77495638..c0da03fe 100644 --- a/src/Loaders/Assimp_Loader.cpp +++ b/src/Loaders/Assimp_Loader.cpp @@ -1,6 +1,7 @@ #include #include "../Assimp/Assimp.hpp" #include +#include "../Image.cpp.hpp" #include #include @@ -46,11 +47,35 @@ namespace dz::loaders::assimp_loader { } } + bool IsCombinedImage( + const aiScene* aiscene, + aiMaterial* material, + aiTextureType type_x, + aiTextureType type_y + ) { + static auto HasType = [](auto material, auto type, auto& imageIndex) -> bool { + auto count = material->GetTextureCount(type); + for (uint32_t i = 0; i < count; ++i) { + aiString str; + material->GetTexture(type, i, &str); + if (str.data[0] == '*') { + imageIndex = atoi(&str.data[1]); + return true; + } + } + return false; + }; + int32_t x_index = -1, y_index = -1; + auto has_x = HasType(material, type_x, x_index); + auto has_y = HasType(material, type_y, y_index); + return (has_x && has_y && x_index == y_index); + } + std::vector LoadMaterialImages( const aiScene *aiscene, aiMaterial *material, const aiTextureType &type, - const std::string &typeName + SurfaceType surfaceType ) { std::vector images; @@ -72,6 +97,7 @@ namespace dz::loaders::assimp_loader { .bytes = std::shared_ptr((char*)aiTex->pcData, [](auto p) {}), .bytes_length = aiTex->mWidth }); + image_ptr->surfaceType = surfaceType; } else { @@ -105,45 +131,133 @@ namespace dz::loaders::assimp_loader { mesh_indexes.push_back(pair_it->second.second); } auto& ai_mesh = context.scene_ptr->mMeshes[aiMeshIndex]; + vec albedo_color; // image data - std::vector> keyed_images; + std::vector images_vec; + MaterialPair material_pair(0, -1); if (ai_mesh->mMaterialIndex >= 0) { aiMaterial *material = context.scene_ptr->mMaterials[ai_mesh->mMaterialIndex]; std::string material_name(material->GetName().C_Str()); // Load base color (albedo) image - std::vector baseColorMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_BASE_COLOR, "baseColor"); - for (auto& image_ptr : baseColorMaps) { - keyed_images.push_back({"ColorTexture", material_name, image_ptr}); + std::vector baseColorMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_BASE_COLOR, SurfaceType::BaseColor); + auto count = 0; + for (auto& image_ptr : baseColorMaps) { + images_vec.push_back(image_ptr); + } } // Load diffuse images + { std::vector diffuseMaps; - if (!baseColorMaps.size()) + if (images_vec.empty()) { - diffuseMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_DIFFUSE, "diffuse"); - for (auto& image_ptr : diffuseMaps) + diffuseMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_DIFFUSE, SurfaceType::Diffuse); + auto count = 0; + for (auto& image_ptr : diffuseMaps) { + images_vec.push_back(image_ptr); + } + } + } + // Load specular textures + { + auto specularMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_SPECULAR, SurfaceType::Specular); + auto count = 0; + for (auto& image_ptr : specularMaps) { + images_vec.push_back(image_ptr); + } + } + // Load normal maps + { + auto normalMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_NORMALS, SurfaceType::Normal); + auto count = 0; + for (auto& image_ptr : normalMaps) { + images_vec.push_back(image_ptr); + } + } + // Load height maps + { + auto heightMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_HEIGHT, SurfaceType::Height); + auto count = 0; + for (auto& image_ptr : heightMaps) { + images_vec.push_back(image_ptr); + } + } + // Load ambient occlusion maps + { + auto aoMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_AMBIENT_OCCLUSION, SurfaceType::AmbientOcclusion); + auto count = 0; + for (auto& image_ptr : aoMaps) { + images_vec.push_back(image_ptr); + } + } + bool is_combined_metal_rough = IsCombinedImage(context.scene_ptr, material, aiTextureType_DIFFUSE_ROUGHNESS, aiTextureType_METALNESS); + if (is_combined_metal_rough) { + // Load MetalnessRoughness maps { - keyed_images.push_back({"ColorTexture", material_name, image_ptr}); + auto metalnessRoughnessMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_DIFFUSE_ROUGHNESS, SurfaceType::MetalnessRoughness); + auto count = 0; + for (auto& image_ptr : metalnessRoughnessMaps) { + images_vec.push_back(image_ptr); + } } } - } - std::vector material_indexes; - material_indexes.reserve(keyed_images.size()); - for (auto& keyed_tuple : keyed_images) { - auto material_pair = info.add_material_function(std::get<1>(keyed_tuple), std::get<2>(keyed_tuple)); - material_indexes.push_back(material_pair.second); + else { + // Load Roughness maps + { + auto roughnessMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_DIFFUSE_ROUGHNESS, SurfaceType::DiffuseRoughness); + auto count = 0; + for (auto& image_ptr : roughnessMaps) { + images_vec.push_back(image_ptr); + } + } + // Load Metal maps + { + auto metalMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_METALNESS, SurfaceType::Metalness); + auto count = 0; + for (auto& image_ptr : metalMaps) { + images_vec.push_back(image_ptr); + } + } + } + // Load Shininess maps + { + auto shininessMaps = LoadMaterialImages(context.scene_ptr, material, aiTextureType_SHININESS, SurfaceType::Shininess); + auto count = 0; + for (auto& image_ptr : shininessMaps) { + images_vec.push_back(image_ptr); + } + } + // Load Albedo Color + { + aiColor4D aicolor; + if (AI_SUCCESS == aiGetMaterialColor(material, AI_MATKEY_COLOR_DIFFUSE, &aicolor)) + { + albedo_color = AssimpConvert>(aicolor); + } + } + material_pair = info.add_material_function(material_name, images_vec); } // vertex data std::vector positions; positions.reserve(ai_mesh->mNumFaces * 3); + std::vector uv2s; uv2s.reserve(ai_mesh->mNumFaces * 3); + std::vector normals; normals.reserve(ai_mesh->mNumFaces * 3); + + std::vector tangents; + tangents.reserve(ai_mesh->mNumFaces * 3); + + std::vector bitangents; + bitangents.reserve(ai_mesh->mNumFaces * 3); + static constexpr auto i0 = 0; static constexpr auto i1 = 1; static constexpr auto i2 = 2; + // ai_mesh->mTangents for (auto fi = 0; fi < ai_mesh->mNumFaces; ++fi) { auto& face = ai_mesh->mFaces[fi]; if (face.mNumIndices == 3) { @@ -159,12 +273,17 @@ namespace dz::loaders::assimp_loader { normals.push_back(AssimpConvert>(ai_mesh->mNormals[i_0])); normals.push_back(AssimpConvert>(ai_mesh->mNormals[i_1])); normals.push_back(AssimpConvert>(ai_mesh->mNormals[i_2])); + tangents.push_back(AssimpConvert>(ai_mesh->mTangents[i_0])); + tangents.push_back(AssimpConvert>(ai_mesh->mTangents[i_1])); + tangents.push_back(AssimpConvert>(ai_mesh->mTangents[i_2])); + bitangents.push_back(AssimpConvert>(ai_mesh->mBitangents[i_0])); + bitangents.push_back(AssimpConvert>(ai_mesh->mBitangents[i_1])); + bitangents.push_back(AssimpConvert>(ai_mesh->mBitangents[i_2])); } else throw std::runtime_error("expected number of indices in face to equal 3"); } - auto material_index = material_indexes.empty() ? -1 : material_indexes[0]; - auto mesh_pair = info.add_mesh_function(ai_mesh->mName.C_Str(), material_index, positions, uv2s, normals); + auto mesh_pair = info.add_mesh_function(ai_mesh->mName.C_Str(), material_pair.second, positions, uv2s, normals, tangents, bitangents); context.mesh_index_pair_map[aiMeshIndex] = mesh_pair; mesh_indexes.push_back(mesh_pair.second); } @@ -173,7 +292,7 @@ namespace dz::loaders::assimp_loader { dz::loaders::SceneID AssimpLoad(AssimpContext& context, const Assimp_Info& info) { CountNodes(context, context.scene_ptr->mRootNode); - auto scene_id = info.add_scene_function(info.parent_id, context.scene_ptr->mName.C_Str()); + auto scene_id = info.add_scene_function(info.parent_id, context.scene_ptr->mName.C_Str(), info.root_position, info.root_rotation, info.root_scale); AddNode(context, info, context.scene_ptr->mRootNode, scene_id); return scene_id; } diff --git a/src/Loaders/STB_Image_Loader.cpp b/src/Loaders/STB_Image_Loader.cpp index 02b9e8f3..14c62c19 100644 --- a/src/Loaders/STB_Image_Loader.cpp +++ b/src/Loaders/STB_Image_Loader.cpp @@ -3,36 +3,64 @@ #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_STATIC #include +#include "../Directz.cpp.hpp" -dz::Image* STB_Image_load_rgba(const uint8_t* ptr, int width, int height) { +int STB_Image_minChannels() { + int minChannels = 4; + if (dr.formats_supported.R8G8B8A8_UNORM && dr.formats_supported.R8G8B8_UNORM && + dr.formats_supported.R8G8_UNORM && dr.formats_supported.R8_UNORM) { + minChannels = 0; + } + return minChannels; +} + +dz::Image* STB_Image_load_image(const uint8_t* ptr, int width, int height, int nrChannels) { + VkFormat format; + switch (nrChannels) { + case 1: + format = VK_FORMAT_R8_UNORM; + break; + case 2: + format = VK_FORMAT_R8G8_UNORM; + break; + case 3: + format = VK_FORMAT_R8G8B8_UNORM; + break; + case 4: + format = VK_FORMAT_R8G8B8A8_UNORM; + break; + } dz::ImageCreateInfo info{ .width = (uint32_t)width, .height = (uint32_t)height, + .format = format, .data = (void*)ptr }; return dz::image_create(info); } dz::Image* STB_Image_load_path(const std::filesystem::path& path) { + auto minChannels = STB_Image_minChannels(); int nrChannels; int width = 0, height = 0; std::string path_string = path.string(); uint8_t *imageData = stbi_load( - path_string.c_str(), &width, &height, &nrChannels, 4); + path_string.c_str(), &width, &height, &nrChannels, (std::max)(nrChannels, minChannels)); if (!imageData) throw std::runtime_error("Failed to load image from memory."); - return STB_Image_load_rgba(imageData, width, height); + return STB_Image_load_image(imageData, width, height, nrChannels); } dz::Image* STB_Image_load_bytes(const std::shared_ptr& bytes, size_t bytes_length) { + auto minChannels = STB_Image_minChannels(); int nrChannels; int width = 0, height = 0; uint8_t *imageData = stbi_load_from_memory( (stbi_uc const *)bytes.get(), - bytes_length, &width, &height, &nrChannels, 4); + bytes_length, &width, &height, &nrChannels, minChannels); if (!imageData) throw std::runtime_error("Failed to load image from memory."); - return STB_Image_load_rgba(imageData, width, height); + return STB_Image_load_image(imageData, width, height, (std::max)(nrChannels, minChannels)); } dz::Image* dz::loaders::STB_Image_Loader::Load(const dz::loaders::STB_Image_Info& info) { diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 70d3dbfa..cdcfcdb9 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -357,6 +357,94 @@ namespace dz { return VK_SAMPLE_COUNT_2_BIT; return VK_SAMPLE_COUNT_1_BIT; } + + void check_format_supported( + VkFormat format, + VkImageType imageType, + VkImageTiling imageTiling, + VkImageUsageFlags usageFlags + ) { + VkImageFormatProperties formatProps = {}; + VkResult result = vkGetPhysicalDeviceImageFormatProperties( + dr.physicalDevice, + format, + imageType, + imageTiling, + usageFlags, + 0, + &formatProps + ); + dr.formats_supported_map[format][imageType][imageTiling][usageFlags] = (result == VK_SUCCESS); + } + + void verify_format_support() + { + static VkFormat formats[] = { + VK_FORMAT_R8_UNORM, + VK_FORMAT_R8G8_UNORM, + VK_FORMAT_R8G8B8_UNORM, + VK_FORMAT_B8G8R8_UNORM, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_R16_SFLOAT, + VK_FORMAT_R16G16_SFLOAT, + VK_FORMAT_R16G16B16_SFLOAT, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT, + VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_D16_UNORM, + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT + }; + + static VkImageType types[] = { + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_3D + }; + + static VkImageTiling tilings[] = { + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_TILING_LINEAR + }; + + static VkImageUsageFlags usages[] = { + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_IMAGE_USAGE_STORAGE_BIT, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + }; + + for (VkFormat format : formats) + { + for (VkImageType type : types) + { + for (VkImageTiling tiling : tilings) + { + for (VkImageUsageFlags usage : usages) + { + check_format_supported(format, type, tiling, usage); + } + } + } + } + dr.formats_supported.R8_UNORM = dr.formats_supported_map + [VK_FORMAT_R8_UNORM][VK_IMAGE_TYPE_2D] + [VK_IMAGE_TILING_OPTIMAL][VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT]; + dr.formats_supported.R8G8_UNORM = dr.formats_supported_map + [VK_FORMAT_R8G8_UNORM][VK_IMAGE_TYPE_2D] + [VK_IMAGE_TILING_OPTIMAL][VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT]; + dr.formats_supported.R8G8B8_UNORM = dr.formats_supported_map + [VK_FORMAT_R8G8B8_UNORM][VK_IMAGE_TYPE_2D] + [VK_IMAGE_TILING_OPTIMAL][VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT]; + dr.formats_supported.R8G8B8A8_UNORM = dr.formats_supported_map + [VK_FORMAT_R8G8B8A8_UNORM][VK_IMAGE_TYPE_2D] + [VK_IMAGE_TILING_OPTIMAL][VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT]; + } + void direct_registry_ensure_physical_device(DirectRegistry* direct_registry, Renderer* renderer) { if (dr.physicalDevice) @@ -392,10 +480,10 @@ namespace dz { { throw std::runtime_error("VulkanRenderer-getPhysicalDevice: failed to find a suitable GPU!"); } - VkPhysicalDeviceProperties physicalDeviceProperties; - vkGetPhysicalDeviceProperties(dr.physicalDevice, &physicalDeviceProperties); - std::cout << "Selected Physical Device: '" << physicalDeviceProperties.deviceName + vkGetPhysicalDeviceProperties(dr.physicalDevice, &dr.physicalDeviceProperties); + std::cout << "Selected Physical Device: '" << dr.physicalDeviceProperties.deviceName << "' with score of: " << selectedDeviceScore << std::endl; + verify_format_support(); return; } uint32_t rate_device_suitability(DirectRegistry* direct_registry, Renderer* renderer, VkPhysicalDevice device) diff --git a/tests/ECS.cpp b/tests/ECS.cpp index e3e949c7..a3aa7477 100644 --- a/tests/ECS.cpp +++ b/tests/ECS.cpp @@ -12,7 +12,7 @@ struct StateSystem : Provider { virtual ~StateSystem() = default; }; -// #define ENABLE_LIGHTS +#define ENABLE_LIGHTS using ExampleECS = ECS< CID_MIN, Scene, @@ -22,7 +22,7 @@ using ExampleECS = ECS< Camera, Material #ifdef ENABLE_LIGHTS - , Light + , Light, PhongLighting #endif >; @@ -61,9 +61,6 @@ auto set_pair_id_index(auto pair, auto& id, auto& index) { using TL = TypeLoader; -std::pair AddPyramidMesh(ExampleECS& ecs, int material_index); -std::pair AddPlaneMesh(ExampleECS& ecs, int material_index); -std::pair AddCubeMesh(ExampleECS& ecs, int material_index); void RenderReflectables(ReflectableGroup& what_reflectable_group); int main() { @@ -101,52 +98,15 @@ int main() { auto& ecs = *ecs_ptr; if (!state_loaded) { - // int mat1_index = -1; - // auto mat1_id = ecs.AddMaterial(Material{}, mat1_index); - // auto im_1 = TL::Load({ - // .path = "images/hi.bmp" - // }); - // ecs.SetMaterialImage(mat1_id, im_1); - - int blue_material = -1; - auto mat2_id = ecs.AddMaterial(Material{ - .albedo = {0.0f, 0.0f, 1.0f, 1.0f} - }, blue_material); - - // auto [pyramid_mesh_id, pyramid_mesh_index] = AddPyramidMesh(ecs, blue_material); - // auto [plane_mesh_id, plane_mesh_index] = AddPlaneMesh(ecs, blue_material); - // auto [cube_mesh_id, cube_mesh_index] = AddCubeMesh(ecs, blue_material); - - // int mat3_index = -1; - // auto mat3_id = ecs.AddMaterial(Material{}, mat3_index); - // auto suzuho = TL::Load({ - // .path = "images/Suzuho-Ueda.bmp" - // }); - // ecs.SetMaterialImage(mat3_id, suzuho); - - // auto scene1_id = ecs.AddScene(Scene{}); - - // auto cam1_id = ecs.AddCamera(scene1_id, Camera{}, Camera::Perspective); - - // auto e1_id = ecs.AddEntity(scene1_id, Entity{}, {plane_mesh_index}); - // auto e2_id = ecs.AddEntity(scene1_id, Entity{ - // .position = {1.f, 1.f, 0.f, 1.f} - // }, {plane_mesh_index}); - - // auto scene2_id = ecs.AddScene(Scene{}); - - // auto cam2_id = ecs.AddCamera(scene2_id, Camera{}, Camera::Perspective); - - // auto e3_id = ecs.AddEntity(scene2_id, Entity{}, {cube_mesh_index}); - // auto e4_id = ecs.AddEntity(scene2_id, Entity{ - // .position = {-2.f, 1.f, 0.f, 1.f} - // }, {pyramid_mesh_index}); - auto cam3_id = ecs.AddCamera(Camera{}, Camera::Perspective); - TL::Load(Assimp_Info{ - .add_scene_function = [&](auto parent_id, const auto& name) { - return ecs.AddScene(parent_id, Scene{}, name); + Assimp_Info base_info{ + .add_scene_function = [&](auto parent_id, const auto& name, auto position, auto rotation, auto scale) { + return ecs.AddScene(parent_id, Scene{ + .position = position, + .rotation = rotation, + .scale = scale + }, name); }, .add_entity_function = [&](auto parent_id, const auto& name, const auto& mesh_indexes, auto position, auto rotation, auto scale) { return ecs.AddEntity(parent_id, Entity{ @@ -155,19 +115,38 @@ int main() { .scale = scale }, mesh_indexes, name); }, - .add_mesh_function = [&](const auto& name, auto material_index, const auto& positions, const auto& uv2s, const auto& normals) -> MeshPair { + .add_mesh_function = [&](const auto& name, auto material_index, const auto& positions, const auto& uv2s, const auto& normals, const auto& tangents, const auto& bitangents) -> MeshPair { int out_index = -1; - auto out_id = ecs.AddMesh(positions, uv2s, normals, material_index, out_index, name); + auto out_id = ecs.AddMesh(positions, uv2s, normals, tangents, bitangents, material_index, out_index, name); return {out_id, out_index}; }, - .add_material_function = [&](const auto& name, auto image_ptr) -> MaterialPair { + .add_material_function = [&](const auto& name, const auto& images_vec) -> MaterialPair { int out_index = -1; auto out_id = ecs.AddMaterial(Material{}, out_index); - ecs.SetMaterialImage(out_id, image_ptr); + ecs.SetMaterialImages(out_id, images_vec); return {out_id, out_index}; - }, - .path = "models/SaiyanOne.glb" - }); + } + }; + + auto saiyan_one_info = base_info; + saiyan_one_info.path = "models/SaiyanOne.glb"; + + TL::Load(saiyan_one_info); + + auto golden_sports_car_info = base_info; + golden_sports_car_info.path = "models/GoldenSportsCar.glb"; + + golden_sports_car_info.root_position[0] += 4.5f; + + TL::Load(golden_sports_car_info); + + ecs.AddLight(Light{ + .type = uint32_t(Light::Directional), + .intensity = 1.f, + .position = {0, 10, 0}, + .direction = {0, -1, 0}, + .color = {1, 1, 1} + }, "Directional Light"); } ecs.MarkReady(); @@ -483,12 +462,12 @@ int main() { ImDrawList* draw_list = ImGui::GetWindowDrawList(); static float rounding = 6.0f; - bool has_texture = !material.atlas_pack.all(-1.f); + bool has_texture = !material.albedo_atlas_pack.all(-1.f); if (has_texture) { draw_list->AddImageRounded( - (ImTextureID)material_group.frame_image_ds, + (ImTextureID)material_group.albedo_frame_image_ds, rect_min, rect_max, ImVec2(0, 0), @@ -509,10 +488,10 @@ int main() { else { ImU32 color = ImGui::ColorConvertFloat4ToU32(ImVec4( - material.albedo[0], - material.albedo[1], - material.albedo[2], - material.albedo[3] + material.albedo_color[0], + material.albedo_color[1], + material.albedo_color[2], + material.albedo_color[3] )); draw_list->AddRectFilled(rect_min, rect_max, color, rounding); @@ -870,153 +849,6 @@ void RenderReflectables(ReflectableGroup& what_reflectable_group) { } }; -std::pair AddPyramidMesh(ExampleECS& ecs, int material_index) -{ - std::vector> positions = { - // Base triangle 1 - { -1.0f, 0.0f, -1.0f, 1.0f }, - { 1.0f, 0.0f, -1.0f, 1.0f }, - { 1.0f, 0.0f, 1.0f, 1.0f }, - - // Base triangle 2 - { 1.0f, 0.0f, 1.0f, 1.0f }, - { -1.0f, 0.0f, 1.0f, 1.0f }, - { -1.0f, 0.0f, -1.0f, 1.0f }, - - // Side 1 - { 1.0f, 0.0f, -1.0f, 1.0f }, - { -1.0f, 0.0f, -1.0f, 1.0f }, - { 0.0f, 1.0f, 0.0f, 1.0f }, - - // Side 2 - { 1.0f, 0.0f, 1.0f, 1.0f }, - { 1.0f, 0.0f, -1.0f, 1.0f }, - { 0.0f, 1.0f, 0.0f, 1.0f }, - - // Side 3 - { -1.0f, 0.0f, 1.0f, 1.0f }, - { 1.0f, 0.0f, 1.0f, 1.0f }, - { 0.0f, 1.0f, 0.0f, 1.0f }, - - // Side 4 - { -1.0f, 0.0f, -1.0f, 1.0f }, - { -1.0f, 0.0f, 1.0f, 1.0f }, - { 0.0f, 1.0f, 0.0f, 1.0f } - }; - - std::vector> uv2s = { - { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 1.0f, 1.0f }, - { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 0.0f, 0.0f }, - { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.5f, 1.0f }, - { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.5f, 1.0f }, - { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.5f, 1.0f }, - { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.5f, 1.0f } - }; - - std::vector> normals = { - { 0.0f, -1.0f, 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f, 0.0f }, - { 0.0f, -1.0f, 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f, 0.0f }, - { 0.0f, 0.707f, -0.707f, 0.0f }, { 0.0f, 0.707f, -0.707f, 0.0f }, { 0.0f, 0.707f, -0.707f, 0.0f }, - { 0.707f, 0.707f, 0.0f, 0.0f }, { 0.707f, 0.707f, 0.0f, 0.0f }, { 0.707f, 0.707f, 0.0f, 0.0f }, - { 0.0f, 0.707f, 0.707f, 0.0f }, { 0.0f, 0.707f, 0.707f, 0.0f }, { 0.0f, 0.707f, 0.707f, 0.0f }, - { -0.707f, 0.707f, 0.0f, 0.0f }, { -0.707f, 0.707f, 0.0f, 0.0f }, { -0.707f, 0.707f, 0.0f, 0.0f } - }; - - int mesh_index = -1; - auto mesh_id = ecs.AddMesh(positions, uv2s, normals, material_index, mesh_index); - return { mesh_id, mesh_index }; -} - -std::pair AddCubeMesh(ExampleECS& ecs, int material_index) -{ - std::vector> positions = { - { 0.5, 0.5, 0.5, 1.0}, {-0.5, 0.5, 0.5, 1.0}, {-0.5, -0.5, 0.5, 1.0}, - {-0.5, -0.5, 0.5, 1.0}, { 0.5, -0.5, 0.5, 1.0}, { 0.5, 0.5, 0.5, 1.0}, - - {-0.5, 0.5, -0.5, 1.0}, { 0.5, 0.5, -0.5, 1.0}, { 0.5, -0.5, -0.5, 1.0}, - { 0.5, -0.5, -0.5, 1.0}, {-0.5, -0.5, -0.5, 1.0}, {-0.5, 0.5, -0.5, 1.0}, - - {-0.5, 0.5, 0.5, 1.0}, {-0.5, 0.5, -0.5, 1.0}, {-0.5, -0.5, -0.5, 1.0}, - {-0.5, -0.5, -0.5, 1.0}, {-0.5, -0.5, 0.5, 1.0}, {-0.5, 0.5, 0.5, 1.0}, - - { 0.5, 0.5, -0.5, 1.0}, { 0.5, 0.5, 0.5, 1.0}, { 0.5, -0.5, 0.5, 1.0}, - { 0.5, -0.5, 0.5, 1.0}, { 0.5, -0.5, -0.5, 1.0}, { 0.5, 0.5, -0.5, 1.0}, - - { 0.5, 0.5, -0.5, 1.0}, {-0.5, 0.5, -0.5, 1.0}, {-0.5, 0.5, 0.5, 1.0}, - {-0.5, 0.5, 0.5, 1.0}, { 0.5, 0.5, 0.5, 1.0}, { 0.5, 0.5, -0.5, 1.0}, - - { 0.5, -0.5, 0.5, 1.0}, {-0.5, -0.5, 0.5, 1.0}, {-0.5, -0.5, -0.5, 1.0}, - {-0.5, -0.5, -0.5, 1.0}, { 0.5, -0.5, -0.5, 1.0}, { 0.5, -0.5, 0.5, 1.0} - }; - - std::vector> uv2s = { - {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0}, - {0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, - - {0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, - {1.0, 0.0}, {0.0, 0.0}, {0.0, 1.0}, - - {0.0, 1.0}, {0.0, 1.0}, {0.0, 0.0}, - {0.0, 0.0}, {0.0, 0.0}, {0.0, 1.0}, - - {1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, - {1.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, - - {1.0, 1.0}, {0.0, 1.0}, {0.0, 1.0}, - {0.0, 1.0}, {1.0, 1.0}, {1.0, 1.0}, - - {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, - {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0} - }; - - std::vector> normals = { - {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, - {0, 0, -1, 0}, {0, 0, -1, 0}, {0, 0, -1, 0}, {0, 0, -1, 0}, {0, 0, -1, 0}, {0, 0, -1, 0}, - {-1, 0, 0, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, - {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, - {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, - {0, -1, 0, 0}, {0, -1, 0, 0}, {0, -1, 0, 0}, {0, -1, 0, 0}, {0, -1, 0, 0}, {0, -1, 0, 0} - }; - - int mesh_index = -1; - auto mesh_id = ecs.AddMesh(positions, uv2s, normals, material_index, mesh_index); - return { mesh_id, mesh_index }; -} - -std::pair AddPlaneMesh(ExampleECS& ecs, int material_index) -{ - std::vector> positions = { - { 0.5, 0.5, 0, 1}, - {-0.5, 0.5, 0, 1}, - {-0.5, -0.5, 0, 1}, - {-0.5, -0.5, 0, 1}, - { 0.5, -0.5, 0, 1}, - { 0.5, 0.5, 0, 1} - }; - - std::vector> uv2s = { - {1.0, 0.0}, - {0.0, 0.0}, - {0.0, 1.0}, - {0.0, 1.0}, - {1.0, 1.0}, - {1.0, 0.0} - }; - - std::vector> normals = { - {0.0, 0.0, 1.0, 1}, - {0.0, 0.0, 1.0, 1}, - {0.0, 0.0, 1.0, 1}, - {0.0, 0.0, 1.0, 1}, - {0.0, 0.0, 1.0, 1}, - {0.0, 0.0, 1.0, 1} - }; - - int mesh_index = -1; - auto mesh_id = ecs.AddMesh(positions, uv2s, normals, material_index, mesh_index); - return { mesh_id, mesh_index }; -} - // void DrawEntityGroup(ExampleECS& ecs, int id, ExampleECS::EntityReflectableGroup& entity_group) // { // ImGui::TableNextRow(); @@ -1402,7 +1234,7 @@ void DrawWindowGroup(const std::string& window_name, WindowReflectableGroup& win ImGui::PopID(); } -bool ReflectableGroupFilterCheck(ImGuiTextFilter& SceneGraphFilter, ReflectableGroup& reflectable_group) { +bool ReflectableGroupFilterCheck(ImGuiTextFilter& SceneGraphFilter, ::ReflectableGroup& reflectable_group) { auto initial = SceneGraphFilter.PassFilter(reflectable_group.GetName().c_str()); if (initial) return true;