diff --git a/Tests.cmake b/Tests.cmake index 3f06e075..c3daafe5 100644 --- a/Tests.cmake +++ b/Tests.cmake @@ -41,4 +41,6 @@ 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) -file(COPY models/GoldenSportsCar.glb DESTINATION ${CMAKE_BINARY_DIR}/models) \ No newline at end of file +file(COPY models/GoldenSportsCar.glb DESTINATION ${CMAKE_BINARY_DIR}/models) +file(COPY hdri/autumn_field_puresky_4k.hdr DESTINATION ${CMAKE_BINARY_DIR}/hdri) +file(COPY hdri/zwartkops_straight_afternoon_4k.hdr DESTINATION ${CMAKE_BINARY_DIR}/hdri) \ No newline at end of file diff --git a/hdri/autumn_field_puresky_4k.hdr b/hdri/autumn_field_puresky_4k.hdr new file mode 100644 index 00000000..494be719 Binary files /dev/null and b/hdri/autumn_field_puresky_4k.hdr differ diff --git a/hdri/zwartkops_straight_afternoon_4k.hdr b/hdri/zwartkops_straight_afternoon_4k.hdr new file mode 100644 index 00000000..dc6e39b5 Binary files /dev/null and b/hdri/zwartkops_straight_afternoon_4k.hdr differ diff --git a/include/dz/BlendState.hpp b/include/dz/BlendState.hpp new file mode 100644 index 00000000..0f758039 --- /dev/null +++ b/include/dz/BlendState.hpp @@ -0,0 +1,51 @@ +#pragma once + +namespace dz { + enum class BlendFactor + { + Zero = 0, + One = 1, + SrcColor = 2, + OneMinusSrcColor = 3, + DstColor = 4, + OneMinusDstColor = 5, + SrcAlpha = 6, + OneMinusSrcAlpha = 7, + DstAlpha = 8, + OneMinusDstAlpha = 9, + ConstantColor = 10, + OneMinusConstantColor = 11, + ConstantAlpha = 12, + OneMinusConstantAlpha = 13, + SrcAlphaSaturate = 14, + Src1Color = 15, + OneMinusSrc1Color = 16, + Src1Alpha = 17, + OneMinusSrc1Alpha = 18 + }; + + enum class BlendOp + { + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4 + }; + + struct BlendState + { + bool enable = true; + BlendFactor srcColor = BlendFactor::SrcAlpha; + BlendFactor dstColor = BlendFactor::OneMinusSrcColor; + BlendFactor srcAlpha = BlendFactor::SrcAlpha; + BlendFactor dstAlpha = BlendFactor::OneMinusSrcAlpha; + BlendOp colorOp = BlendOp::Add; + BlendOp alphaOp = BlendOp::Add; + static BlendState Disabled; + static BlendState MainFramebuffer; + static BlendState Layout; + static BlendState Text; + static BlendState SrcAlpha; + }; +} \ No newline at end of file diff --git a/include/dz/DrawList.hpp b/include/dz/DrawList.hpp index 9886452a..a7619a51 100644 --- a/include/dz/DrawList.hpp +++ b/include/dz/DrawList.hpp @@ -48,9 +48,9 @@ namespace dz // using FramebufferDrawList = std::unordered_map; /** - * @brief A DrawTuples is the information required to produce a DrawList in a DrawListManager + * @brief A DrawTuple is the information required to produce a DrawList in a DrawListManager */ - using DrawTuples = std::vector>; + using DrawTuple = std::tuple; /** * @brief A CameraTuple is the information required to draw from a cameras perspective diff --git a/include/dz/DrawListManager.hpp b/include/dz/DrawListManager.hpp index ac3d1b1e..76916722 100644 --- a/include/dz/DrawListManager.hpp +++ b/include/dz/DrawListManager.hpp @@ -36,11 +36,11 @@ namespace dz template struct DrawListManager : IDrawListManager { - using Determine_DrawT_DrawTuples_Function = std::function; + using Determine_DrawT_DrawTuple_Function = std::function; using Determine_CameraTuple_Function = std::function; using Determine_VisibleDraws_Function = std::function(BufferGroup*, int camera_index)>; private: - Determine_DrawT_DrawTuples_Function fn_determine_DrawT_DrawTuples; + Determine_DrawT_DrawTuple_Function fn_determine_DrawT_DrawTuple; Determine_CameraTuple_Function fn_determine_CameraTuple; Determine_VisibleDraws_Function fn_get_visible_draws; std::string draw_key; @@ -54,15 +54,15 @@ namespace dz * @brief Constructs a DrawListManager with a draw key and logic function. * * @param draw_key Buffer key to iterate over. - * @param fn_determine_DrawT_DrawTuples Function that maps a DrawT instance to shader and vertex count. + * @param fn_determine_DrawT_DrawTuple Function that maps a DrawT instance to shader and vertex count. */ DrawListManager( - const std::string& draw_key, const Determine_DrawT_DrawTuples_Function& fn_determine_DrawT_DrawTuples, + const std::string& draw_key, const Determine_DrawT_DrawTuple_Function& fn_determine_DrawT_DrawTuple, const std::string& camera_key = "", const Determine_CameraTuple_Function& fn_determine_CameraTuple = {}, const Determine_VisibleDraws_Function& fn_get_visible_draws = {}, bool enable_global_camera_if_cameras_empty = true ): - fn_determine_DrawT_DrawTuples(fn_determine_DrawT_DrawTuples), + fn_determine_DrawT_DrawTuple(fn_determine_DrawT_DrawTuple), fn_determine_CameraTuple(fn_determine_CameraTuple), draw_key(draw_key), camera_key(camera_key), @@ -128,15 +128,10 @@ namespace dz drawInformation.cameraDrawInfos.push_back(cameraDrawInfo); } - auto drawTuplesMatch = [](const auto& a, const auto& b) -> bool + auto drawTupleMatch = [](const auto& a, const auto& b) -> bool { - if (a.size() != b.size()) + if (std::get<0>(a) != std::get<0>(b) || std::get<1>(a) != std::get<1>(b)) return false; - for (size_t k = 0; k < a.size(); ++k) - { - if (std::get<0>(a[k]) != std::get<0>(b[k]) || std::get<1>(a[k]) != std::get<1>(b[k])) - return false; - } return true; }; @@ -154,7 +149,7 @@ namespace dz auto element_view = buffer_group_get_buffer_element_view(buffer_group, draw_key, i); auto& element = element_view.template as_struct(); - auto draw_tuples = fn_determine_DrawT_DrawTuples(buffer_group, element); + auto draw_tuple = fn_determine_DrawT_DrawTuple(buffer_group, element); uint32_t run_start = static_cast(i); uint32_t instance_count = 1; @@ -166,25 +161,24 @@ namespace dz j = visible_entity_indices_data[vj]; auto next_element_view = buffer_group_get_buffer_element_view(buffer_group, draw_key, j); auto& next_element = next_element_view.template as_struct(); - auto next_draw_tuples = fn_determine_DrawT_DrawTuples(buffer_group, next_element); + auto next_draw_tuple = fn_determine_DrawT_DrawTuple(buffer_group, next_element); - if (!drawTuplesMatch(draw_tuples, next_draw_tuples)) + if (!drawTupleMatch(draw_tuple, next_draw_tuple)) break; instance_count += 1; vj += 1; } - for (auto& [shader, vertexCount] : draw_tuples) - { - DrawIndirectCommand cmd; - cmd.vertexCount = vertexCount; - cmd.instanceCount = instance_count; - cmd.firstVertex = 0; - cmd.firstInstance = run_start; + auto& [shader, vertexCount] = draw_tuple; + + DrawIndirectCommand cmd; + cmd.vertexCount = vertexCount; + cmd.instanceCount = instance_count; + cmd.firstVertex = 0; + cmd.firstInstance = run_start; - cameraDrawInfo.shaderDrawList[shader].push_back(cmd); - } + cameraDrawInfo.shaderDrawList[shader].push_back(cmd); vi = vj; } diff --git a/include/dz/ECS.hpp b/include/dz/ECS.hpp index a098f333..3d7e3911 100644 --- a/include/dz/ECS.hpp +++ b/include/dz/ECS.hpp @@ -12,12 +12,15 @@ #include "ECS/Provider.hpp" #include "ECS/Light.hpp" #include "ECS/PhongLighting.hpp" +#include "ECS/PhysicallyBasedLighting.hpp" #include "ECS/Scene.hpp" #include "ECS/Entity.hpp" #include "ECS/Mesh.hpp" #include "ECS/SubMesh.hpp" #include "ECS/Camera.hpp" #include "ECS/Material.hpp" +#include "ECS/HDRI.hpp" +#include "ECS/SkyBox.hpp" #include "ImagePack.hpp" #include #include @@ -27,6 +30,7 @@ #include #include #include +#include namespace dz { @@ -37,6 +41,7 @@ namespace dz { 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 HDRIAtlas_Str = "HDRIAtlas"; inline static std::string VertexPositions_Str = "VertexPositions"; inline static std::string VertexUV2s_Str = "VertexUV2s"; inline static std::string VertexNormals_Str = "VertexNormals"; @@ -70,9 +75,10 @@ namespace dz { std::string buffer_name; std::string sparse_name; std::string glsl_struct; - bool requires_buffer; + BufferHost buffer_host_type; std::unordered_map glsl_methods; std::unordered_map> glsl_layouts; + std::vector glsl_bindings; std::string glsl_main; bool is_component = false; int component_id = 0; @@ -94,6 +100,7 @@ namespace dz { std::vector> reflectable_group_root_vector; // Y std::vector> material_group_vector; // Y + std::vector> hdri_group_vector; // Y std::vector> mesh_group_vector; // Y std::map> pid_reflectable_vecs; // ! std::unordered_map> pid_id_index_maps; // ! @@ -111,6 +118,7 @@ namespace dz { MetalnessAtlas_Str, MetalnessRoughnessAtlas_Str, ShininessAtlas_Str, + HDRIAtlas_Str, VertexPositions_Str, VertexUV2s_Str, VertexNormals_Str, @@ -127,15 +135,22 @@ namespace dz { using SceneProviderT = typename FirstMatchingOrDefault::type; using MaterialProviderT = typename FirstMatchingOrDefault::type; using MeshProviderT = typename FirstMatchingOrDefault::type; + using HDRIProviderT = typename FirstMatchingOrDefault::type; + using SkyBoxProviderT = typename FirstMatchingOrDefault::type; + DrawListManager skybox_mg; // ! DrawListManager draw_mg; // ! BufferGroup* buffer_group = nullptr; // ! bool buffer_initialized = false; // ! int buffer_size = 0; // ! + std::unordered_map cpu_buffers; // Y Shader* main_shader = nullptr; // ! + Shader* skybox_shader = nullptr; // ! Shader* model_compute_shader = nullptr; // ! Shader* camera_mat_compute_shader = nullptr; // ! + std::vector raster_shaders; + std::vector compute_shaders; bool material_browser_open = true; @@ -146,12 +161,76 @@ namespace dz { ImagePack metalness_atlas_pack; ImagePack metalness_roughness_atlas_pack; ImagePack shininess_atlas_pack; + ImagePack hdri_atlas_pack; - auto GenerateEntitysDrawFunction() { - return [&](auto buffer_group, auto& draw_object) -> DrawTuples { - return { - {main_shader, draw_object.GetVertexCount(buffer_group, draw_object)} + auto GenerateSkyBoxDrawFunction() { + return [&](auto buffer_group, auto& skybox) -> DrawTuple { + return { skybox_shader, 36 }; + }; + } + auto GenerateSkyBoxCamerasDrawFunction() { + return [&](auto buffer_group, auto camera_index) -> CameraTuple { + auto& camera_group = GetGroupByIndex(camera_index); + auto& camera = GetCamera(camera_group.id); + return {camera_index, camera_group.framebuffer, [&, camera_index]() { + shader_update_push_constant(skybox_shader, 0, (void*)&camera_index, sizeof(uint32_t)); + }, !camera.is_active}; + }; + } + auto GenerateSkyBoxCameraVisibilityFunction() { + return [&](auto buffer_group, auto camera_index) -> std::vector { + std::vector visible; + auto& camera_group = GetGroupByIndex(camera_index); + auto current_parent_group_ptr = camera_group.parent_ptr; + while (current_parent_group_ptr) { + auto scene_group_ptr = dynamic_cast(current_parent_group_ptr); + if (scene_group_ptr) { + break; + } + current_parent_group_ptr = current_parent_group_ptr->parent_ptr; + } + auto visible_from_node_ptr = (current_parent_group_ptr) ? + ¤t_parent_group_ptr->GetChildren() : + &reflectable_group_root_vector; + + std::function&, const std::vector>*, int)> add_child_entries; + + add_child_entries = [&](auto& visible, auto node_ptr, auto scenes_hit) { + for (auto& ref_group_sh_ptr : *node_ptr) { + auto ref_group_ptr = ref_group_sh_ptr.get(); + assert(ref_group_ptr); + auto e_group_ptr = dynamic_cast(ref_group_ptr); + if (e_group_ptr) { + add_child_entries(visible, &ref_group_ptr->GetChildren(), scenes_hit); + continue; + } + auto s_group_ptr = dynamic_cast(ref_group_ptr); + if (s_group_ptr && !scenes_hit) { + add_child_entries(visible, &ref_group_ptr->GetChildren(), scenes_hit + 1); + continue; + } + auto c_group_ptr = dynamic_cast(ref_group_ptr); + if (c_group_ptr) { + // do nothing for now (and ever?) + continue; + } + auto b_group_ptr = dynamic_cast(ref_group_ptr); + if (b_group_ptr) { + visible.push_back(b_group_ptr->index); + continue; + } + } }; + + add_child_entries(visible, visible_from_node_ptr, 0); + + return visible; + }; + } + + auto GenerateEntitysDrawFunction() { + return [&](auto buffer_group, auto& draw_object) -> DrawTuple { + return { main_shader, draw_object.GetVertexCount(buffer_group) }; }; } @@ -232,9 +311,31 @@ namespace dz { return out_string; } + void Initialize() { + RegisterProviders(); + buffer_group = CreateBufferGroup(); + assert(buffer_group); + + main_shader = GenerateMainShader(); + + skybox_shader = GenerateSkyBoxShader(); + + model_compute_shader = GenerateModelComputeShader(); + + camera_mat_compute_shader = GenerateCameraMatComputeShader(); + + EnableDrawInWindow(window_ptr); + } + ECS(Serial& serial): buffer_name(FindBufferNameFromProviders()), window_ptr(state_get_ptr(CID_WINDOW)), + skybox_mg( + buffer_name, GenerateSkyBoxDrawFunction(), + Cameras_Str, GenerateSkyBoxCamerasDrawFunction(), + GenerateSkyBoxCameraVisibilityFunction(), + false + ), draw_mg( buffer_name, GenerateEntitysDrawFunction(), Cameras_Str, GenerateCamerasDrawFunction(), @@ -242,20 +343,19 @@ namespace dz { false ) { - RegisterProviders(); - buffer_group = CreateBufferGroup(); - assert(buffer_group); - main_shader = GenerateMainShader(); - model_compute_shader = GenerateModelComputeShader(); - camera_mat_compute_shader = GenerateCameraMatComputeShader(); - EnableDrawInWindow(window_ptr); + Initialize(); restore(serial); - loaded_from_io = true; } ECS(WINDOW* initial_window_ptr): buffer_name(FindBufferNameFromProviders()), window_ptr(initial_window_ptr), + skybox_mg( + buffer_name, GenerateSkyBoxDrawFunction(), + Cameras_Str, GenerateSkyBoxCamerasDrawFunction(), + GenerateSkyBoxCameraVisibilityFunction(), + false + ), draw_mg( buffer_name, GenerateEntitysDrawFunction(), Cameras_Str, GenerateCamerasDrawFunction(), @@ -263,18 +363,13 @@ namespace dz { false ) { - RegisterProviders(); - buffer_group = CreateBufferGroup(); - assert(buffer_group); - main_shader = GenerateMainShader(); - model_compute_shader = GenerateModelComputeShader(); - camera_mat_compute_shader = GenerateCameraMatComputeShader(); - EnableDrawInWindow(window_ptr); + Initialize(); } void UseAtlas(auto& pack, auto& str) { auto atlas = pack.getAtlas(); shader_use_image(main_shader, str, atlas); + shader_use_image(skybox_shader, str, atlas); shader_use_image(model_compute_shader, str, atlas); shader_use_image(camera_mat_compute_shader, str, atlas); } @@ -287,6 +382,8 @@ namespace dz { UseAtlas(metalness_atlas_pack, MetalnessAtlas_Str); UseAtlas(metalness_roughness_atlas_pack, MetalnessRoughnessAtlas_Str); UseAtlas(shininess_atlas_pack, ShininessAtlas_Str); + UpdateHDRIAtlas(); + UseAtlas(hdri_atlas_pack, HDRIAtlas_Str); if (!buffer_initialized) { buffer_group_initialize(buffer_group); buffer_initialized = true; @@ -329,6 +426,19 @@ namespace dz { } } + void UpdateHDRIAtlas() { + hdri_atlas_pack.check(); + for (auto& hdri_group_sh_ptr : hdri_group_vector) { + auto generic_group_ptr = hdri_group_sh_ptr.get(); + auto hdri_group_ptr = dynamic_cast(generic_group_ptr); + auto& hdri_group = *hdri_group_ptr; + auto& hdri = GetHDRI(hdri_group.id); + // + UpdatePackedRect(hdri_group.hdri_image, hdri_atlas_pack, hdri.hdri_atlas_pack); + continue; + } + } + bool backup(Serial& serial) override { std::lock_guard lock(e_mutex); if (!serial.canWrite()) @@ -339,6 +449,8 @@ namespace dz { return false; if (!BackupGroupVector(serial, material_group_vector)) return false; + if (!BackupGroupVector(serial, hdri_group_vector)) + return false; if (!BackupGroupVector(serial, mesh_group_vector)) return false; if (!BackupBuffers(serial)) @@ -360,6 +472,8 @@ namespace dz { return false; if (!RestoreGroupVector(serial, material_group_vector, buffer_group)) return false; + if (!RestoreGroupVector(serial, hdri_group_vector, buffer_group)) + return false; if (!RestoreGroupVector(serial, mesh_group_vector, buffer_group)) return false; if (!EnsureGroupVectorParentPtrs(reflectable_group_root_vector, nullptr)) @@ -367,7 +481,7 @@ namespace dz { if (!RestoreBuffers(serial)) return false; UpdateGroupsChildren(); - return true; + return (loaded_from_io = true); } bool Backup_pid_reflectable_vecs_sizes(Serial& serial) { @@ -425,7 +539,7 @@ namespace dz { if (pid == cam_pid) { auto cam_ptr = dynamic_cast(ptr); assert(cam_ptr); - cam_ptr->InitFramebuffer(main_shader, width, height); + cam_ptr->InitFramebuffer(raster_shaders, width, height); cam_ptr->update_draw_list_fn = [&]() { draw_mg.MarkDirty(); }; @@ -491,8 +605,9 @@ namespace dz { auto& glsl_struct = TProvider::GetGLSLStruct(); auto& glsl_methods = TProvider::GetGLSLMethods(); auto& glsl_layouts = TProvider::GetGLSLLayouts(); + auto& glsl_bindings = TProvider::GetGLSLBindings(); auto& priority_glsl_main = TProvider::GetGLSLMain(); - constexpr auto requires_buffer = TProvider::GetRequiresBuffer(); + constexpr auto buffer_host_type = TProvider::GetBufferHostType(); constexpr auto pid = TProvider::GetPID(); prioritized_provider_ids[priority].push_back(pid); auto provider_index = pid_provider_groups.size(); @@ -505,8 +620,9 @@ namespace dz { provider_group.glsl_struct = glsl_struct; provider_group.glsl_methods = glsl_methods; provider_group.glsl_layouts = glsl_layouts; + provider_group.glsl_bindings = glsl_bindings; provider_group.is_component = TProvider::GetIsComponent(); - provider_group.requires_buffer = requires_buffer; + provider_group.buffer_host_type = buffer_host_type; for (auto& [main_priority, main_string, module_type] : priority_glsl_main) { priority_glsl_mains[module_type][main_priority].push_back(main_string); } @@ -556,14 +672,58 @@ namespace dz { return dynamic_cast(*children[index]); } - template + template + uint32_t xpu_group_get_buffer_element_count(const std::string& buffer_name, bool cpu) { + if (cpu) { + auto& buffer_any = cpu_buffers[buffer_name]; + if (buffer_any.type() != typeid(std::vector)) + return 0; + return std::any_cast&>(buffer_any).size(); + } + else { + return buffer_group_get_buffer_element_count(buffer_group, buffer_name); + } + } + + template + void xpu_group_set_buffer_element_count(const std::string& buffer_name, uint32_t element_count, bool cpu) { + if (cpu) { + auto& buffer_any = cpu_buffers[buffer_name]; + if (buffer_any.type() != typeid(std::vector)) { + buffer_any = std::vector{}; + } + auto& buffer_vec = std::any_cast&>(buffer_any); + buffer_vec.resize(element_count); + } + else { + buffer_group_set_buffer_element_count(buffer_group, buffer_name, element_count); + } + } + + template + std::shared_ptr xpu_group_get_buffer_data_ptr(const std::string& buffer_name, bool cpu) { + if (cpu) { + auto& buffer_any = cpu_buffers[buffer_name]; + if (buffer_any.type() != typeid(std::vector)) + return 0; + auto& buffer_vec = std::any_cast&>(buffer_any); + auto data = (uint8_t*)(buffer_vec.data()); + return std::shared_ptr(data, [](auto ptr){}); + } + else { + return buffer_group_get_buffer_data_ptr(buffer_group, buffer_name); + } + } + + template void AddProviderSingle( int parent_id, size_t& id, - const TData& data, + const TData& new_data, std::vector>& reflectable_group_vector, int& out_index, - const std::string& name = "" + const std::string& name, + const Args&... args ) { if (id) return; @@ -597,8 +757,10 @@ namespace dz { auto& provider_group = pid_provider_groups[pid]; id = ecs_id; + + constexpr auto cpu = (TProvider::GetBufferHostType() == BufferHost::CPU); - auto provider_index = buffer_group_get_buffer_element_count(buffer_group, provider_group.buffer_name); + auto provider_index = xpu_group_get_buffer_element_count(provider_group.buffer_name, cpu); auto& prov_ptr_vec = pid_reflectable_vecs[pid]; assert(provider_index == prov_ptr_vec.size()); @@ -611,13 +773,15 @@ namespace dz { if (provider_group.buffer_name == buffer_name) Resize(provider_index + 1); else - buffer_group_set_buffer_element_count(buffer_group, provider_group.buffer_name, provider_index + 1); + xpu_group_set_buffer_element_count(provider_group.buffer_name, provider_index + 1, cpu); - auto buffer = buffer_group_get_buffer_data_ptr(buffer_group, provider_group.buffer_name); + auto buffer = xpu_group_get_buffer_data_ptr(provider_group.buffer_name, cpu); auto data_ptr = ((TData*)(buffer.get())); - data_ptr[provider_index] = data; + data_ptr[provider_index] = new_data; + + auto& data = data_ptr[provider_index]; auto parent_group_ptr = FindParentGroupPtr(parent_id); @@ -634,28 +798,27 @@ namespace dz { sparse_ptr[parent_entity_group.index] = provider_index; } - group.UpdateChildren(); - if (parent_id != -1) { auto& parent_group = GetGenericGroupByID(parent_id); - if constexpr (std::is_same_v) { - auto& entity = GetEntity(id); - SetWhoParent(entity, &parent_group); - } - if constexpr (std::is_same_v) { - auto& camera = GetCamera(id); - SetWhoParent(camera, &parent_group); - } - if constexpr (std::is_same_v) { - auto& scene = GetScene(id); - SetWhoParent(scene, &parent_group); - } - if constexpr (std::is_same_v) { - auto& submesh = GetSubMesh(id); - SetWhoParent(submesh, &parent_group); - } + if constexpr (std::is_same_v) + SetWhoParent(GetEntity(id), &parent_group); + if constexpr (std::is_same_v) + SetWhoParent(GetCamera(id), &parent_group); + if constexpr (std::is_same_v) + SetWhoParent(GetScene(id), &parent_group); + if constexpr (std::is_same_v) + SetWhoParent(GetSubMesh(id), &parent_group); + if constexpr (std::is_same_v) + SetWhoParent(GetSkyBox(id), &parent_group); } + if constexpr (requires { data.Initialize(*this, group); }) + data.Initialize(*this, group); + else if constexpr (requires { data.Initialize(); }) + data.Initialize(); + + group.UpdateChildren(); + if constexpr (std::is_same_v || std::is_same_v) { MarkDirty(); } @@ -672,7 +835,7 @@ namespace dz { const TData& data, std::vector>& reflectable_group_vector, int& out_index, - const std::string& name = "" + const std::string& name ) { size_t id = 0; (AddProviderSingle(parent_id, id, data, reflectable_group_vector, out_index, name), ...); @@ -682,7 +845,7 @@ namespace dz { } template - int AddEntity(int parent_id, const TEntity& entity_data, const std::vector& mesh_indexes, const std::string& name = "") { + int AddEntity(int parent_id, const TEntity& entity_data, const std::vector& mesh_indexes, const std::string& name) { auto parent_group_ptr = FindParentGroupPtr(parent_id); int out_index = -1; auto entity_id = AddProvider(parent_id, entity_data, @@ -702,12 +865,12 @@ namespace dz { } template - int AddEntity(const TEntity& entity_data, const std::vector& mesh_indexes, const std::string& name = "") { + int AddEntity(const TEntity& entity_data, const std::vector& mesh_indexes, const std::string& name) { return AddEntity(-1, entity_data, mesh_indexes, name); } template - int AddScene(int parent_id, const TScene& scene_data, const std::string& name = "") { + int AddScene(int parent_id, const TScene& scene_data, const std::string& name) { auto parent_group_ptr = FindParentGroupPtr(parent_id); int out_index = -1; return AddProvider(parent_id, scene_data, @@ -715,7 +878,7 @@ namespace dz { } template - int AddScene(const TScene& scene_data, const std::string& name = "") { + int AddScene(const TScene& scene_data, const std::string& name) { return AddScene(-1, scene_data, name); } @@ -724,7 +887,7 @@ namespace dz { } template - int AddMaterial(const TMaterial& material_data, int& out_index, const std::string& name = "") { + int AddMaterial(const TMaterial& material_data, int& out_index, const std::string& name) { return AddProvider(-1, material_data, material_group_vector, out_index, name); } @@ -777,6 +940,26 @@ namespace dz { UpdateAtlases(); } + template + int AddHDRI(const THDRI& hdri_data, int& out_index, const std::string& name) { + return AddProvider(-1, hdri_data, hdri_group_vector, out_index, name); + } + + HDRIProviderT& GetHDRI(size_t hdri_id) { + return GetProviderData(hdri_id); + } + + void SetHDRIImage(size_t hdri_id, Image* image_ptr) { + auto& hdri_group = GetGroupByID(hdri_id); + + hdri_group.hdri_image = image_ptr; + hdri_group.hdri_frame_image_ds = image_create_descriptor_set(image_ptr).second; + hdri_atlas_pack.addImage(image_ptr); + + if (buffer_initialized) + UpdateHDRIAtlas(); + } + int AddMesh( const std::vector>& positions, const std::vector>& uv2s, @@ -785,7 +968,7 @@ namespace dz { const std::vector>& bitangents, int material_index, int& out_index, - const std::string& name = "" + const std::string& name ) { MeshProviderT mesh_data; auto position_index = buffer_group_get_buffer_element_count(buffer_group, VertexPositions_Str); @@ -861,7 +1044,7 @@ namespace dz { } template - int AddLight(int parent_id, const TLight& light_data, const std::string& name = "") { + 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, @@ -869,10 +1052,27 @@ namespace dz { } template - int AddLight(const TLight& light_data, const std::string& name = "") { + int AddLight(const TLight& light_data, const std::string& name) { return AddLight(-1, light_data, name); } + template + int AddSkyBox(int parent_id, const TSkyBox& skybox_data, const std::string& name) { + auto parent_group_ptr = FindParentGroupPtr(parent_id); + int out_index = -1; + return AddProvider(parent_id, skybox_data, + parent_group_ptr ? parent_group_ptr->GetChildren() : reflectable_group_root_vector, out_index, name); + } + + template + int AddSkyBox(const TSkyBox& skybox_data, const std::string& name) { + return AddSkyBox(-1, skybox_data, name); + } + + SkyBoxProviderT& GetSkyBox(size_t skybox_id) { + return GetProviderData(skybox_id); + } + ReflectableGroup& GetGenericGroupByID(size_t id) { auto ptr = FindParentGroupPtr(id); if (ptr) @@ -962,41 +1162,33 @@ namespace dz { } template - int AddCamera(size_t parent_id, const TCamera& camera_data, TCamera::ProjectionType projectionType, const std::string& name = "") { + int AddCamera(size_t parent_id, const TCamera& camera_data, const std::string& name) { + auto new_data = camera_data; + auto width = *window_get_width_ref(window_ptr); + auto height = *window_get_height_ref(window_ptr); + if (new_data.width == 0 || new_data.height == 0) { + new_data.width = width; + new_data.height = height; + } auto parent_group_ptr = FindParentGroupPtr(parent_id); int out_index = -1; - auto camera_id = AddProvider(parent_id, camera_data, + auto camera_id = AddProvider(parent_id, new_data, parent_group_ptr ? parent_group_ptr->GetChildren() : reflectable_group_root_vector, out_index, name); - auto& camera = GetCamera(camera_id); auto& camera_group = GetGroupByID(camera_id); camera_group.update_draw_list_fn = [&]() { draw_mg.MarkDirty(); }; - auto& width = *window_get_width_ref(window_ptr); - auto& height = *window_get_height_ref(window_ptr); - // Initialize camera matrices - { - switch(projectionType) { - case TCamera::Perspective: - CameraInit(camera, {0, 0, 10}, {0, 0, 0}, {0, 1, 0}, 0.25f, 1000.f, width, height, radians(81.f)); - break; - case TCamera::Orthographic: - CameraInit(camera, {0, 0, 10}, {0, 0, 0}, {0, 1, 0}, 0.25f, 1000.f, vec(0, 0, width, height)); - break; - } - } - camera_group.NotifyNameChanged(); - camera_group.InitFramebuffer(main_shader, width, height); + camera_group.InitFramebuffer(raster_shaders, width, height); return camera_id; } template - int AddCamera(const TCamera& camera_data, TCamera::ProjectionType projectionType, const std::string& name = "") { - return AddCamera(-1, camera_data, projectionType, name); + int AddCamera(const TCamera& camera_data, const std::string& name) { + return AddCamera(-1, camera_data, name); } CameraProviderT& GetCamera(size_t camera_id) { @@ -1066,6 +1258,25 @@ namespace dz { shader_add_module(shader_ptr, ShaderModuleType::Vertex, GenerateMainVertexShaderCode()); shader_add_module(shader_ptr, ShaderModuleType::Fragment, GenerateMainFragmentShaderCode()); + raster_shaders.push_back(shader_ptr); + return shader_ptr; + } + + Shader* GenerateSkyBoxShader() { + auto shader_ptr = shader_create(); + + shader_add_buffer_group(shader_ptr, buffer_group); + + shader_set_depth_test(shader_ptr, true); + shader_set_depth_write(shader_ptr, false); + shader_set_depth_compare_op(shader_ptr, VK_COMPARE_OP_LESS_OR_EQUAL); + shader_set_depth_bounds_test(shader_ptr, false); + shader_set_stencil_test(shader_ptr, false); + + shader_add_module(shader_ptr, ShaderModuleType::Vertex, GenerateSkyBoxVertexShaderCode()); + shader_add_module(shader_ptr, ShaderModuleType::Fragment, GenerateSkyBoxFragmentShaderCode()); + + raster_shaders.push_back(shader_ptr); return shader_ptr; } @@ -1083,6 +1294,7 @@ namespace dz { return buffer_group_get_buffer_element_count(buffer_group, buffer_name); }); + compute_shaders.push_back(shader_ptr); return shader_ptr; } @@ -1100,11 +1312,13 @@ namespace dz { return buffer_group_get_buffer_element_count(buffer_group, Cameras_Str); }); + compute_shaders.push_back(shader_ptr); return shader_ptr; } void EnableDrawInWindow(WINDOW* window_ptr) { window_add_drawn_buffer_group(window_ptr, &draw_mg, buffer_group); + window_add_drawn_buffer_group(window_ptr, &skybox_mg, buffer_group); window_register_free_callback(window_ptr, 100.f, [&]() mutable { // for (auto& [scene_id, scene_group] : id_scene_groups) @@ -1113,17 +1327,38 @@ namespace dz { }); } + std::string GenerateShaderBinding(ShaderModuleType moduleType, int& binding_index) { + std::string shader_bindings; + for (auto& [priority, provider_ids] : prioritized_provider_ids) { + for (auto& provider_id : provider_ids) { + auto& provider_group = pid_provider_groups[provider_id]; + auto& bindings_vec = provider_group.glsl_bindings; + for (auto binding_str : bindings_vec) { + static std::string BINDING_STR = "@BINDING@"; + static auto replace_str = [](const auto& STR, auto& binding_str, auto& binding_index) { + auto pos = binding_str.find(STR); + if (pos != std::string::npos) { + auto binding_str_it = binding_str.begin(); + binding_str.erase(binding_str_it + pos, binding_str_it + pos + STR.size()); + auto binding_index_str = std::to_string(binding_index++); + binding_str.insert(binding_str.begin() + pos, binding_index_str.begin(), binding_index_str.end()); + } + return pos; + }; + while (replace_str(BINDING_STR, binding_str, binding_index) != std::string::npos) {} + shader_bindings += ("\n" + binding_str + "\n"); + } + } + } + return shader_bindings; + } + std::string GenerateShaderHeader(ShaderModuleType moduleType) { std::string shader_header; auto binding_index = 0; - 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"; + shader_header += GenerateShaderBinding(moduleType, binding_index); // Setup Structs for (auto& [priority, provider_ids] : prioritized_provider_ids) { @@ -1164,7 +1399,7 @@ layout(std430, binding = )" + std::to_string(binding_index++) + R"() buffer Vert 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) { + if (provider_group.buffer_host_type != BufferHost::GPU) { shader_header += provider_group.glsl_methods[moduleType]; continue; } @@ -1275,13 +1510,14 @@ bool HasComponentWithType(in Entity entity, int entity_index, int type, out int layout(location = 0) out int outID; layout(location = 1) out vec4 outColor; 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; +layout(location = 3) out vec3 outLocalPosition; +layout(location = 4) out vec3 outNormal; +layout(location = 5) out vec3 outViewPosition; +layout(location = 6) out vec2 outUV2; +layout(location = 7) out vec3 outTangent; +layout(location = 8) out vec3 outBitangent; )"; - int out_location = 8; + int out_location = 9; int in_location = 0; shader_string += GenerateShaderLayout(ShaderModuleType::Vertex, in_location, out_location); @@ -1326,15 +1562,16 @@ void main() { layout(location = 0) flat in int inID; layout(location = 1) in vec4 inColor; 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 = 3) in vec3 inLocalPosition; +layout(location = 4) in vec3 inNormal; +layout(location = 5) in vec3 inViewPosition; +layout(location = 6) in vec2 inUV2; +layout(location = 7) in vec3 inTangent; +layout(location = 8) in vec3 inBitangent; layout(location = 0) out vec4 FragColor; )"; - int in_location = 8; + int in_location = 9; int out_location = 1; shader_string += GenerateShaderLayout(ShaderModuleType::Fragment, in_location, out_location); @@ -1365,6 +1602,94 @@ void main() { return shader_string; } + std::string GenerateSkyBoxVertexShaderCode() { + std::string shader_string = R"( +#version 450 +layout(location = 0) out int outID; +layout(location = 1) out vec3 outLocalPosition; +)"; + int out_location = 2; + int in_location = 0; + shader_string += GenerateShaderLayout(ShaderModuleType::Vertex, in_location, out_location); + + shader_string += R"( +layout(push_constant) uniform PushConstants { + int camera_index; +} pc; +)"; + shader_string += GenerateShaderHeader(ShaderModuleType::Vertex); + + // Main + shader_string += R"( +vec3 positions[36] = vec3[]( + vec3(-1.0, 1.0, -1.0), vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0, -1.0), + vec3( 1.0, -1.0, -1.0), vec3( 1.0, 1.0, -1.0), vec3(-1.0, 1.0, -1.0), + + vec3(-1.0, -1.0, 1.0), vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, -1.0), + vec3(-1.0, 1.0, -1.0), vec3(-1.0, 1.0, 1.0), vec3(-1.0, -1.0, 1.0), + + vec3( 1.0, -1.0, -1.0), vec3( 1.0, -1.0, 1.0), vec3( 1.0, 1.0, 1.0), + vec3( 1.0, 1.0, 1.0), vec3( 1.0, 1.0, -1.0), vec3( 1.0, -1.0, -1.0), + + vec3(-1.0, -1.0, 1.0), vec3(-1.0, 1.0, 1.0), vec3( 1.0, 1.0, 1.0), + vec3( 1.0, 1.0, 1.0), vec3( 1.0, -1.0, 1.0), vec3(-1.0, -1.0, 1.0), + + vec3(-1.0, 1.0, -1.0), vec3( 1.0, 1.0, -1.0), vec3( 1.0, 1.0, 1.0), + vec3( 1.0, 1.0, 1.0), vec3(-1.0, 1.0, 1.0), vec3(-1.0, 1.0, -1.0), + + vec3(-1.0, -1.0, -1.0), vec3(-1.0, -1.0, 1.0), vec3( 1.0, -1.0, -1.0), + vec3( 1.0, -1.0, -1.0), vec3(-1.0, -1.0, 1.0), vec3( 1.0, -1.0, 1.0) +); + +void main() { + int skybox_index = outID = gl_InstanceIndex; + Camera camera = GetCameraData(pc.camera_index); + vec3 pos = positions[gl_VertexIndex]; + mat4 viewNoTranslation = mat4(mat3(camera.view)); + gl_Position = camera.projection * viewNoTranslation * vec4(pos, 1.0); + gl_Position.z = gl_Position.w; + outLocalPosition = pos; +} +)"; + + return shader_string; + } + + std::string GenerateSkyBoxFragmentShaderCode() { + std::string shader_string = R"( +#version 450 +layout(location = 0) flat in int inID; +layout(location = 1) in vec3 inLocalPosition; + +vec3 inTangent = vec3(0.0); +vec3 inBitangent = vec3(0.0); +vec3 inNormal = vec3(0.0); + +layout(location = 0) out vec4 FragColor; +)"; + int in_location = 2; + int out_location = 1; + shader_string += GenerateShaderLayout(ShaderModuleType::Fragment, in_location, out_location); + + shader_string += R"( + +layout(push_constant) uniform PushConstants { + int camera_index; +} pc; +)"; + shader_string += GenerateShaderHeader(ShaderModuleType::Fragment); + + shader_string += R"( +void main() { + SkyBox skybox = GetSkyBoxData(inID); + vec3 direction = normalize(inLocalPosition); + direction.y = -direction.y; + FragColor = SampleHDRI(skybox.hdri_index, direction);; +} +)"; + return shader_string; + } + std::string GenerateModelComputeShaderCode() { std::string shader_string = R"( #version 450 @@ -1470,16 +1795,15 @@ void main() { bool SetCameraAspect(size_t camera_id, float width, float height) { if (!width || !height) return false; + auto& camera = GetCamera(camera_id); - camera.orthoWidth = width; - camera.orthoHeight = height; - switch (typename CameraProviderT::ProjectionType(camera.type)) { - case CameraProviderT::Perspective: - camera.aspect = camera.orthoWidth / camera.orthoHeight; - break; - default: break; - } - CameraInit(camera); + + camera.width = width; + camera.height = height; + + if constexpr (requires { camera.Initialize(); }) + camera.Initialize(); + return true; } diff --git a/include/dz/ECS/Camera.hpp b/include/dz/ECS/Camera.hpp index b1bd7153..93a35afe 100644 --- a/include/dz/ECS/Camera.hpp +++ b/include/dz/ECS/Camera.hpp @@ -15,21 +15,25 @@ namespace dz::ecs { }; mat view; mat projection; - float nearPlane; - float farPlane; - int type; - float aspect = 0; - vec position; + float nearPlane = 0.f; + float farPlane = 0.f; + int type = -1; + int padding = 0; + vec position = {0, 0, 0}; float fov = 80.f; - vec center; - float orthoWidth; - vec up; - float orthoHeight; + vec center = {0, 0, 0}; + float width = 0; + vec up = {0, 1, 0}; + float height = 0; int parent_index = -1; int parent_cid = 0; int transform_dirty = 1; int is_active = 1; - inline static constexpr bool RequiresBuffer = true; + + static Camera DefaultPerspective; + static Camera DefaultOrthographic; + + inline static constexpr BufferHost BufferHostType = BufferHost::GPU; inline static constexpr bool IsCameraProvider = true; inline static constexpr size_t PID = 5; inline static float Priority = 0.5f; @@ -42,13 +46,13 @@ struct Camera { float nearPlane; float farPlane; int type; - float aspect; + float padding; vec3 position; float fov; vec3 center; - float orthoWidth; + float width; vec3 up; - float orthoHeight; + float height; int parent_index; int parent_cid; int transform_dirty; @@ -126,7 +130,6 @@ void GetCameraModel(int camera_index, out mat4 out_model, out int parent_index, } )"} }; - struct CameraMetaReflectable : ::Reflectable { @@ -221,19 +224,15 @@ void GetCameraModel(int camera_index, out mat4 out_model, out int parent_index, int uid; std::string name; inline static std::unordered_map> prop_name_indexes = { - {"Aspect", {0, 0}}, - {"FOV", {1, 0}} + {"FOV", {0, 0}} }; inline static std::unordered_map prop_index_names = { - {0, "Aspect"}, - {1, "FOV"} + {0, "FOV"} }; inline static std::vector prop_names = { - "Aspect", "FOV" }; inline static const std::vector typeinfos = { - &typeid(float), &typeid(float) }; @@ -382,7 +381,7 @@ void GetCameraModel(int camera_index, out mat4 out_model, out int parent_index, } } - void InitFramebuffer(Shader* shader, float width, float height) { + void InitFramebuffer(const std::vector& shader_vec, float width, float height) { // Initialize camera framebuffer fb_color_image = image_create({ .width = uint32_t(width), @@ -415,7 +414,8 @@ void GetCameraModel(int camera_index, out mat4 out_model, out int parent_index, auto frame_ds_pair = image_create_descriptor_set(fb_color_image); frame_image_ds = frame_ds_pair.second; - shader_set_render_pass(shader, framebuffer); + for (auto& shader : shader_vec) + shader_set_render_pass(shader, framebuffer); } bool backup(Serial& serial) const override { if (!backup_internal(serial)) @@ -432,32 +432,24 @@ void GetCameraModel(int camera_index, out mat4 out_model, out int parent_index, }; using ReflectableGroup = CameraReflectableGroup; - }; - void CameraInit( - Camera& camera, - vec position, - vec center, - vec up, - float nearPlane, - float farPlane, - float width, - float height, - float fov, - Camera::ProjectionType projectionType = Camera::Perspective - ); - - void CameraInit( - Camera& camera, - vec position, - vec center, - vec up, - float nearPlane, - float farPlane, - vec viewport, - Camera::ProjectionType projectionType = Camera::Orthographic - ); + void Initialize() { + switch(Camera::ProjectionType(type)) + { + case Camera::Perspective: + projection = perspective(radians(fov), width / height, nearPlane, farPlane); + break; + case Camera::Orthographic: + projection = orthographic(-width / 2.f, width / 2.f, -height / 2.f, height / 2.f, nearPlane, farPlane); + break; + default: break; + } + } - void CameraInit(Camera& camera); + template + void Initialize(TECS& ecs, ::ReflectableGroup& camera_group) { + Initialize(); + } + }; } \ No newline at end of file diff --git a/include/dz/ECS/Entity.hpp b/include/dz/ECS/Entity.hpp index 34673773..14a8b5b0 100644 --- a/include/dz/ECS/Entity.hpp +++ b/include/dz/ECS/Entity.hpp @@ -16,7 +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 BufferHost BufferHostType = BufferHost::GPU; inline static constexpr bool IsEntityProvider = true; inline static std::string ProviderName = "Entity"; inline static std::string StructName = "Entity"; diff --git a/include/dz/ECS/HDRI.hpp b/include/dz/ECS/HDRI.hpp new file mode 100644 index 00000000..d93ac27a --- /dev/null +++ b/include/dz/ECS/HDRI.hpp @@ -0,0 +1,148 @@ +#pragma once +#include "Provider.hpp" +#include "../Shader.hpp" +#include "../Reflectable.hpp" +#include "../BufferGroup.hpp" +#include "../Image.hpp" + +namespace dz::ecs { + + struct HDRIIndexReflectable { + int hdri_index = 0; + }; + + struct HDRI : Provider { + vec hdri_atlas_pack = {-1.0f, -1.0f, -1.0f, -1.0f}; + + inline static constexpr size_t PID = 11; + inline static float Priority = 2.6f; + inline static constexpr BufferHost BufferHostType = BufferHost::GPU; + inline static constexpr bool IsHDRIProvider = true; + inline static std::string ProviderName = "HDRI"; + inline static std::string StructName = "HDRI"; + inline static std::string GLSLStruct = R"( +struct HDRI { + vec4 hdri_atlas_pack; +}; +)"; + inline static std::unordered_map GLSLMethods = { + { ShaderModuleType::Vertex, R"( +)" }, + { ShaderModuleType::Fragment, R"( +const vec2 invAtan = vec2(0.1591, 0.3183); +vec2 SampleSphericalMap(vec3 v) { + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= invAtan; + uv += 0.5; + return uv; +} +vec4 SampleHDRI(in int hdri_index, in vec3 v) { + vec2 image_size = HDRIs.data[hdri_index].hdri_atlas_pack.xy; + if (image_size.x == -1.0) + return vec4(0.0); + vec2 packed_rect = HDRIs.data[hdri_index].hdri_atlas_pack.zw; + return SampleAtlas(SampleSphericalMap(v), image_size, packed_rect, HDRIAtlas); +} +)" } + }; + + inline static std::vector GLSLBindings = { + R"( +layout(binding = @BINDING@) uniform sampler2D HDRIAtlas; +)" + }; + + inline static std::vector> GLSLMain = { + {0.5f, R"( +)", ShaderModuleType::Vertex}, + {0.5f, R"( + vec4 hdri_sample = SampleHDRI(0, inLocalPosition); +)", ShaderModuleType::Fragment} + }; + + struct HDRIReflectable : ::Reflectable { + + private: + std::function get_hdri_function; + int uid; + std::string name; + inline static std::unordered_map> prop_name_indexes = { + }; + inline static std::unordered_map prop_index_names = { + }; + inline static std::vector prop_names = { + }; + inline static const std::vector typeinfos = { + }; + + public: + HDRIReflectable(const std::function& get_hdri_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; + }; + + struct HDRIReflectableGroup : ReflectableGroup { + BufferGroup* buffer_group = nullptr; + std::string name; + std::vector reflectables; + + Image* hdri_image = nullptr; + VkDescriptorSet hdri_frame_image_ds = VK_NULL_HANDLE; + + HDRIReflectableGroup(BufferGroup* buffer_group): + buffer_group(buffer_group), + name("HDRI") + {} + HDRIReflectableGroup(BufferGroup* buffer_group, Serial& serial): + buffer_group(buffer_group) + { + restore(serial); + } + GroupType GetGroupType() override { + return ReflectableGroup::Generic; + } + std::string& GetName() override { + return name; + } + const std::vector& GetReflectables() override { + return reflectables; + } + void ClearReflectables() { + if (reflectables.empty()) { + return; + } + delete reflectables[0]; + reflectables.clear(); + } + void UpdateChildren() override { + if (reflectables.empty()) { + reflectables.push_back(new HDRIReflectable([&]() { + auto buffer = buffer_group_get_buffer_data_ptr(buffer_group, "HDRIs"); + return ((struct HDRI*)(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; + } + + }; + + using ReflectableGroup = HDRIReflectableGroup; + }; +} \ No newline at end of file diff --git a/include/dz/ECS/Light.hpp b/include/dz/ECS/Light.hpp index 490e6aff..4ee7767b 100644 --- a/include/dz/ECS/Light.hpp +++ b/include/dz/ECS/Light.hpp @@ -21,7 +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 constexpr BufferHost BufferHostType = BufferHost::GPU; inline static std::string ProviderName = "Light"; inline static std::string StructName = "Light"; inline static std::string GLSLStruct = R"( @@ -37,13 +37,25 @@ struct Light { vec3 color; float outerCone; }; + +struct LightingParams { + vec3 worldPosition; + vec3 viewDirection; + float NdotV; + vec3 normal; + int lightsSize; +}; + +LightingParams lParams; )"; inline static std::vector> GLSLMain = { {3.5f, R"( - vec3 frag_pos = inPosition; - vec3 view_dir = normalize(camera.position - frag_pos); - int lights_size = Lights.data.length(); + lParams.worldPosition = inPosition; + lParams.viewDirection = normalize(camera.position - lParams.worldPosition); + lParams.NdotV = max(dot(current_normal, lParams.viewDirection), 0.0); + lParams.normal = current_normal; + lParams.lightsSize = Lights.data.length(); )", ShaderModuleType::Fragment} }; diff --git a/include/dz/ECS/Material.hpp b/include/dz/ECS/Material.hpp index c2f8c696..306e3f3c 100644 --- a/include/dz/ECS/Material.hpp +++ b/include/dz/ECS/Material.hpp @@ -1,6 +1,7 @@ #pragma once #include "Provider.hpp" #include "../Reflectable.hpp" +#include "../Shader.hpp" #include "../Image.hpp" namespace dz::ecs { @@ -20,7 +21,7 @@ namespace dz::ecs { inline static constexpr size_t PID = 6; inline static float Priority = 2.5f; - inline static constexpr bool RequiresBuffer = true; + inline static constexpr BufferHost BufferHostType = BufferHost::GPU; inline static constexpr bool IsMaterialProvider = true; inline static std::string ProviderName = "Material"; inline static std::string StructName = "Material"; @@ -34,6 +35,15 @@ struct Material { vec4 shininess_atlas_pack; vec4 albedo_color; }; + +struct MaterialParams { + vec3 albedo; + vec3 normal; + float metalness; + float roughness; +}; + +MaterialParams mParams; )"; inline static std::unordered_map GLSLMethods = { { ShaderModuleType::Vertex, R"( @@ -42,52 +52,37 @@ vec4 GetMaterialBaseColor(in SubMesh submesh) { 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) { +vec4 SampleAtlas(in vec2 uv, 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; + vec2 packed_uv = offset_uv + uv * scale_uv; return texture(atlas, packed_uv); } -void EnsureMaterialFragColor(in SubMesh submesh, inout vec4 current_color) { +void EnsureMaterialFragColor(in vec2 uv, in SubMesh submesh, inout vec4 current_color) { 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); + current_color = SampleAtlas(uv, image_size, packed_rect, AlbedoAtlas); } -void EnsureMaterialNormal(in SubMesh submesh, inout vec3 current_normal) { +void EnsureMaterialNormal(in vec2 uv, 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; + vec3 tangentNormal = SampleAtlas(uv, 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) { +void EnsureMaterialMetalnessRoughness(in vec2 uv, 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); + vec4 m_r_vec = SampleAtlas(uv, m_r_image_size, m_r_packed_rect, MetalnessRoughnessAtlas); metalness = m_r_vec.r; roughness = m_r_vec.g; return; @@ -95,37 +90,42 @@ void EnsureMaterialMetalnessRoughness(in SubMesh submesh, inout float metalness, 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; + metalness = SampleAtlas(uv, 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; + roughness = SampleAtlas(uv, 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;" - // } } + inline static std::vector GLSLBindings = { + R"( +layout(binding = @BINDING@) uniform sampler2D AlbedoAtlas; +layout(binding = @BINDING@) uniform sampler2D NormalAtlas; +layout(binding = @BINDING@) uniform sampler2D RoughnessAtlas; +layout(binding = @BINDING@) uniform sampler2D MetalnessAtlas; +layout(binding = @BINDING@) uniform sampler2D MetalnessRoughnessAtlas; +layout(binding = @BINDING@) uniform sampler2D ShininessAtlas; +)" }; 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); + EnsureMaterialFragColor(inUV2, submesh, current_color); + EnsureMaterialNormal(inUV2, submesh, current_normal); float metalness = 0.0; float roughness = 0.0; - EnsureMaterialMetalnessRoughness(submesh, metalness, roughness); + EnsureMaterialMetalnessRoughness(inUV2, submesh, metalness, roughness); + mParams.albedo = vec3(current_color); + mParams.normal = current_normal; + mParams.metalness = metalness; + mParams.roughness = roughness; )", ShaderModuleType::Fragment} }; diff --git a/include/dz/ECS/Mesh.hpp b/include/dz/ECS/Mesh.hpp index 4a87c808..bf36ed57 100644 --- a/include/dz/ECS/Mesh.hpp +++ b/include/dz/ECS/Mesh.hpp @@ -16,7 +16,7 @@ namespace dz::ecs { inline static constexpr size_t PID = 3; inline static float Priority = 0.5f; - inline static constexpr bool RequiresBuffer = true; + inline static constexpr BufferHost BufferHostType = BufferHost::GPU; inline static constexpr bool IsMeshProvider = true; inline static std::string ProviderName = "Mesh"; inline static std::string StructName = "Mesh"; diff --git a/include/dz/ECS/PBRLighting.hpp b/include/dz/ECS/PBRLighting.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/include/dz/ECS/PhongLighting.hpp b/include/dz/ECS/PhongLighting.hpp index 3284e103..2c2fe232 100644 --- a/include/dz/ECS/PhongLighting.hpp +++ b/include/dz/ECS/PhongLighting.hpp @@ -7,12 +7,11 @@ 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 CalculatePhongLighting(in Light light) { vec3 light_dir; float attenuation = 1.0; @@ -22,14 +21,14 @@ vec3 CalculatePhongLighting(in vec3 normal, vec3 frag_pos, vec3 view_dir, in Lig } else { - light_dir = normalize(light.position - frag_pos); - float dist = length(light.position - frag_pos); + light_dir = normalize(light.position - lParams.worldPosition); + float dist = length(light.position - lParams.worldPosition); 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 diff = max(dot(lParams.normal, light_dir), 0.0); + vec3 reflect_dir = reflect(-light_dir, lParams.normal); + float spec = pow(max(dot(lParams.viewDirection, reflect_dir), 0.0), 4.0);//shininess); float spotlight_factor = 1.0; if (light.type == 2) @@ -49,8 +48,8 @@ vec3 CalculatePhongLighting(in vec3 normal, vec3 frag_pos, vec3 view_dir, in Lig 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]); + for (int light_index = 0; light_index < lParams.lightsSize; light_index++) { + light_color += CalculatePhongLighting(Lights.data[light_index]); } current_color = vec4(light_color, 1.0) * current_color; )", ShaderModuleType::Fragment} diff --git a/include/dz/ECS/PhysicallyBasedLighting.hpp b/include/dz/ECS/PhysicallyBasedLighting.hpp new file mode 100644 index 00000000..f3bd8512 --- /dev/null +++ b/include/dz/ECS/PhysicallyBasedLighting.hpp @@ -0,0 +1,156 @@ +#pragma once +#include "Provider.hpp" +#include "../Reflectable.hpp" +#include "../math.hpp" +#include "../Shader.hpp" +namespace dz::ecs { + struct PhysicallyBasedLighting : Provider { + inline static constexpr size_t PID = 9; + inline static float Priority = 4.0f; + inline static std::string ProviderName = "PhysicallyBasedLighting"; + inline static std::string StructName = "PhysicallyBasedLighting"; + inline static std::unordered_map GLSLMethods = { + {ShaderModuleType::Fragment, R"( +const vec3 Fdielectric = vec3(0.04); +const float PI = 3.141592; +const float Epsilon = 0.00001; + +// Shlick's approximation of the Fresnel factor. +vec3 fresnelSchlick(vec3 F0, float cosTheta) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} + +// GGX/Towbridge-Reitz normal distribution function. +// Uses Disney's reparametrization of alpha = roughness^2 +float ndfGGX(float cosLh, float roughness) +{ + float alpha = roughness * roughness; + float alphaSq = alpha * alpha; + + float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + return alphaSq / (PI * denom * denom); +} + +// Single term for separable Schlick-GGX below. +float gaSchlickG1(float cosTheta, float k) +{ + return cosTheta / (cosTheta * (1.0 - k) + k); +} + +// Schlick-GGX approximation of geometric attenuation function using Smith's method. +float gaSchlickGGX(float cosLi, float NdotV, float roughness) +{ + float r = roughness + 1.0; + float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. + return gaSchlickG1(cosLi, k) * gaSchlickG1(NdotV, k); +} + +vec3 IBL(vec3 F0, vec3 Lr) +{ + // vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb; + // vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness); + // vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness); + // vec3 diffuseIBL = m_Params.Albedo * irradiance; + + // int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex); + // float NoV = clamp(m_Params.NdotV, 0.0, 1.0); + // vec3 R = 2.0 * dot(m_Params.View, m_Params.Normal) * m_Params.Normal - m_Params.View; + // vec3 specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (m_Params.Roughness * m_Params.Roughness) * u_EnvRadianceTexLevels).rgb; + + // // Sample BRDF Lut, 1.0 - roughness for y-coord because texture was generated (in Sparky) for gloss model + // vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg; + // vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y); + + // return kd * diffuseIBL + specularIBL; + return vec3(0.0); +} + +vec3 PBDL(vec3 F0, in Light light) { + vec3 result = vec3(0.0); + vec3 Li = -light.direction; + vec3 Lradiance = vec3(light.intensity); + vec3 Lh = normalize(Li + lParams.viewDirection); + + // Calculate angles between surface normal and various light vectors. + float cosLi = max(0.0, dot(lParams.normal, Li)); + float cosLh = max(0.0, dot(lParams.normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, lParams.viewDirection))); + float D = ndfGGX(cosLh, mParams.roughness); + float G = gaSchlickGGX(cosLi, lParams.NdotV, mParams.roughness); + + vec3 kd = (1.0 - F) * (1.0 - mParams.metalness); + vec3 diffuseBRDF = kd * mParams.albedo; + + // Cook-Torrance + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * lParams.NdotV); + + result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi; + + return result; +} +vec3 PBL(vec3 F0) { + vec3 result = vec3(0.0); + for (int light_index = 0; light_index < lParams.lightsSize; light_index++) { + switch (Lights.data[light_index].type) { + case 0: + result += PBDL(F0, Lights.data[light_index]); + break; + } + } + return result; +} +)" } + }; + inline static std::vector> GLSLMain = { + {4.0f, R"( + // Specular reflection vector + vec3 Lr = 2.0 * lParams.NdotV * lParams.normal - lParams.viewDirection; + + // Fresnel reflectance, metals use albedo + vec3 F0 = mix(Fdielectric, mParams.albedo, mParams.metalness); + + vec3 lightContribution = PBL(F0); + vec3 iblContribution = IBL(F0, Lr); + + current_color = vec4(lightContribution + iblContribution, 1.0); +)", ShaderModuleType::Fragment} + }; + + struct PhysicallyBasedLightingReflectableGroup : ReflectableGroup { + BufferGroup* buffer_group = nullptr; + std::string name; + std::vector reflectables; + PhysicallyBasedLightingReflectableGroup(BufferGroup* buffer_group): + buffer_group(buffer_group), + name("PhysicallyBasedLighting") + {} + PhysicallyBasedLightingReflectableGroup(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 = PhysicallyBasedLightingReflectableGroup; + }; +} \ No newline at end of file diff --git a/include/dz/ECS/Provider.hpp b/include/dz/ECS/Provider.hpp index 49671eed..da80768c 100644 --- a/include/dz/ECS/Provider.hpp +++ b/include/dz/ECS/Provider.hpp @@ -7,6 +7,12 @@ namespace dz { inline static const std::string kEmptyString = ""; + enum class BufferHost { + NoBuffer, + CPU, + GPU + }; + template struct Provider { inline static constexpr size_t GetPID() { @@ -30,11 +36,11 @@ namespace dz { return 0; } - inline static constexpr bool GetRequiresBuffer() { - if constexpr (requires { T::RequiresBuffer; } ) { - return T::RequiresBuffer; + inline static constexpr BufferHost GetBufferHostType() { + if constexpr (requires { T::BufferHostType; } ) { + return T::BufferHostType; } - return false; + return BufferHost::NoBuffer; } inline static constexpr bool GetIsDrawProvider() { @@ -86,6 +92,20 @@ namespace dz { return false; } + inline static constexpr bool GetIsHDRIProvider() { + if constexpr (requires { T::IsHDRIProvider; }) { + return T::IsHDRIProvider; + } + return false; + } + + inline static constexpr bool GetIsSkyBoxProvider() { + if constexpr (requires { T::IsSkyBoxProvider; }) { + return T::IsSkyBoxProvider; + } + return false; + } + inline static float GetPriority() { if constexpr (requires { T::Priority; }) { return T::Priority; @@ -130,6 +150,14 @@ namespace dz { return kEmptyMap; } + inline static const std::vector& GetGLSLBindings() { + if constexpr (requires { T::GLSLBindings; }) { + return T::GLSLBindings; + } + static std::vector kEmptyVec = {}; + return kEmptyVec; + } + inline static std::vector>& GetGLSLMain() { if constexpr (requires { T::GLSLMain; }) { return T::GLSLMain; @@ -189,6 +217,18 @@ namespace dz { static constexpr bool value = Provider::GetIsSubMeshProvider(); }; + template + struct IsHDRIProvider + { + static constexpr bool value = Provider::GetIsHDRIProvider(); + }; + + template + struct IsSkyBoxProvider + { + static constexpr bool value = Provider::GetIsSkyBoxProvider(); + }; + template class Trait, typename... Ts> struct FirstMatchingOrDefault; diff --git a/include/dz/ECS/Scene.hpp b/include/dz/ECS/Scene.hpp index 836f3a05..3fad5619 100644 --- a/include/dz/ECS/Scene.hpp +++ b/include/dz/ECS/Scene.hpp @@ -15,7 +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 BufferHost BufferHostType = BufferHost::GPU; inline static constexpr bool IsSceneProvider = true; inline static std::string ProviderName = "Scene"; inline static std::string StructName = "Scene"; diff --git a/include/dz/ECS/SkyBox.hpp b/include/dz/ECS/SkyBox.hpp new file mode 100644 index 00000000..ee457e3a --- /dev/null +++ b/include/dz/ECS/SkyBox.hpp @@ -0,0 +1,70 @@ +#pragma once +#include "Provider.hpp" +#include "../Reflectable.hpp" +#include "../math.hpp" +#include "../Shader.hpp" +namespace dz::ecs { + struct SkyBox : Provider { + int parent_index = -1; + int parent_cid = 0; + int hdri_index = -1; + int padding = 0; + inline static constexpr size_t PID = 10; + inline static float Priority = 4.0f; + inline static constexpr BufferHost BufferHostType = BufferHost::GPU; + inline static constexpr bool IsSkyBoxProvider = true; + inline static std::string ProviderName = "SkyBox"; + inline static std::string StructName = "SkyBox"; + inline static std::string GLSLStruct = R"( +struct SkyBox { + int parent_index; + int parent_cid; + int hdri_index; + int padding; +}; +)"; + inline static std::unordered_map GLSLMethods = { + {ShaderModuleType::Fragment, R"( +)" } + }; + inline static std::vector> GLSLMain = { + {4.0f, R"( +)", ShaderModuleType::Fragment} + }; + + struct SkyBoxReflectableGroup : ReflectableGroup { + BufferGroup* buffer_group = nullptr; + std::string name; + std::vector reflectables; + SkyBoxReflectableGroup(BufferGroup* buffer_group): + buffer_group(buffer_group), + name("SkyBox") + {} + SkyBoxReflectableGroup(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 = SkyBoxReflectableGroup; + }; +} \ No newline at end of file diff --git a/include/dz/ECS/SubMesh.hpp b/include/dz/ECS/SubMesh.hpp index 2c755895..feb056c9 100644 --- a/include/dz/ECS/SubMesh.hpp +++ b/include/dz/ECS/SubMesh.hpp @@ -14,7 +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 BufferHost BufferHostType = BufferHost::GPU; inline static constexpr bool IsDrawProvider = true; inline static constexpr bool IsSubMeshProvider = true; inline static std::string ProviderName = "SubMesh"; @@ -28,10 +28,10 @@ struct SubMesh { }; )"; - uint32_t GetVertexCount(BufferGroup* buffer_group, SubMesh& submesh) { - auto mesh_buffer_sh_ptr = buffer_group_get_buffer_data_ptr(buffer_group, Meshs_Str); - auto& mesh = *(Mesh*)(mesh_buffer_sh_ptr.get() + (sizeof(Mesh) * submesh.mesh_index)); - return mesh.vertex_count; + uint32_t GetVertexCount(BufferGroup* buffer_group) { + auto mesh_buffer_sh_ptr = buffer_group_get_buffer_data_ptr(buffer_group, Meshs_Str); + auto& mesh = *(Mesh*)(mesh_buffer_sh_ptr.get() + (sizeof(Mesh) * mesh_index)); + return mesh.vertex_count; } struct SubMeshReflectable : ::Reflectable { diff --git a/include/dz/Framebuffer.hpp b/include/dz/Framebuffer.hpp index 38bdc6df..ace26355 100644 --- a/include/dz/Framebuffer.hpp +++ b/include/dz/Framebuffer.hpp @@ -1,5 +1,6 @@ #pragma once #include "Image.hpp" +#include "BlendState.hpp" namespace dz { @@ -26,7 +27,7 @@ namespace dz { /** * @brief Binds a Framebuffer as the current render target */ - void framebuffer_bind(Framebuffer*); + void framebuffer_bind(Framebuffer*, bool clear); /** * @brief Unbinds a Framebuffer @@ -69,53 +70,6 @@ namespace dz { */ Image* framebuffer_get_image(Framebuffer*, AttachmentType, bool new_image = false); - enum class BlendFactor - { - Zero = 0, - One = 1, - SrcColor = 2, - OneMinusSrcColor = 3, - DstColor = 4, - OneMinusDstColor = 5, - SrcAlpha = 6, - OneMinusSrcAlpha = 7, - DstAlpha = 8, - OneMinusDstAlpha = 9, - ConstantColor = 10, - OneMinusConstantColor = 11, - ConstantAlpha = 12, - OneMinusConstantAlpha = 13, - SrcAlphaSaturate = 14, - Src1Color = 15, - OneMinusSrc1Color = 16, - Src1Alpha = 17, - OneMinusSrc1Alpha = 18 - }; - - enum class BlendOp - { - Add = 0, - Subtract = 1, - ReverseSubtract = 2, - Min = 3, - Max = 4 - }; - - struct BlendState - { - bool enable = true; - BlendFactor srcColor = BlendFactor::SrcAlpha; - BlendFactor dstColor = BlendFactor::OneMinusSrcColor; - BlendFactor srcAlpha = BlendFactor::SrcAlpha; - BlendFactor dstAlpha = BlendFactor::OneMinusSrcAlpha; - BlendOp colorOp = BlendOp::Add; - BlendOp alphaOp = BlendOp::Add; - static BlendState MainFramebuffer; - static BlendState Layout; - static BlendState Text; - static BlendState SrcAlpha; - }; - struct FramebufferInfo { Image** pImages = 0; int imagesCount = 0; diff --git a/include/dz/Shader.hpp b/include/dz/Shader.hpp index 61626ab7..f2676840 100644 --- a/include/dz/Shader.hpp +++ b/include/dz/Shader.hpp @@ -8,6 +8,7 @@ #include #include "ReflectedStructView.hpp" #include "math.hpp" +#include "BlendState.hpp" namespace dz { @@ -159,4 +160,80 @@ namespace dz * @brief Updates a push_constant by index given data and size */ void shader_update_push_constant(Shader*, uint32_t pc_index, void* data, uint32_t size); + + /** + * @brief Sets the line width for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_line_width(Shader*, float line_width); + + /** + * @brief Enables/Disables depth testing in a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_depth_test(Shader*, bool enabled); + + /** + * @brief Enables/Disables depth writing in a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_depth_write(Shader*, bool write_enabled); + + /** + * @brief Enables/Disables depth clamping in a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_depth_clamp(Shader*, bool clamp_enabled); + + /** + * @brief Sets the polygon mode for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_polygon_mode(Shader*, VkPolygonMode polygon_mode); + + /** + * @brief Sets the compare of of a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_depth_compare_op(Shader*, VkCompareOp compare_op); + + /** + * @brief Sets the cull mode for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_cull_mode(Shader*, VkCullModeFlags cull_mode); + + /** + * @brief Sets the front face for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_front_face(Shader*, VkFrontFace front_face); + + /** + * @brief Sets the BlendState for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_blend_state(Shader*, BlendState blend_state); + + /** + * @brief Sets depth_bounds_test for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_depth_bounds_test(Shader*, bool enabled); + /** + * @brief Sets stencil_test for a Shader + * + * @note must be called before the Shader is compiled + */ + void shader_set_stencil_test(Shader*, bool enabled); } // namespace dz \ No newline at end of file diff --git a/src/BufferGroup.cpp b/src/BufferGroup.cpp index 1d57c0b1..361b18ce 100644 --- a/src/BufferGroup.cpp +++ b/src/BufferGroup.cpp @@ -129,20 +129,14 @@ namespace dz { memset(new_buffer.get(), 0, new_size); memcpy(new_buffer.get(), buffer.data_ptr.get(), (std::min)(old_size, new_size)); buffer.data_ptr = new_buffer; + + std::cout << "Resized dynamic CPU buffer '" << buffer_name << "' to hold " << element_count << " elements (" << new_size << " bytes)." << std::endl; } else if (!buffer.gpu_buffer.mapped_memory) { // Allocate the initial CPU-side buffer. Use a custom deleter for array `new[]`. buffer.data_ptr = std::shared_ptr(new uint8_t[new_size], std::default_delete()); memset(buffer.data_ptr.get(), 0, new_size); - - if (old_element_count && old_data_ptr) { - auto copy_size = std::min(old_element_count, element_count); - memcpy(buffer.data_ptr.get(), old_data_ptr.get(), copy_size); - std::cout << "Resized dynamic CPU buffer '" << buffer_name << "' to hold " << element_count << " elements (" << new_size << " bytes). CPU staging buffer created." << std::endl; - } - else { - std::cout << "Set dynamic CPU buffer '" << buffer_name << "' to hold " << element_count << " elements (" << new_size << " bytes). CPU staging buffer created." << std::endl; - } + std::cout << "Set dynamic CPU buffer '" << buffer_name << "' to hold " << element_count << " elements (" << new_size << " bytes). CPU staging buffer created." << std::endl; } else { buffer_group_resize_gpu_buffer(buffer_name, buffer); diff --git a/src/DirectZ.cpp b/src/DirectZ.cpp index e64ec01f..b0eae149 100644 --- a/src/DirectZ.cpp +++ b/src/DirectZ.cpp @@ -79,6 +79,7 @@ namespace dz #include "ECS/Mesh.cpp" #include "ECS/SubMesh.cpp" #include "ECS/Material.cpp" +#include "ECS/HDRI.cpp" #include "ECS/Camera.cpp" #include "ECS/Light.cpp" diff --git a/src/ECS/Camera.cpp b/src/ECS/Camera.cpp index a8c9b64f..d81b3af8 100644 --- a/src/ECS/Camera.cpp +++ b/src/ECS/Camera.cpp @@ -1,68 +1,22 @@ #include #include -void dz::ecs::CameraInit( - Camera& camera, - vec position, - vec center, - vec up, - float nearPlane, - float farPlane, - float width, - float height, - float fov, - Camera::ProjectionType projectionType -) { - assert(projectionType == Camera::Perspective); - camera.nearPlane = nearPlane; - camera.farPlane = farPlane; - camera.position = position; - camera.center = center; - camera.up = up; - camera.type = int(projectionType); - camera.aspect = width / height; - camera.fov = fov; - camera.orthoWidth = width; - camera.orthoHeight = height; - CameraInit(camera); -} -void dz::ecs::CameraInit( - Camera& camera, - vec position, - vec center, - vec up, - float nearPlane, - float farPlane, - vec viewport, - Camera::ProjectionType projectionType -) { - assert(projectionType == Camera::Orthographic); - camera.nearPlane = nearPlane; - camera.farPlane = farPlane; - camera.position = position; - camera.center = center; - camera.up = up; - camera.type = int(projectionType); - camera.orthoWidth = viewport[3]; - camera.orthoHeight = viewport[4]; - camera.aspect = camera.orthoWidth / camera.orthoHeight; - CameraInit(camera); -} - -void dz::ecs::CameraInit(Camera& camera) { - switch(Camera::ProjectionType(camera.type)) - { - case Camera::Perspective: - camera.projection = perspective(camera.fov, camera.aspect, camera.nearPlane, camera.farPlane); - // camera.view = lookAt(camera.position, camera.center, camera.up); - break; - case Camera::Orthographic: - camera.projection = orthographic(-camera.orthoWidth / 2.f, camera.orthoWidth / 2.f, -camera.orthoHeight / 2.f, camera.orthoHeight / 2.f, camera.nearPlane, camera.farPlane); - // camera.view = lookAt(camera.position, camera.center, camera.up); - break; - default: break; - } -} +dz::ecs::Camera dz::ecs::Camera::DefaultPerspective = { + .nearPlane = 0.25f, + .farPlane = 1000.f, + .type = dz::ecs::Camera::Perspective, + .position = {0, 0, 10}, + .center = {0, 0, 0}, + .up = {0, 1, 0} +}; +dz::ecs::Camera dz::ecs::Camera::DefaultOrthographic = { + .nearPlane = 0.25f, + .farPlane = 1000.f, + .type = dz::ecs::Camera::Orthographic, + .position = {0, 0, 10}, + .center = {0, 0, 0}, + .up = {0, 1, 0} +}; dz::ecs::Camera::CameraMetaReflectable::CameraMetaReflectable( const std::function& get_camera_function, @@ -101,7 +55,7 @@ void dz::ecs::Camera::CameraMetaReflectable::NotifyChange(int prop_index) { auto& camera = *camera_ptr; switch (prop_index) { default: - CameraInit(camera); + camera.Initialize(); reset_reflectables_function(); break; } @@ -148,7 +102,7 @@ void dz::ecs::Camera::CameraViewReflectable::NotifyChange(int prop_index) { auto& camera = *camera_ptr; switch (prop_index) { default: - CameraInit(camera); + camera.Initialize(); camera.transform_dirty = 1; break; } @@ -174,10 +128,7 @@ void* dz::ecs::Camera::CameraPerspectiveReflectable::GetVoidPropertyByIndex(int return nullptr; auto& camera = *camera_ptr; switch (prop_index) { - case 0: - return &camera.aspect; - case 1: - return &camera.fov; + case 0: return &camera.fov; default: return nullptr; } } @@ -189,7 +140,7 @@ void dz::ecs::Camera::CameraPerspectiveReflectable::NotifyChange(int prop_index) auto& camera = *camera_ptr; switch (prop_index) { default: - CameraInit(camera); + camera.Initialize(); break; } } @@ -215,9 +166,9 @@ void* dz::ecs::Camera::CameraOrthographicReflectable::GetVoidPropertyByIndex(int auto& camera = *camera_ptr; switch (prop_index) { case 0: - return &camera.orthoWidth; + return &camera.width; case 1: - return &camera.orthoHeight; + return &camera.height; default: return nullptr; } } @@ -229,7 +180,7 @@ void dz::ecs::Camera::CameraOrthographicReflectable::NotifyChange(int prop_index auto& camera = *camera_ptr; switch (prop_index) { default: - CameraInit(camera); + camera.Initialize(); break; } } \ No newline at end of file diff --git a/src/ECS/HDRI.cpp b/src/ECS/HDRI.cpp new file mode 100644 index 00000000..62a78f40 --- /dev/null +++ b/src/ECS/HDRI.cpp @@ -0,0 +1,27 @@ +#include +#include + +dz::ecs::HDRI::HDRIReflectable::HDRIReflectable(const std::function& get_hdri_function): + get_hdri_function(get_hdri_function), + uid(int(GlobalUID::GetNew("Reflectable"))), + name("HDRI") +{} + +int dz::ecs::HDRI::HDRIReflectable::GetID() { + return uid; +} + +std::string& dz::ecs::HDRI::HDRIReflectable::GetName() { + return name; +} + +void* dz::ecs::HDRI::HDRIReflectable::GetVoidPropertyByIndex(int prop_index) { + auto hdri_ptr = get_hdri_function(); + assert(hdri_ptr); + auto& hdri = *hdri_ptr; + switch (prop_index) { + default: return nullptr; + } +} + +void dz::ecs::HDRI::HDRIReflectable::NotifyChange(int prop_index) {} \ No newline at end of file diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index c88e4918..28be55c2 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -56,9 +56,13 @@ namespace dz { vkCreateEvent(dr.device, &eventCreateInfo, 0, &framebuffer.event); - std::vector vkAttachments; - std::vector colorAttachmentRefs; - std::vector resolveAttachmentRefs; + std::vector clearAttachments; + std::vector clearColorAttachmentRefs; + std::vector clearResolveAttachmentRefs; + + std::vector loadAttachments; + std::vector loadColorAttachmentRefs; + std::vector loadResolveAttachmentRefs; UsingAttachmentReference depthStencilRef{}; #ifdef USING_VULKAN_1_2 VkSubpassDescriptionDepthStencilResolve subpassDepthStencilResolve{}; @@ -96,15 +100,17 @@ namespace dz { vkImageViews.push_back(image.imageView); - UsingAttachmentDescription attachment{}; + UsingAttachmentDescription clearAttachment{}; + UsingAttachmentDescription loadAttachment{}; #if USING_VULKAN_1_2 - attachment.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; + loadAttachment.sType = clearAttachment.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; #endif - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + clearAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + loadAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + loadAttachment.storeOp = clearAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + loadAttachment.stencilLoadOp = clearAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + loadAttachment.stencilStoreOp = clearAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; if (framebuffer.width != image.width || framebuffer.height != image.height) { @@ -114,17 +120,17 @@ namespace dz { VkImageLayout subpassLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.format = image.format; + loadAttachment.format = clearAttachment.format = image.format; - if (attachment.format == VK_FORMAT_UNDEFINED) + if (clearAttachment.format == VK_FORMAT_UNDEFINED) throw std::runtime_error("Attachment format is undefined!"); switch (attachmentType) { case AttachmentType::ColorResolve: { - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + loadAttachment.samples = clearAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + loadAttachment.initialLayout = clearAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + loadAttachment.finalLayout = clearAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; subpassLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; UsingAttachmentReference _ref_{}; #ifdef USING_VULKAN_1_2 @@ -132,14 +138,14 @@ namespace dz { #endif _ref_.attachment = attachmentIndex; _ref_.layout = subpassLayout; - resolveAttachmentRefs.push_back(_ref_); + clearResolveAttachmentRefs.push_back(_ref_); break; } case AttachmentType::DepthResolve: { - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + loadAttachment.samples = clearAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + loadAttachment.initialLayout = clearAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + loadAttachment.finalLayout = clearAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; subpassLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; #ifdef USING_VULKAN_1_2 depthResolveRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; @@ -155,11 +161,11 @@ namespace dz { } case AttachmentType::Color: { - attachment.samples = image.multisampling; - // if (attachment.samples > maxMSAASamples) - // attachment.samples = maxMSAASamples; - attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + loadAttachment.samples = clearAttachment.samples = image.multisampling; + // if (loadAttachment.samples = clearAttachment.samples > maxMSAASamples) + // loadAttachment.samples = clearAttachment.samples = maxMSAASamples; + loadAttachment.initialLayout = clearAttachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + loadAttachment.finalLayout = clearAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subpassLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; UsingAttachmentReference _ref_{}; #ifdef USING_VULKAN_1_2 @@ -167,7 +173,7 @@ namespace dz { #endif _ref_.attachment = attachmentIndex; _ref_.layout = subpassLayout; - colorAttachmentRefs.push_back(_ref_); + clearColorAttachmentRefs.push_back(_ref_); inputSrcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; inputDstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; inputDstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; @@ -184,16 +190,16 @@ namespace dz { { if (hasDepthStencil) throw std::runtime_error("Framebuffer cannot have multiple depth/stencil attachments!"); - attachment.samples = image.multisampling; - // if (attachment.samples > maxMSAASamples) - // attachment.samples = maxMSAASamples; - attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;//(framebuffer.hasDepthResolveAttachment() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + loadAttachment.samples = clearAttachment.samples = image.multisampling; + // if (loadAttachment.samples = clearAttachment.samples > maxMSAASamples) + // loadAttachment.samples = clearAttachment.samples = maxMSAASamples; + loadAttachment.initialLayout = clearAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + loadAttachment.finalLayout = clearAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;//(framebuffer.hasDepthResolveAttachment() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); subpassLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; if (attachmentType != AttachmentType::Depth) { - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + loadAttachment.stencilLoadOp = clearAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + loadAttachment.stencilStoreOp = clearAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; } UsingAttachmentReference _ref_{}; #ifdef USING_VULKAN_1_2 @@ -218,7 +224,8 @@ namespace dz { default: throw std::runtime_error("Unsupported attachment type"); } - vkAttachments.push_back(attachment); + clearAttachments.push_back(clearAttachment); + loadAttachments.push_back(loadAttachment); attachmentIndex++; } @@ -229,10 +236,10 @@ namespace dz { subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; #endif subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = static_cast(colorAttachmentRefs.size()); - subpass.pColorAttachments = colorAttachmentRefs.empty() ? nullptr : colorAttachmentRefs.data(); + subpass.colorAttachmentCount = static_cast(clearColorAttachmentRefs.size()); + subpass.pColorAttachments = clearColorAttachmentRefs.empty() ? nullptr : clearColorAttachmentRefs.data(); subpass.pDepthStencilAttachment = hasDepthStencil ? &depthStencilRef : nullptr; - subpass.pResolveAttachments = resolveAttachmentRefs.data(); + subpass.pResolveAttachments = clearResolveAttachmentRefs.data(); #ifdef USING_VULKAN_1_2 if (requiresDepthResolve) subpass.pNext = &subpassDepthStencilResolve; @@ -264,28 +271,39 @@ namespace dz { dependencies[1].dstAccessMask = outputDstAccessMask; // Updated based on finalLayout dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - UsingRenderPassCreateInfo renderPassInfo{}; + UsingRenderPassCreateInfo clearRenderPassInfo{}; #ifdef USING_VULKAN_1_2 - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; + clearRenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; #endif - renderPassInfo.attachmentCount = static_cast(vkAttachments.size()); - renderPassInfo.pAttachments = vkAttachments.data(); - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = static_cast(dependencies.size()); - renderPassInfo.pDependencies = dependencies.data(); + clearRenderPassInfo.attachmentCount = static_cast(clearAttachments.size()); + clearRenderPassInfo.pAttachments = clearAttachments.data(); + clearRenderPassInfo.subpassCount = 1; + clearRenderPassInfo.pSubpasses = &subpass; + clearRenderPassInfo.dependencyCount = static_cast(dependencies.size()); + clearRenderPassInfo.pDependencies = dependencies.data(); #ifdef USING_VULKAN_1_2 vk_check("vkCreateRenderPass2", - vkCreateRenderPass2(dr.device, &renderPassInfo, nullptr, &framebuffer.renderPass)); + vkCreateRenderPass2(dr.device, &clearRenderPassInfo, nullptr, &framebuffer.clearRenderPass)); #else vk_check("vkCreateRenderPass", - vkCreateRenderPass(dr.device, &renderPassInfo, nullptr, &framebuffer.renderPass)); + vkCreateRenderPass(dr.device, &clearRenderPassInfo, nullptr, &framebuffer.clearRenderPass)); +#endif + + auto loadRenderPassInfo = clearRenderPassInfo; + loadRenderPassInfo.pAttachments = loadAttachments.data(); + +#ifdef USING_VULKAN_1_2 + vk_check("vkCreateRenderPass2", + vkCreateRenderPass2(dr.device, &loadRenderPassInfo, nullptr, &framebuffer.loadRenderPass)); +#else + vk_check("vkCreateRenderPass", + vkCreateRenderPass(dr.device, &loadRenderPassInfo, nullptr, &framebuffer.loadRenderPass)); #endif VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = framebuffer.renderPass; + framebufferInfo.renderPass = framebuffer.clearRenderPass; framebufferInfo.attachmentCount = static_cast(vkImageViews.size()); framebufferInfo.pAttachments = vkImageViews.data(); framebufferInfo.width = framebuffer.width; @@ -321,7 +339,7 @@ namespace dz { framebuffer.clear_changed = true; } - void framebuffer_bind(Framebuffer* framebuffer_ptr) { + void framebuffer_bind(Framebuffer* framebuffer_ptr, bool clear) { if (!framebuffer_ptr) { return; } @@ -341,14 +359,15 @@ namespace dz { framebuffer.render_pass_info_changed = true; } - if (framebuffer.render_pass_info_changed) { + if (framebuffer.clear != clear || framebuffer.render_pass_info_changed) { framebuffer.renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - framebuffer.renderPassInfo.renderPass = framebuffer.renderPass; + framebuffer.renderPassInfo.renderPass = clear ? framebuffer.clearRenderPass : framebuffer.loadRenderPass; framebuffer.renderPassInfo.framebuffer = framebuffer.framebuffer; framebuffer.renderPassInfo.renderArea.offset = {0, 0}; framebuffer.renderPassInfo.renderArea.extent.width = framebuffer.width; framebuffer.renderPassInfo.renderArea.extent.height = framebuffer.height; framebuffer.render_pass_info_changed = false; + framebuffer.clear = clear; } if (framebuffer.clear_changed) { @@ -492,7 +511,8 @@ namespace dz { free(framebuffer.pImages); if (framebuffer.pAttachmentTypes) free(framebuffer.pAttachmentTypes); - vkDestroyRenderPass(dr.device, framebuffer.renderPass, 0); + vkDestroyRenderPass(dr.device, framebuffer.clearRenderPass, 0); + vkDestroyRenderPass(dr.device, framebuffer.loadRenderPass, 0); vkDestroyFramebuffer(dr.device, framebuffer.framebuffer, 0); vkDestroyEvent(dr.device, framebuffer.event, 0); vkFreeCommandBuffers(dr.device, dr.commandPool, 1, &framebuffer.commandBuffer); @@ -550,7 +570,7 @@ namespace dz { VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = framebuffer.renderPass; + framebufferInfo.renderPass = framebuffer.clearRenderPass; framebufferInfo.attachmentCount = static_cast(vkImageViews.size()); framebufferInfo.pAttachments = vkImageViews.data(); framebufferInfo.width = framebuffer.width; @@ -590,6 +610,9 @@ namespace dz { return nullptr; } + BlendState BlendState::Disabled = { + .enable = false + }; BlendState BlendState::MainFramebuffer = { true, BlendFactor::One, diff --git a/src/Framebuffer.cpp.hpp b/src/Framebuffer.cpp.hpp index 4f57be32..9a8bfc5a 100644 --- a/src/Framebuffer.cpp.hpp +++ b/src/Framebuffer.cpp.hpp @@ -12,7 +12,8 @@ namespace dz { bool own_images; VkCommandBuffer commandBuffer; - VkRenderPass renderPass; + VkRenderPass clearRenderPass; + VkRenderPass loadRenderPass; VkFramebuffer framebuffer; uint32_t attachmentsSize; uint32_t width; @@ -35,5 +36,7 @@ namespace dz { Image** new_pImages = 0; VkFramebuffer new_framebuffer = VK_NULL_HANDLE; + + bool clear = true; }; } \ No newline at end of file diff --git a/src/ImagePack.cpp b/src/ImagePack.cpp index 9acdd25a..a53f4495 100644 --- a/src/ImagePack.cpp +++ b/src/ImagePack.cpp @@ -212,11 +212,13 @@ void dz::ImagePack::repack() .height = uint32_t(atlas_height), .data = rgba }); + owns_atlas = true; } } else if (image_vec_size) { atlas = image_vec[0]; + owns_atlas = false; } } size_t dz::ImagePack::findImageIndex(Image* image) diff --git a/src/Loaders/STB_Image_Loader.cpp b/src/Loaders/STB_Image_Loader.cpp index 14c62c19..44873663 100644 --- a/src/Loaders/STB_Image_Loader.cpp +++ b/src/Loaders/STB_Image_Loader.cpp @@ -48,7 +48,7 @@ dz::Image* STB_Image_load_path(const std::filesystem::path& path) { 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_image(imageData, width, height, nrChannels); + return STB_Image_load_image(imageData, width, height, (std::max)(nrChannels, minChannels)); } dz::Image* STB_Image_load_bytes(const std::shared_ptr& bytes, size_t bytes_length) { diff --git a/src/Shader.cpp b/src/Shader.cpp index 091ab910..e6e86ae0 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -113,7 +113,7 @@ namespace dz { void shader_set_render_pass(Shader* shader_ptr, Framebuffer* framebuffer_ptr) { if (!shader_ptr || !framebuffer_ptr) return; - shader_ptr->renderPass = framebuffer_ptr->renderPass; + shader_ptr->renderPass = framebuffer_ptr->clearRenderPass; } void shader_include_asset_pack(Shader* shader, AssetPack* asset_pack) { @@ -1778,12 +1778,12 @@ namespace dz { VkPipelineRasterizationStateCreateInfo rasterizer{}; rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; + rasterizer.depthClampEnable = shader->depth_clamp_enabled; rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.polygonMode = shader->polygon_mode; + rasterizer.lineWidth = shader->line_width; + rasterizer.cullMode = shader->cull_mode; + rasterizer.frontFace = shader->front_face; rasterizer.depthBiasEnable = VK_FALSE; VkPipelineMultisampleStateCreateInfo multisampling{}; @@ -1793,18 +1793,20 @@ namespace dz { VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencil.depthTestEnable = VK_TRUE; - depthStencil.depthWriteEnable = VK_TRUE; - depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthTestEnable = shader->depth_test_enabled; + depthStencil.depthWriteEnable = shader->depth_write_enabled; + depthStencil.depthCompareOp = shader->depth_compare_op; + depthStencil.depthBoundsTestEnable = shader->depth_bounds_test_enabled; + depthStencil.stencilTestEnable = shader->stencil_test_enabled; VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.blendEnable = VK_FALSE; - colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.blendEnable = shader->blend_state.enable; + colorBlendAttachment.srcColorBlendFactor = (VkBlendFactor)shader->blend_state.srcColor; + colorBlendAttachment.dstColorBlendFactor = (VkBlendFactor)shader->blend_state.dstColor; + colorBlendAttachment.colorBlendOp = (VkBlendOp)shader->blend_state.colorOp; + colorBlendAttachment.srcAlphaBlendFactor = (VkBlendFactor)shader->blend_state.srcAlpha; + colorBlendAttachment.dstAlphaBlendFactor = (VkBlendFactor)shader->blend_state.dstAlpha; + colorBlendAttachment.alphaBlendOp = (VkBlendOp)shader->blend_state.alphaOp; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; @@ -1966,6 +1968,9 @@ namespace dz { size_t screen_draw_list_index = 0; size_t fb_draw_list_index = 0; + static std::unordered_map framebuffers_cleared; + framebuffers_cleared.clear(); + for (auto& drawInformation_ptr : renderer->vec_draw_information) { auto& drawInformation = *drawInformation_ptr; for (auto& cameraDrawInfo : drawInformation.cameraDrawInfos) { @@ -1991,7 +1996,9 @@ namespace dz { if (camera_pre_render_fn) camera_pre_render_fn(); auto framebuffer_ptr = std::get<0>(fb_tuple); - framebuffer_bind(framebuffer_ptr); + auto& cleared = framebuffers_cleared[framebuffer_ptr]; + framebuffer_bind(framebuffer_ptr, !cleared); + cleared = true; draw_shader_draw_list(renderer, *std::get<1>(fb_tuple)); framebuffer_unbind(framebuffer_ptr); } @@ -2179,4 +2186,48 @@ namespace dz { assert(false); return (VkShaderStageFlags)0; } + + void shader_set_line_width(Shader* shader, float line_width) { + shader->line_width = line_width; + } + + void shader_set_depth_test(Shader* shader, bool enabled) { + shader->depth_test_enabled = enabled; + } + + void shader_set_depth_write(Shader* shader, bool write_enabled) { + shader->depth_write_enabled = write_enabled; + } + + void shader_set_depth_clamp(Shader* shader, bool clamp_enabled) { + shader->depth_clamp_enabled = clamp_enabled; + } + + void shader_set_polygon_mode(Shader* shader, VkPolygonMode polygon_mode) { + shader->polygon_mode = polygon_mode; + } + + void shader_set_depth_compare_op(Shader* shader, VkCompareOp compare_op) { + shader->depth_compare_op = compare_op; + } + + void shader_set_cull_mode(Shader* shader, VkCullModeFlags cull_mode) { + shader->cull_mode = cull_mode; + } + + void shader_set_front_face(Shader* shader, VkFrontFace front_face) { + shader->front_face = front_face; + } + + void shader_set_blend_state(Shader* shader, BlendState blend_state) { + shader->blend_state = blend_state; + } + + void shader_set_depth_bounds_test(Shader* shader, bool enabled) { + shader->depth_bounds_test_enabled = enabled; + } + + void shader_set_stencil_test(Shader* shader, bool enabled) { + shader->stencil_test_enabled = enabled; + } } \ No newline at end of file diff --git a/src/Shader.cpp.hpp b/src/Shader.cpp.hpp index 18a5cc8d..c70e51c3 100644 --- a/src/Shader.cpp.hpp +++ b/src/Shader.cpp.hpp @@ -218,6 +218,17 @@ namespace dz { VkRenderPass renderPass = VK_NULL_HANDLE; std::unordered_map sampler_key_image_override_map; std::unordered_map keyed_set_binding_index_map; + float line_width = 1.0f; + bool depth_test_enabled = true; + bool depth_write_enabled = true; + bool depth_clamp_enabled = false; + VkPolygonMode polygon_mode = VK_POLYGON_MODE_FILL; + VkCompareOp depth_compare_op = VK_COMPARE_OP_LESS; + VkCullModeFlags cull_mode = VK_CULL_MODE_BACK_BIT; + VkFrontFace front_face = VK_FRONT_FACE_CLOCKWISE; + BlendState blend_state = BlendState::Disabled; + bool depth_bounds_test_enabled = false; + bool stencil_test_enabled = false; }; struct BufferGroup { diff --git a/tests/ECS.cpp b/tests/ECS.cpp index a3aa7477..8d538303 100644 --- a/tests/ECS.cpp +++ b/tests/ECS.cpp @@ -20,9 +20,11 @@ using ExampleECS = ECS< Mesh, SubMesh, Camera, - Material + Material, + HDRI, + SkyBox #ifdef ENABLE_LIGHTS - , Light, PhongLighting + , Light, PhysicallyBasedLighting #endif >; @@ -98,9 +100,24 @@ int main() { auto& ecs = *ecs_ptr; if (!state_loaded) { - auto cam3_id = ecs.AddCamera(Camera{}, Camera::Perspective); + int autumn_hdri_index = -1; + auto autumn_hdri_id = ecs.AddHDRI(HDRI{}, autumn_hdri_index, "hdri/autumn_field_puresky_4k"); + ecs.SetHDRIImage(autumn_hdri_id, TL::Load(STB_Image_Info{ + .path = "hdri/autumn_field_puresky_4k.hdr" + })); + + int afternoon_hdri_index = -1; + auto afternoon_hdri_id = ecs.AddHDRI(HDRI{}, afternoon_hdri_index, "zwartkops_straight_afternoon_4k"); + ecs.SetHDRIImage(afternoon_hdri_id, TL::Load(STB_Image_Info{ + .path = "hdri/zwartkops_straight_afternoon_4k.hdr" + })); + + auto sky_scene_id = ecs.AddScene(Scene{}, "Sky Scene"); + + ecs.AddCamera(sky_scene_id, Camera::DefaultPerspective, "Sky Camera"); Assimp_Info base_info{ + .parent_id = sky_scene_id, .add_scene_function = [&](auto parent_id, const auto& name, auto position, auto rotation, auto scale) { return ecs.AddScene(parent_id, Scene{ .position = position, @@ -122,7 +139,7 @@ int main() { }, .add_material_function = [&](const auto& name, const auto& images_vec) -> MaterialPair { int out_index = -1; - auto out_id = ecs.AddMaterial(Material{}, out_index); + auto out_id = ecs.AddMaterial(Material{}, out_index, name); ecs.SetMaterialImages(out_id, images_vec); return {out_id, out_index}; } @@ -140,13 +157,25 @@ int main() { TL::Load(golden_sports_car_info); - ecs.AddLight(Light{ + ecs.AddLight(sky_scene_id, Light{ .type = uint32_t(Light::Directional), .intensity = 1.f, .position = {0, 10, 0}, .direction = {0, -1, 0}, .color = {1, 1, 1} }, "Directional Light"); + + ecs.AddSkyBox(sky_scene_id, SkyBox{ + .hdri_index = autumn_hdri_index + }, "Pure Sky SkyBox"); + + auto afternoon_scene_id = ecs.AddScene(Scene{}, "Afternoon Scene"); + + ecs.AddCamera(afternoon_scene_id, Camera::DefaultPerspective, "Afternoon Camera"); + + ecs.AddSkyBox(afternoon_scene_id, SkyBox{ + .hdri_index = afternoon_hdri_index + }, "Afternoon SkyBox"); } ecs.MarkReady(); @@ -1174,23 +1203,23 @@ void DrawDropTarget(ReflectableGroup& target_group, ReflectableGroup* dragged_gr switch (dragged_group->cid) { case Entity::PID: { - auto& entity = ecs_ptr->GetEntity(dragged_group->id); - ExampleECS::SetWhoParent(entity, new_parent_ptr); + ExampleECS::SetWhoParent(ecs_ptr->GetEntity(dragged_group->id), new_parent_ptr); break; } case Camera::PID: { - auto& camera = ecs_ptr->GetCamera(dragged_group->id); - ExampleECS::SetWhoParent(camera, new_parent_ptr); + ExampleECS::SetWhoParent(ecs_ptr->GetCamera(dragged_group->id), new_parent_ptr); break; } case Scene::PID: { - auto& scene = ecs_ptr->GetScene(dragged_group->id); - ExampleECS::SetWhoParent(scene, new_parent_ptr); + ExampleECS::SetWhoParent(ecs_ptr->GetScene(dragged_group->id), new_parent_ptr); break; } case SubMesh::PID: { - auto& submesh = ecs_ptr->GetSubMesh(dragged_group->id); - ExampleECS::SetWhoParent(submesh, new_parent_ptr); + ExampleECS::SetWhoParent(ecs_ptr->GetSubMesh(dragged_group->id), new_parent_ptr); + break; + } + case SkyBox::PID: { + ExampleECS::SetWhoParent(ecs_ptr->GetSkyBox(dragged_group->id), new_parent_ptr); break; } } diff --git a/tests/LineGrid.cpp b/tests/LineGrid.cpp index 827e7628..56d0c315 100644 --- a/tests/LineGrid.cpp +++ b/tests/LineGrid.cpp @@ -33,10 +33,8 @@ int main() auto render_line_grid_shader = shader_create(ShaderTopology::LineStrip); - DrawListManager line_draw_list_mg("Lines", [&](auto buffer_group, auto& line) -> DrawTuples { - return { - {render_line_grid_shader, line.vert_count} - }; + DrawListManager line_draw_list_mg("Lines", [&](auto buffer_group, auto& line) -> DrawTuple { + return { render_line_grid_shader, line.vert_count }; }); window_add_drawn_buffer_group(window, &line_draw_list_mg, line_buffer_group); diff --git a/tests/Particle2D.cpp b/tests/Particle2D.cpp index b5227d39..0aa13c25 100644 --- a/tests/Particle2D.cpp +++ b/tests/Particle2D.cpp @@ -96,10 +96,8 @@ int main() auto render_shader = shader_create(); auto diffuse_density_shader = shader_create(); - DrawListManager quad_draw_list_mg("Quads", [&](auto buffer_group, auto& quad) -> DrawTuples { - return { - {render_shader, 6} - }; + DrawListManager quad_draw_list_mg("Quads", [&](auto buffer_group, auto& quad) -> DrawTuple { + return { render_shader, 6 }; }); window_add_drawn_buffer_group(window, &quad_draw_list_mg, quad_group); diff --git a/tests/ShaderReflect.cpp b/tests/ShaderReflect.cpp index 053728ba..c95edb9d 100644 --- a/tests/ShaderReflect.cpp +++ b/tests/ShaderReflect.cpp @@ -259,7 +259,7 @@ void main() { auto green_entity_shader = shader_create(); set_shader_defines(green_entity_shader); - DrawListManager entity_draw_list_mg("Entitys", [&](auto buffer_group, auto& entity) -> DrawTuples { + DrawListManager entity_draw_list_mg("Entitys", [&](auto buffer_group, auto& entity) -> DrawTuple { auto mesh_index = entity.index_meta[0]; auto material_index = entity.index_meta[1]; auto mesh_view = buffer_group_get_buffer_element_view(buffer_group, "Meshes", mesh_index); @@ -285,9 +285,7 @@ void main() { vert_count = 6; break; } - return { - {chosen_shader, vert_count} - }; + return { chosen_shader, vert_count }; }); window_add_drawn_buffer_group(main_window, &entity_draw_list_mg, main_buffer_group); diff --git a/tests/x-platform/src/app-lib.cpp b/tests/x-platform/src/app-lib.cpp index d19d4329..05e3db33 100644 --- a/tests/x-platform/src/app-lib.cpp +++ b/tests/x-platform/src/app-lib.cpp @@ -69,12 +69,10 @@ DZ_EXPORT EventInterface* init(const WindowCreateInfo& window_info) shader_include_asset_pack(raster_shader, asset_pack); - quad_draw_list_mg_ptr = std::make_shared>("Quads", [&](auto buffer_group, auto& quad) -> DrawTuples { + quad_draw_list_mg_ptr = std::make_shared>("Quads", [&](auto buffer_group, auto& quad) -> DrawTuple { auto chosen_shader = raster_shader; uint32_t vert_count = 6; - return { - {chosen_shader, vert_count} - }; + return { chosen_shader, vert_count }; }); auto& quad_draw_list_mg = *quad_draw_list_mg_ptr;