From 43821b0cffc5aa419c0218992f06f8962ae54a13 Mon Sep 17 00:00:00 2001 From: Frederico Linhares Date: Wed, 8 May 2024 17:56:29 -0300 Subject: refa Rename graphical engine to BluCat --- src/binary_reader.hpp | 4 +- src/blucat/animation.cpp | 27 ++ src/blucat/animation.hpp | 51 +++ src/blucat/animation/frame.hpp | 85 ++++ src/blucat/base_buffer.cpp | 96 ++++ src/blucat/base_buffer.hpp | 56 +++ src/blucat/character.cpp | 274 +++++++++++ src/blucat/character.hpp | 49 ++ src/blucat/command_pool.cpp | 87 ++++ src/blucat/command_pool.hpp | 59 +++ src/blucat/core.hpp | 34 ++ src/blucat/descriptor_set_layout.cpp | 197 ++++++++ src/blucat/descriptor_set_layout.hpp | 38 ++ src/blucat/destination_buffer.cpp | 109 +++++ src/blucat/destination_buffer.hpp | 54 +++ src/blucat/device.cpp | 392 ++++++++++++++++ src/blucat/device.hpp | 69 +++ src/blucat/font.cpp | 53 +++ src/blucat/font.hpp | 42 ++ src/blucat/framebuffer.cpp | 198 ++++++++ src/blucat/framebuffer.hpp | 43 ++ src/blucat/graphics_pipeline_2d_solid.cpp | 297 ++++++++++++ src/blucat/graphics_pipeline_2d_solid.hpp | 44 ++ src/blucat/graphics_pipeline_2d_solid_layout.cpp | 83 ++++ src/blucat/graphics_pipeline_2d_solid_layout.hpp | 35 ++ src/blucat/graphics_pipeline_2d_wired.cpp | 313 +++++++++++++ src/blucat/graphics_pipeline_2d_wired.hpp | 47 ++ src/blucat/graphics_pipeline_2d_wired_layout.cpp | 87 ++++ src/blucat/graphics_pipeline_2d_wired_layout.hpp | 35 ++ src/blucat/graphics_pipeline_3d.cpp | 307 +++++++++++++ src/blucat/graphics_pipeline_3d.hpp | 43 ++ src/blucat/graphics_pipeline_3d_layout.cpp | 79 ++++ src/blucat/graphics_pipeline_3d_layout.hpp | 35 ++ src/blucat/graphics_pipeline_3d_skeletal.cpp | 322 +++++++++++++ src/blucat/graphics_pipeline_3d_skeletal.hpp | 43 ++ src/blucat/graphics_pipeline_sprite_3d.cpp | 315 +++++++++++++ src/blucat/graphics_pipeline_sprite_3d.hpp | 44 ++ src/blucat/image.cpp | 149 ++++++ src/blucat/image.hpp | 73 +++ src/blucat/light.cpp | 205 +++++++++ src/blucat/light.hpp | 41 ++ src/blucat/qoi.cpp | 205 +++++++++ src/blucat/qoi.hpp | 41 ++ src/blucat/queue.cpp | 61 +++ src/blucat/queue.hpp | 82 ++++ src/blucat/queue_family.cpp | 84 ++++ src/blucat/queue_family.hpp | 58 +++ src/blucat/rectangle.cpp | 30 ++ src/blucat/rectangle.hpp | 42 ++ src/blucat/render_pass.cpp | 203 ++++++++ src/blucat/render_pass.hpp | 36 ++ src/blucat/renderer.cpp | 413 +++++++++++++++++ src/blucat/renderer.hpp | 72 +++ src/blucat/skeletal_mesh.cpp | 204 +++++++++ src/blucat/skeletal_mesh.hpp | 52 +++ src/blucat/skeletal_mesh_vertex.hpp | 42 ++ src/blucat/skeletal_model.cpp | 238 ++++++++++ src/blucat/skeletal_model.hpp | 55 +++ src/blucat/source_buffer.cpp | 87 ++++ src/blucat/source_buffer.hpp | 45 ++ src/blucat/sprite.cpp | 99 ++++ src/blucat/sprite.hpp | 50 ++ src/blucat/sprite_3d.cpp | 168 +++++++ src/blucat/sprite_3d.hpp | 46 ++ src/blucat/sprite_to_draw.cpp | 40 ++ src/blucat/sprite_to_draw.hpp | 44 ++ src/blucat/static_mesh.cpp | 132 ++++++ src/blucat/static_mesh.hpp | 48 ++ src/blucat/static_mesh_vertex.hpp | 34 ++ src/blucat/static_model.cpp | 165 +++++++ src/blucat/static_model.hpp | 49 ++ src/blucat/swapchain.cpp | 204 +++++++++ src/blucat/swapchain.hpp | 47 ++ src/blucat/texture.cpp | 559 +++++++++++++++++++++++ src/blucat/texture.hpp | 51 +++ src/blucat/uniform_buffer.cpp | 89 ++++ src/blucat/uniform_buffer.hpp | 49 ++ src/blucat/uniform_data_object.hpp | 80 ++++ src/blucat/view_2d.cpp | 160 +++++++ src/blucat/view_2d.hpp | 60 +++ src/blucat/view_3d.cpp | 155 +++++++ src/blucat/view_3d.hpp | 48 ++ src/candy_gear.cpp | 12 +- src/core.cpp | 148 +++--- src/core.hpp | 64 +-- src/font.cpp | 14 +- src/skeletal_mesh.cpp | 18 +- src/skeletal_model.cpp | 28 +- src/sprite.cpp | 24 +- src/sprite_3d.cpp | 20 +- src/static_mesh.cpp | 16 +- src/static_model.cpp | 30 +- src/texture.cpp | 36 +- src/vector_4d.cpp | 6 +- src/view_2d.cpp | 30 +- src/view_2d.hpp | 6 +- src/view_3d.cpp | 26 +- src/vk/animation.cpp | 27 -- src/vk/animation.hpp | 51 --- src/vk/animation/frame.hpp | 85 ---- src/vk/base_buffer.cpp | 96 ---- src/vk/base_buffer.hpp | 56 --- src/vk/character.cpp | 274 ----------- src/vk/character.hpp | 49 -- src/vk/command_pool.cpp | 87 ---- src/vk/command_pool.hpp | 59 --- src/vk/core.hpp | 34 -- src/vk/descriptor_set_layout.cpp | 197 -------- src/vk/descriptor_set_layout.hpp | 38 -- src/vk/destination_buffer.cpp | 109 ----- src/vk/destination_buffer.hpp | 54 --- src/vk/device.cpp | 392 ---------------- src/vk/device.hpp | 69 --- src/vk/font.cpp | 53 --- src/vk/font.hpp | 42 -- src/vk/framebuffer.cpp | 198 -------- src/vk/framebuffer.hpp | 43 -- src/vk/graphics_pipeline_2d_solid.cpp | 297 ------------ src/vk/graphics_pipeline_2d_solid.hpp | 44 -- src/vk/graphics_pipeline_2d_solid_layout.cpp | 83 ---- src/vk/graphics_pipeline_2d_solid_layout.hpp | 35 -- src/vk/graphics_pipeline_2d_wired.cpp | 313 ------------- src/vk/graphics_pipeline_2d_wired.hpp | 47 -- src/vk/graphics_pipeline_2d_wired_layout.cpp | 87 ---- src/vk/graphics_pipeline_2d_wired_layout.hpp | 35 -- src/vk/graphics_pipeline_3d.cpp | 307 ------------- src/vk/graphics_pipeline_3d.hpp | 43 -- src/vk/graphics_pipeline_3d_layout.cpp | 79 ---- src/vk/graphics_pipeline_3d_layout.hpp | 35 -- src/vk/graphics_pipeline_3d_skeletal.cpp | 322 ------------- src/vk/graphics_pipeline_3d_skeletal.hpp | 43 -- src/vk/graphics_pipeline_sprite_3d.cpp | 315 ------------- src/vk/graphics_pipeline_sprite_3d.hpp | 44 -- src/vk/image.cpp | 149 ------ src/vk/image.hpp | 73 --- src/vk/light.cpp | 205 --------- src/vk/light.hpp | 41 -- src/vk/qoi.cpp | 205 --------- src/vk/qoi.hpp | 41 -- src/vk/queue.cpp | 61 --- src/vk/queue.hpp | 82 ---- src/vk/queue_family.cpp | 84 ---- src/vk/queue_family.hpp | 58 --- src/vk/rectangle.cpp | 30 -- src/vk/rectangle.hpp | 42 -- src/vk/render_pass.cpp | 203 -------- src/vk/render_pass.hpp | 36 -- src/vk/renderer.cpp | 413 ----------------- src/vk/renderer.hpp | 72 --- src/vk/skeletal_mesh.cpp | 204 --------- src/vk/skeletal_mesh.hpp | 52 --- src/vk/skeletal_mesh_vertex.hpp | 42 -- src/vk/skeletal_model.cpp | 238 ---------- src/vk/skeletal_model.hpp | 55 --- src/vk/source_buffer.cpp | 87 ---- src/vk/source_buffer.hpp | 45 -- src/vk/sprite.cpp | 99 ---- src/vk/sprite.hpp | 50 -- src/vk/sprite_3d.cpp | 168 ------- src/vk/sprite_3d.hpp | 46 -- src/vk/sprite_to_draw.cpp | 40 -- src/vk/sprite_to_draw.hpp | 44 -- src/vk/static_mesh.cpp | 132 ------ src/vk/static_mesh.hpp | 48 -- src/vk/static_mesh_vertex.hpp | 34 -- src/vk/static_model.cpp | 165 ------- src/vk/static_model.hpp | 49 -- src/vk/swapchain.cpp | 204 --------- src/vk/swapchain.hpp | 47 -- src/vk/texture.cpp | 559 ----------------------- src/vk/texture.hpp | 51 --- src/vk/uniform_buffer.cpp | 89 ---- src/vk/uniform_buffer.hpp | 49 -- src/vk/uniform_data_object.hpp | 80 ---- src/vk/view_2d.cpp | 160 ------- src/vk/view_2d.hpp | 60 --- src/vk/view_3d.cpp | 155 ------- src/vk/view_3d.hpp | 48 -- 178 files changed, 9278 insertions(+), 9278 deletions(-) create mode 100644 src/blucat/animation.cpp create mode 100644 src/blucat/animation.hpp create mode 100644 src/blucat/animation/frame.hpp create mode 100644 src/blucat/base_buffer.cpp create mode 100644 src/blucat/base_buffer.hpp create mode 100644 src/blucat/character.cpp create mode 100644 src/blucat/character.hpp create mode 100644 src/blucat/command_pool.cpp create mode 100644 src/blucat/command_pool.hpp create mode 100644 src/blucat/core.hpp create mode 100644 src/blucat/descriptor_set_layout.cpp create mode 100644 src/blucat/descriptor_set_layout.hpp create mode 100644 src/blucat/destination_buffer.cpp create mode 100644 src/blucat/destination_buffer.hpp create mode 100644 src/blucat/device.cpp create mode 100644 src/blucat/device.hpp create mode 100644 src/blucat/font.cpp create mode 100644 src/blucat/font.hpp create mode 100644 src/blucat/framebuffer.cpp create mode 100644 src/blucat/framebuffer.hpp create mode 100644 src/blucat/graphics_pipeline_2d_solid.cpp create mode 100644 src/blucat/graphics_pipeline_2d_solid.hpp create mode 100644 src/blucat/graphics_pipeline_2d_solid_layout.cpp create mode 100644 src/blucat/graphics_pipeline_2d_solid_layout.hpp create mode 100644 src/blucat/graphics_pipeline_2d_wired.cpp create mode 100644 src/blucat/graphics_pipeline_2d_wired.hpp create mode 100644 src/blucat/graphics_pipeline_2d_wired_layout.cpp create mode 100644 src/blucat/graphics_pipeline_2d_wired_layout.hpp create mode 100644 src/blucat/graphics_pipeline_3d.cpp create mode 100644 src/blucat/graphics_pipeline_3d.hpp create mode 100644 src/blucat/graphics_pipeline_3d_layout.cpp create mode 100644 src/blucat/graphics_pipeline_3d_layout.hpp create mode 100644 src/blucat/graphics_pipeline_3d_skeletal.cpp create mode 100644 src/blucat/graphics_pipeline_3d_skeletal.hpp create mode 100644 src/blucat/graphics_pipeline_sprite_3d.cpp create mode 100644 src/blucat/graphics_pipeline_sprite_3d.hpp create mode 100644 src/blucat/image.cpp create mode 100644 src/blucat/image.hpp create mode 100644 src/blucat/light.cpp create mode 100644 src/blucat/light.hpp create mode 100644 src/blucat/qoi.cpp create mode 100644 src/blucat/qoi.hpp create mode 100644 src/blucat/queue.cpp create mode 100644 src/blucat/queue.hpp create mode 100644 src/blucat/queue_family.cpp create mode 100644 src/blucat/queue_family.hpp create mode 100644 src/blucat/rectangle.cpp create mode 100644 src/blucat/rectangle.hpp create mode 100644 src/blucat/render_pass.cpp create mode 100644 src/blucat/render_pass.hpp create mode 100644 src/blucat/renderer.cpp create mode 100644 src/blucat/renderer.hpp create mode 100644 src/blucat/skeletal_mesh.cpp create mode 100644 src/blucat/skeletal_mesh.hpp create mode 100644 src/blucat/skeletal_mesh_vertex.hpp create mode 100644 src/blucat/skeletal_model.cpp create mode 100644 src/blucat/skeletal_model.hpp create mode 100644 src/blucat/source_buffer.cpp create mode 100644 src/blucat/source_buffer.hpp create mode 100644 src/blucat/sprite.cpp create mode 100644 src/blucat/sprite.hpp create mode 100644 src/blucat/sprite_3d.cpp create mode 100644 src/blucat/sprite_3d.hpp create mode 100644 src/blucat/sprite_to_draw.cpp create mode 100644 src/blucat/sprite_to_draw.hpp create mode 100644 src/blucat/static_mesh.cpp create mode 100644 src/blucat/static_mesh.hpp create mode 100644 src/blucat/static_mesh_vertex.hpp create mode 100644 src/blucat/static_model.cpp create mode 100644 src/blucat/static_model.hpp create mode 100644 src/blucat/swapchain.cpp create mode 100644 src/blucat/swapchain.hpp create mode 100644 src/blucat/texture.cpp create mode 100644 src/blucat/texture.hpp create mode 100644 src/blucat/uniform_buffer.cpp create mode 100644 src/blucat/uniform_buffer.hpp create mode 100644 src/blucat/uniform_data_object.hpp create mode 100644 src/blucat/view_2d.cpp create mode 100644 src/blucat/view_2d.hpp create mode 100644 src/blucat/view_3d.cpp create mode 100644 src/blucat/view_3d.hpp delete mode 100644 src/vk/animation.cpp delete mode 100644 src/vk/animation.hpp delete mode 100644 src/vk/animation/frame.hpp delete mode 100644 src/vk/base_buffer.cpp delete mode 100644 src/vk/base_buffer.hpp delete mode 100644 src/vk/character.cpp delete mode 100644 src/vk/character.hpp delete mode 100644 src/vk/command_pool.cpp delete mode 100644 src/vk/command_pool.hpp delete mode 100644 src/vk/core.hpp delete mode 100644 src/vk/descriptor_set_layout.cpp delete mode 100644 src/vk/descriptor_set_layout.hpp delete mode 100644 src/vk/destination_buffer.cpp delete mode 100644 src/vk/destination_buffer.hpp delete mode 100644 src/vk/device.cpp delete mode 100644 src/vk/device.hpp delete mode 100644 src/vk/font.cpp delete mode 100644 src/vk/font.hpp delete mode 100644 src/vk/framebuffer.cpp delete mode 100644 src/vk/framebuffer.hpp delete mode 100644 src/vk/graphics_pipeline_2d_solid.cpp delete mode 100644 src/vk/graphics_pipeline_2d_solid.hpp delete mode 100644 src/vk/graphics_pipeline_2d_solid_layout.cpp delete mode 100644 src/vk/graphics_pipeline_2d_solid_layout.hpp delete mode 100644 src/vk/graphics_pipeline_2d_wired.cpp delete mode 100644 src/vk/graphics_pipeline_2d_wired.hpp delete mode 100644 src/vk/graphics_pipeline_2d_wired_layout.cpp delete mode 100644 src/vk/graphics_pipeline_2d_wired_layout.hpp delete mode 100644 src/vk/graphics_pipeline_3d.cpp delete mode 100644 src/vk/graphics_pipeline_3d.hpp delete mode 100644 src/vk/graphics_pipeline_3d_layout.cpp delete mode 100644 src/vk/graphics_pipeline_3d_layout.hpp delete mode 100644 src/vk/graphics_pipeline_3d_skeletal.cpp delete mode 100644 src/vk/graphics_pipeline_3d_skeletal.hpp delete mode 100644 src/vk/graphics_pipeline_sprite_3d.cpp delete mode 100644 src/vk/graphics_pipeline_sprite_3d.hpp delete mode 100644 src/vk/image.cpp delete mode 100644 src/vk/image.hpp delete mode 100644 src/vk/light.cpp delete mode 100644 src/vk/light.hpp delete mode 100644 src/vk/qoi.cpp delete mode 100644 src/vk/qoi.hpp delete mode 100644 src/vk/queue.cpp delete mode 100644 src/vk/queue.hpp delete mode 100644 src/vk/queue_family.cpp delete mode 100644 src/vk/queue_family.hpp delete mode 100644 src/vk/rectangle.cpp delete mode 100644 src/vk/rectangle.hpp delete mode 100644 src/vk/render_pass.cpp delete mode 100644 src/vk/render_pass.hpp delete mode 100644 src/vk/renderer.cpp delete mode 100644 src/vk/renderer.hpp delete mode 100644 src/vk/skeletal_mesh.cpp delete mode 100644 src/vk/skeletal_mesh.hpp delete mode 100644 src/vk/skeletal_mesh_vertex.hpp delete mode 100644 src/vk/skeletal_model.cpp delete mode 100644 src/vk/skeletal_model.hpp delete mode 100644 src/vk/source_buffer.cpp delete mode 100644 src/vk/source_buffer.hpp delete mode 100644 src/vk/sprite.cpp delete mode 100644 src/vk/sprite.hpp delete mode 100644 src/vk/sprite_3d.cpp delete mode 100644 src/vk/sprite_3d.hpp delete mode 100644 src/vk/sprite_to_draw.cpp delete mode 100644 src/vk/sprite_to_draw.hpp delete mode 100644 src/vk/static_mesh.cpp delete mode 100644 src/vk/static_mesh.hpp delete mode 100644 src/vk/static_mesh_vertex.hpp delete mode 100644 src/vk/static_model.cpp delete mode 100644 src/vk/static_model.hpp delete mode 100644 src/vk/swapchain.cpp delete mode 100644 src/vk/swapchain.hpp delete mode 100644 src/vk/texture.cpp delete mode 100644 src/vk/texture.hpp delete mode 100644 src/vk/uniform_buffer.cpp delete mode 100644 src/vk/uniform_buffer.hpp delete mode 100644 src/vk/uniform_data_object.hpp delete mode 100644 src/vk/view_2d.cpp delete mode 100644 src/vk/view_2d.hpp delete mode 100644 src/vk/view_3d.cpp delete mode 100644 src/vk/view_3d.hpp diff --git a/src/binary_reader.hpp b/src/binary_reader.hpp index 5dbff54..e09c13a 100644 --- a/src/binary_reader.hpp +++ b/src/binary_reader.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ #include #include -#include "vk/core.hpp" +#include "blucat/core.hpp" class BinaryReader { diff --git a/src/blucat/animation.cpp b/src/blucat/animation.cpp new file mode 100644 index 0000000..b4daeef --- /dev/null +++ b/src/blucat/animation.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "animation.hpp" + +namespace BluCat +{ + +Bone::Bone(glm::mat4 offset_matrix): + offset_matrix{offset_matrix} +{ +} + +} diff --git a/src/blucat/animation.hpp b/src/blucat/animation.hpp new file mode 100644 index 0000000..c789c5e --- /dev/null +++ b/src/blucat/animation.hpp @@ -0,0 +1,51 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_ANIMATION_H +#define CANDY_GEAR_BLUCAT_ANIMATION_H 1 + +#include + +#include "core.hpp" +#include "animation/frame.hpp" + +namespace BluCat +{ + +struct Bone +{ + glm::mat4x4 offset_matrix; + + Bone(glm::mat4 offset_matrix); +}; + +struct BoneTransform +{ + uint32_t bone_id; + Channel positions; + Channel rotations; + Channel scales; +}; + +struct Animation +{ + std::vector bone_transforms; + float final_time; +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_ANIMATION_H */ diff --git a/src/blucat/animation/frame.hpp b/src/blucat/animation/frame.hpp new file mode 100644 index 0000000..a1d5f39 --- /dev/null +++ b/src/blucat/animation/frame.hpp @@ -0,0 +1,85 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_FRAME_H +#define CANDY_GEAR_BLUCAT_FRAME_H 1 + +#include + +#include "../core.hpp" + +namespace BluCat +{ + +template +struct Frame +{ + const T value; + const float timestamp; + + Frame(T value, float timestamp): + value{value}, + timestamp{timestamp} + { + } + +}; + +template +struct Channel +{ + int current_index{0}; + std::vector> key_frames; + + inline glm::mat4 + interpolate( + float animation_time, + glm::mat4 (*single_frame)(T frame), + glm::mat4 (*multiple_frames)(T current_frame, T next_frame, float scale)) + { + if(this->key_frames.size() == 1) + return single_frame(this->key_frames[0].value); + else + { + while(animation_time > this->key_frames[current_index].timestamp) + this->current_index++; + + float scale_factor; + Frame *previous_frame; + Frame *next_frame{&(this->key_frames[this->current_index])}; + if(this->current_index == 0) + { + previous_frame = &(this->key_frames[this->key_frames.size() - 1]); + float midway_length{animation_time - 0}; + float frames_diff{next_frame->timestamp - 0}; + scale_factor = midway_length / frames_diff; + } + else + { + previous_frame = &(this->key_frames[this->current_index - 1]); + float midway_length{animation_time - previous_frame->timestamp}; + float frames_diff{next_frame->timestamp - previous_frame->timestamp}; + scale_factor = midway_length / frames_diff; + } + + return multiple_frames( + previous_frame->value, next_frame->value, scale_factor); + } + }; +}; + +} +#endif /* CANDY_GEAR_BLUCAT_FRAME_H */ diff --git a/src/blucat/base_buffer.cpp b/src/blucat/base_buffer.cpp new file mode 100644 index 0000000..762c89a --- /dev/null +++ b/src/blucat/base_buffer.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "base_buffer.hpp" + +namespace BluCat +{ + +const CommandChain BaseBuffer::loader{ + {&BaseBuffer::load_buffer, &BaseBuffer::unload_buffer}, + {&BaseBuffer::load_memory, &BaseBuffer::unload_memory} +}; + +void +BaseBuffer::load_buffer(void *obj) +{ + auto self = static_cast(obj); + + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.pNext = nullptr; + buffer_info.flags = 0; + buffer_info.size = self->device_size; + buffer_info.usage = self->buffer_usage; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buffer_info.queueFamilyIndexCount = 0; + buffer_info.pQueueFamilyIndices = nullptr; + + if(vkCreateBuffer( + self->device->device, &buffer_info, nullptr, &self->buffer) + != VK_SUCCESS) + throw CommandError{"Failed to create vertex buffer."}; +} + +void +BaseBuffer::unload_buffer(void *obj) +{ + auto self = static_cast(obj); + + if(self->buffer != VK_NULL_HANDLE) + vkDestroyBuffer(self->device->device, self->buffer, nullptr); +} + +void +BaseBuffer::load_memory(void *obj) +{ + auto self = static_cast(obj); + + VkMemoryRequirements memory_requirements; + vkGetBufferMemoryRequirements( + self->device->device, self->buffer, &memory_requirements); + + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties( + self->device->physical_device, &memory_properties); + + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = nullptr; + alloc_info.allocationSize = memory_requirements.size; + if(!self->device->select_memory_type( + &alloc_info.memoryTypeIndex, &memory_requirements, + self->memory_properties)) + throw CommandError{"Could not allocate memory for Vulkan vertex buffer."}; + + if(vkAllocateMemory(self->device->device, &alloc_info, nullptr, + &self->device_memory) != VK_SUCCESS) + throw CommandError{"Could not allocate memory for Vulkan vertex buffer."}; + + vkBindBufferMemory( + self->device->device, self->buffer, self->device_memory, 0); +} + +void +BaseBuffer::unload_memory(void *obj) +{ + auto self = static_cast(obj); + + if(self->device_memory != VK_NULL_HANDLE) + vkFreeMemory(self->device->device, self->device_memory, nullptr); +} + +} diff --git a/src/blucat/base_buffer.hpp b/src/blucat/base_buffer.hpp new file mode 100644 index 0000000..03b838c --- /dev/null +++ b/src/blucat/base_buffer.hpp @@ -0,0 +1,56 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_BASE_BUFFER_H +#define CANDY_GEAR_BLUCAT_BASE_BUFFER_H 1 + +#include "../command.hpp" +#include "core.hpp" +#include "device.hpp" + +namespace BluCat +{ + +class BaseBuffer +{ + public: + virtual ~BaseBuffer(){}; + + VkBuffer buffer; + VkDeviceMemory device_memory; + VkDeviceSize device_size; + VkBufferUsageFlags buffer_usage; + VkMemoryPropertyFlags memory_properties; + + protected: + static const CommandChain loader; + + Device *device; + + static void + load_buffer(void *obj); + static void + unload_buffer(void *obj); + + static void + load_memory(void *obj); + static void + unload_memory(void *obj); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_BASE_BUFFER_H */ diff --git a/src/blucat/character.cpp b/src/blucat/character.cpp new file mode 100644 index 0000000..c13ffef --- /dev/null +++ b/src/blucat/character.cpp @@ -0,0 +1,274 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "character.hpp" + +#include "../command.hpp" +#include "../core.hpp" +#include "font.hpp" +#include "image.hpp" +#include "source_buffer.hpp" + +namespace +{ + +struct CharacterBuilder +{ + BluCat::Character *character; + FT_Face face; + uint32_t character_code; + + CharacterBuilder( + BluCat::Character *character, FT_Face face, uint32_t character_code); +}; + +CharacterBuilder::CharacterBuilder( + BluCat::Character *character, FT_Face face, uint32_t character_code): + character{character}, + face{face}, + character_code{character_code} +{ +} + +// TODO: creating one image with one device memory for each character is +// ineficient +void +load_image(void *obj) +{ + auto self = static_cast(obj); + + FT_Error error; + std::vector source_image_raw; + const int num_channels = 4; // all images are converted to RGBA + auto glyph_index{FT_Get_Char_Index(self->face, self->character_code)}; + + error = FT_Load_Glyph(self->face, glyph_index, FT_LOAD_DEFAULT); + if(error) throw CommandError{"failed to load glyph"}; + + error = FT_Render_Glyph(self->face->glyph, FT_RENDER_MODE_NORMAL); + if(error) throw CommandError{"failed to render glyph"}; + + self->character->bearing_x = self->face->glyph->bitmap_left; + self->character->bearing_y = self->face->glyph->bitmap_top; + self->character->advance = (self->face->glyph->advance.x >> 6); + self->character->width = self->face->glyph->bitmap.width; + self->character->height = self->face->glyph->bitmap.rows; + self->character->mip_levels = 1; + + // Character is a white-space. + if(self->character->width <= 0) + { + self->character->image = VK_NULL_HANDLE; + self->character->device_memory = VK_NULL_HANDLE; + + return; + } + + auto image_size{static_cast( + self->face->glyph->bitmap.width * + self->face->glyph->bitmap.rows * num_channels)}; + + { // Create the data for the image buffer + source_image_raw.resize(image_size, 0); + + for(auto y{0}; y < self->face->glyph->bitmap.width; y++) + { + for(auto x{0}; x < self->face->glyph->bitmap.rows; x++) + { + auto image_coord = y * self->face->glyph->bitmap.rows * num_channels + + x * num_channels; + auto glyph_coord = y * self->face->glyph->bitmap.rows + x; + // Red + source_image_raw[image_coord] = 255; + // Green + source_image_raw[image_coord + 1] = 255; + // Blue + source_image_raw[image_coord + 2] = 255; + // Alpha + source_image_raw[image_coord + 3] = + self->face->glyph->bitmap.buffer[glyph_coord]; + } + } + } + + BluCat::SourceBuffer source_image_buffer{ + cg_core.vk_device_with_swapchain, source_image_raw.data(), + image_size}; + + { // Create Vulkan image. + try + { + VkExtent3D vk_extent3d; + vk_extent3d.width = self->face->glyph->bitmap.width; + vk_extent3d.height = self->face->glyph->bitmap.rows; + vk_extent3d.depth = 1; + + BluCat::Image::create( + cg_core.vk_device_with_swapchain, + &self->character->image, + &self->character->device_memory, + VK_FORMAT_R8G8B8A8_UNORM, + vk_extent3d, + self->character->mip_levels, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + } + catch(BluCat::Image::Error error) + { + throw CommandError{error.what()}; + } + } + + { // Copy image from buffer into image. + auto queue_family{cg_core.vk_device_with_swapchain-> + get_queue_family_with_presentation()}; + auto queue{queue_family->get_queue()}; + BluCat::CommandPool command_pool{queue_family, 1}; + VkCommandBuffer vk_command_buffer{command_pool.command_buffers[0]}; + + queue.submit_one_time_command(vk_command_buffer, [&](){ + BluCat::Image::move_image_state( + vk_command_buffer, self->character->image, VK_FORMAT_R8G8B8A8_UNORM, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkBufferImageCopy image_copy; + image_copy.bufferOffset = 0; + image_copy.bufferRowLength = 0; + image_copy.bufferImageHeight = 0; + image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_copy.imageSubresource.mipLevel = 0; + image_copy.imageSubresource.baseArrayLayer = 0; + image_copy.imageSubresource.layerCount = 1; + image_copy.imageOffset = {0, 0, 0}; + image_copy.imageExtent = { + self->character->width, self->character->height, 1}; + + vkCmdCopyBufferToImage( + vk_command_buffer, source_image_buffer.buffer, self->character->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); + + BluCat::Image::move_image_state( + vk_command_buffer, self->character->image, VK_FORMAT_R8G8B8A8_UNORM, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + }); + } +} + +void +unload_image(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyImage( + cg_core.vk_device_with_swapchain->device, self->character->image, nullptr); + vkFreeMemory( + cg_core.vk_device_with_swapchain->device, self->character->device_memory, + nullptr); +} + +const CommandChain loader{ + {&load_image, &unload_image} +}; + +} + +namespace BluCat +{ + +Character::Character(FT_Face face, uint32_t character_code) +{ + CharacterBuilder character_builder(this, face, character_code); + loader.execute(&character_builder); +} + +Character::~Character() +{ + CharacterBuilder character_builder(this, nullptr, 0); + loader.revert(&character_builder); +} + +std::vector +Character::str_to_unicode(const char* str) +{ + std::vector unicode_text; + int text_width{0}; + int text_height{0}; + + { // Reserve memory + int size{0}; + for(auto i{0}; str[i] != '\0'; i++) + if((str[i] & 0b11000000) != 0b10000000) size++; + unicode_text.reserve(size); + } + + for(auto i{0}; str[i] != '\0'; i++) + { + int num_bytes; + uint32_t codepoint{0}; + + if(str[i] >= 0 && str[i] < 127) + { // Normal ASCI character, 1-byte. + num_bytes = 1; + codepoint = str[i]; + } + else if((str[i] & 0xE0) == 0xC0) + { // 2-byte character. + num_bytes = 2; + codepoint += ((str[i] & 0b00011111) << 6); + } + else if((str[i] & 0xF0) == 0xE0) + { // 3-byte character. + num_bytes = 3; + codepoint += ((str[i] & 0b00001111) << 12); + } + else if((str[i] & 0xF8) == 0xF0) + { // 4-byte character. + num_bytes = 4; + codepoint += ((str[i] & 0b00000111) << 18); + } + else + { // FIXME: Add support to 5-byte and 6-byte characters. + } + + switch (num_bytes) + { + case 4: + i++; + codepoint += ((str[i] & 0b00111111) << 12); + case 3: + i++; + codepoint += ((str[i] & 0b00111111) << 6); + case 2: + i++; + codepoint += (str[i] & 0b00111111); + case 1: + default: + break; + } + + unicode_text.push_back(codepoint); + } + + return unicode_text; +} + +} diff --git a/src/blucat/character.hpp b/src/blucat/character.hpp new file mode 100644 index 0000000..43cc765 --- /dev/null +++ b/src/blucat/character.hpp @@ -0,0 +1,49 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_CHARACTER_H +#define CANDY_GEAR_BLUCAT_CHARACTER_H 1 + +#include +#include FT_FREETYPE_H + +#include "core.hpp" + +#include + +namespace BluCat +{ + +struct Character +{ + VkImage image; + VkDeviceMemory device_memory; + int32_t bearing_y, bearing_x; + uint32_t width, height, advance, mip_levels; + + Character(FT_Face face, uint32_t character_code); + ~Character(); + + Character(Character const&) = delete; + Character& operator=(Character const&) = delete; + + static std::vector + str_to_unicode(const char* str); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_CHARACTER_H */ diff --git a/src/blucat/command_pool.cpp b/src/blucat/command_pool.cpp new file mode 100644 index 0000000..898d7ae --- /dev/null +++ b/src/blucat/command_pool.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "command_pool.hpp" + +namespace BluCat +{ + +const CommandChain CommandPool::loader{ + {&CommandPool::load_command_pool, &CommandPool::unload_command_pool}, + {&CommandPool::load_command_buffers, nullptr} +}; + +CommandPool::CommandPool(QueueFamily *queue_family, uint32_t buffers_quantity): + queue_family{queue_family} +{ + this->command_buffers.resize(buffers_quantity); + + CommandPool::loader.execute(this); +} + +CommandPool::~CommandPool() +{ + CommandPool::loader.revert(this); +} + +void +CommandPool::load_command_pool(void *obj) +{ + auto *self = static_cast(obj); + + VkCommandPoolCreateInfo command_pool_create_info; + + command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + command_pool_create_info.pNext = nullptr; + command_pool_create_info.flags = + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + command_pool_create_info.queueFamilyIndex = self->queue_family->family_index; + + if(vkCreateCommandPool( + self->queue_family->device->device, &command_pool_create_info, + nullptr, &self->command_pool) != VK_SUCCESS) + throw CommandError{"Vulkan command pool could not be created."}; +} + +void +CommandPool::unload_command_pool(void *obj) +{ + auto *self = static_cast(obj); + + vkDestroyCommandPool( + self->queue_family->device->device, self->command_pool, nullptr); +} + +void +CommandPool::load_command_buffers(void *obj) +{ + auto *self = static_cast(obj); + + VkCommandBufferAllocateInfo command_buffer_info; + command_buffer_info.sType = + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_info.pNext = nullptr; + command_buffer_info.commandPool = self->command_pool; + command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command_buffer_info.commandBufferCount = self->command_buffers.size(); + + if(vkAllocateCommandBuffers( + self->queue_family->device->device, + &command_buffer_info, self->command_buffers.data()) != VK_SUCCESS) + throw CommandError{"Vulkan command buffers could not be allocated."}; +} + +} diff --git a/src/blucat/command_pool.hpp b/src/blucat/command_pool.hpp new file mode 100644 index 0000000..aa23387 --- /dev/null +++ b/src/blucat/command_pool.hpp @@ -0,0 +1,59 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_COMMAND_POOL_H +#define CANDY_GEAR_BLUCAT_COMMAND_POOL_H 1 + +#include + +#include "../command.hpp" +#include "core.hpp" +#include "device.hpp" + +namespace BluCat +{ + +class CommandPool +{ + CommandPool(const CommandPool &t) = delete; + CommandPool& operator=(const CommandPool &t) = delete; + CommandPool(const CommandPool &&t) = delete; + CommandPool& operator=(const CommandPool &&t) = delete; + +public: + std::vector command_buffers; + + CommandPool(QueueFamily *queue_family, uint32_t buffers_quantity); + ~CommandPool(); + +private: + static const CommandChain loader; + + QueueFamily *queue_family; + VkCommandPool command_pool; + + static void + load_command_pool(void *obj); + static void + unload_command_pool(void *obj); + + static void + load_command_buffers(void *obj); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_COMMAND_POOL_H */ diff --git a/src/blucat/core.hpp b/src/blucat/core.hpp new file mode 100644 index 0000000..169e3bc --- /dev/null +++ b/src/blucat/core.hpp @@ -0,0 +1,34 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_CORE_H +#define CANDY_GEAR_BLUCAT_CORE_H 1 + +// GLM uses some definitions to control their behavior, so you should not +// include it directly. Instead, use this header. +#define GLM_ENABLE_EXPERIMENTAL +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE + +#include +#include +#include +#include +#include + +#include + +#endif /* CANDY_GEAR_BLUCAT_CORE_H */ diff --git a/src/blucat/descriptor_set_layout.cpp b/src/blucat/descriptor_set_layout.cpp new file mode 100644 index 0000000..0fc5208 --- /dev/null +++ b/src/blucat/descriptor_set_layout.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "descriptor_set_layout.hpp" + +#include + +#include "../core.hpp" + +namespace +{ + +void +load_world(void *obj) +{ + auto self = static_cast(obj); + + std::array set_layouts{}; + set_layouts[0].binding = 0; + set_layouts[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + set_layouts[0].descriptorCount = 1; + set_layouts[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + set_layouts[0].pImmutableSamplers = nullptr; + + set_layouts[1].binding = 1; + set_layouts[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + set_layouts[1].descriptorCount = 1; + set_layouts[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + set_layouts[1].pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutCreateInfo layout_info{}; + layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_info.pNext = nullptr; + layout_info.flags = 0; + layout_info.bindingCount = set_layouts.size(); + layout_info.pBindings = set_layouts.data(); + + if(vkCreateDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, + &self->world) != VK_SUCCESS) + throw CommandError{ + "Failed to create Vulkan descriptor set layout for world view."}; +} + +void +unload_world(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, self->world, nullptr); +} + +void +load_view(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings{}; + + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layout_bindings[0].pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutCreateInfo layout_info{}; + layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_info.pNext = nullptr; + layout_info.flags = 0; + layout_info.bindingCount = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.data(); + + if(vkCreateDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, + &self->view) != VK_SUCCESS) + throw CommandError{ + "Failed to create Vulkan descriptor set layout for view."}; +} + +void +unload_view(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, self->view, nullptr); +} + +void +load_texture(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings{}; + + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layout_bindings[0].pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutCreateInfo layout_info{}; + layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_info.pNext = nullptr; + layout_info.flags = 0; + layout_info.bindingCount = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.data(); + + if(vkCreateDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, + &self->texture) != VK_SUCCESS) + throw CommandError{ + "Failed to create Vulkan descriptor set layout for textures."}; +} + +void +unload_texture(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, self->texture, nullptr); +} + +void +load_model(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings; + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layout_bindings[0].pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutCreateInfo layout_info{}; + layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_info.pNext = nullptr; + layout_info.flags = 0; + layout_info.bindingCount = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.data(); + + if(vkCreateDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, + &self->model) != VK_SUCCESS) + throw CommandError{ + "Failed to create Vulkan descriptor set layout for model instance."}; +} + +void +unload_model(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, self->model, nullptr); +} + +const CommandChain loader{ + {&load_world, &unload_world}, + {&load_view, &unload_view}, + {&load_texture, &unload_texture}, + {&load_model, &unload_model}, +}; + +} + +namespace BluCat +{ + +DescriptorSetLayout::DescriptorSetLayout() +{ + loader.execute(this); +} + +DescriptorSetLayout::~DescriptorSetLayout() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/descriptor_set_layout.hpp b/src/blucat/descriptor_set_layout.hpp new file mode 100644 index 0000000..144a137 --- /dev/null +++ b/src/blucat/descriptor_set_layout.hpp @@ -0,0 +1,38 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_DESCRIPTOR_SET_LAYOUT_H +#define CANDY_GEAR_BLUCAT_DESCRIPTOR_SET_LAYOUT_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +struct DescriptorSetLayout +{ + VkDescriptorSetLayout world; + VkDescriptorSetLayout view; + VkDescriptorSetLayout texture; + VkDescriptorSetLayout model; + + DescriptorSetLayout(); + ~DescriptorSetLayout(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_DESCRIPTOR_SET_LAYOUT_H */ diff --git a/src/blucat/destination_buffer.cpp b/src/blucat/destination_buffer.cpp new file mode 100644 index 0000000..ea5f31e --- /dev/null +++ b/src/blucat/destination_buffer.cpp @@ -0,0 +1,109 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "destination_buffer.hpp" + +#include "command_pool.hpp" + +namespace BluCat +{ + +DestinationBuffer::DestinationBuffer( + QueueFamily *queue_family, SourceBuffer *source_buffer, + VkBufferUsageFlags buffer_usage) +{ + this->device = queue_family->device; + this->device_size = source_buffer->device_size; + this->buffer_usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | buffer_usage; + this->memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + this->queue_family = queue_family; + this->source_buffer = source_buffer; + + BaseBuffer::loader.execute(dynamic_cast(this)); + + this->copy_data(); +} + +DestinationBuffer::DestinationBuffer( + DestinationBuffer &&that) +{ + this->buffer = that.buffer; + this->device_memory = that.device_memory; + this->device_size = that.device_size; + this->buffer_usage = that.buffer_usage; + this->memory_properties = that.memory_properties; + + that.buffer = VK_NULL_HANDLE; + that.device_memory = VK_NULL_HANDLE; +} + +DestinationBuffer& +DestinationBuffer::operator=(DestinationBuffer &&that) +{ + this->buffer = that.buffer; + this->device_memory = that.device_memory; + this->device_size = that.device_size; + this->buffer_usage = that.buffer_usage; + this->memory_properties = that.memory_properties; + + that.buffer = VK_NULL_HANDLE; + that.device_memory = VK_NULL_HANDLE; + + return *this; +} + +DestinationBuffer::~DestinationBuffer() +{ + BaseBuffer::loader.revert(dynamic_cast(this)); +} + +void +DestinationBuffer::copy_data() +{ + CommandPool command_pool(this->queue_family, 1); + Queue transfer_queue{this->queue_family->get_queue()}; + this->device_size = source_buffer->device_size; + + this->vk_command_buffer = command_pool.command_buffers[0]; + + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VkBufferCopy copy_region = {}; + copy_region.srcOffset = 0; + copy_region.dstOffset = 0; + copy_region.size = this->device_size; + + vkBeginCommandBuffer(this->vk_command_buffer, &begin_info); + + vkCmdCopyBuffer( + this->vk_command_buffer, this->source_buffer->buffer, this->buffer, 1, + ©_region); + + vkEndCommandBuffer(this->vk_command_buffer); + + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &this->vk_command_buffer; + + vkQueueSubmit(transfer_queue.queue, 1, &submit_info, VK_NULL_HANDLE); + + vkQueueWaitIdle(transfer_queue.queue); +} + +} diff --git a/src/blucat/destination_buffer.hpp b/src/blucat/destination_buffer.hpp new file mode 100644 index 0000000..8c098ab --- /dev/null +++ b/src/blucat/destination_buffer.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_DESTINATION_BUFFER_H +#define CANDY_GEAR_BLUCAT_DESTINATION_BUFFER_H 1 + +#include "base_buffer.hpp" +#include "core.hpp" +#include "source_buffer.hpp" +#include "queue_family.hpp" + +namespace BluCat +{ + +struct DestinationBuffer: public BaseBuffer +{ + DestinationBuffer(const DestinationBuffer &t) = delete; + DestinationBuffer& + operator=(const DestinationBuffer &t) = delete; + + QueueFamily *queue_family; + SourceBuffer *source_buffer; + VkCommandBuffer vk_command_buffer; + + DestinationBuffer( + QueueFamily *queue_family, SourceBuffer *source_buffer, + VkBufferUsageFlags buffer_usage); + + DestinationBuffer(DestinationBuffer &&that); + DestinationBuffer& + operator=(DestinationBuffer &&that); + + ~DestinationBuffer(); + + void + copy_data(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_DESTINATION_BUFFER_H */ diff --git a/src/blucat/device.cpp b/src/blucat/device.cpp new file mode 100644 index 0000000..cf21fa4 --- /dev/null +++ b/src/blucat/device.cpp @@ -0,0 +1,392 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "device.hpp" + +#include +#include +#include +#ifdef DEBUG +#include +#endif + +#include "../core.hpp" + +namespace +{ +VkShaderModule +create_shader_module(VkDevice vk_device, const char *filename) +{ + std::ifstream file(filename, std::ios::ate | std::ios::binary); + + if (!file.is_open()) + { + throw std::runtime_error("Failed to open shader module file."); + } + + size_t file_size = (size_t) file.tellg(); + std::vector code(file_size); + + file.seekg(0); + file.read(code.data(), file_size); + + file.close(); + + VkShaderModuleCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = code.size(); + create_info.pCode = reinterpret_cast(code.data()); + + VkShaderModule shader_module; + if (vkCreateShaderModule(vk_device, &create_info, nullptr, + &shader_module) != VK_SUCCESS) + { + throw std::runtime_error("Failed to create shader module."); + } + + return shader_module; +} +} + +namespace BluCat +{ + +Device::Device(VkPhysicalDevice vk_physical_device, bool with_swapchain) +{ + this->physical_device = vk_physical_device; + + std::vector queue_family_properties; + + // Get queue families. + { + vkGetPhysicalDeviceQueueFamilyProperties( + vk_physical_device, &this->queue_families_count, nullptr); + queue_family_properties.resize(this->queue_families_count); + vkGetPhysicalDeviceQueueFamilyProperties( + vk_physical_device, &this->queue_families_count, + queue_family_properties.data()); + } + + // Get information from physical device. + { + VkPhysicalDeviceProperties physical_properties = {}; + vkGetPhysicalDeviceProperties(vk_physical_device, &physical_properties); + VkPhysicalDeviceFeatures supported_features = {}; + vkGetPhysicalDeviceFeatures(vk_physical_device, &supported_features); + +#ifdef DEBUG + std::stringstream message{}; + message << "Name: " << physical_properties.deviceName << std::endl; + message << "API version: " << physical_properties.apiVersion << + std::endl; + message << "Driver version: " << physical_properties.driverVersion << + std::endl; + message << "Vendor ID: " << physical_properties.vendorID << std::endl; + message << "Device ID: " << physical_properties.deviceID << std::endl; + message << "Device type: " << physical_properties.deviceType << + std::endl; + cg_core.log.message(Log::Level::Trace, message.str()); +#endif + + std::vector device_queue_create_infos; + std::vector> queue_priorities( + queue_family_properties.size()); + device_queue_create_infos.resize(queue_family_properties.size()); + for(auto i{0}; i < queue_family_properties.size(); i++) + { + // Give different priorities to queues. + int queue_count = queue_family_properties[i].queueCount; + queue_priorities[i].resize(queue_count); + float priority_unity = 1.0f/queue_count; + for(auto ii{0}; ii < queue_count; ii++) + queue_priorities[i][ii] = priority_unity * (queue_count - ii); + + device_queue_create_infos[i].sType = + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + device_queue_create_infos[i].pNext = nullptr; + device_queue_create_infos[i].flags = 0; + device_queue_create_infos[i].queueFamilyIndex = i; + device_queue_create_infos[i].queueCount = queue_priorities[i].size(); + device_queue_create_infos[i].pQueuePriorities = + queue_priorities[i].data(); + } + + VkPhysicalDeviceFeatures required_features = {}; + required_features.multiDrawIndirect = supported_features.multiDrawIndirect; + required_features.fillModeNonSolid = VK_TRUE; + required_features.geometryShader = VK_TRUE; + required_features.tessellationShader = VK_TRUE; + required_features.samplerAnisotropy = VK_TRUE; + + std::vector device_extensions; + if(with_swapchain) + device_extensions.emplace_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + VkDeviceCreateInfo device_create_info = {}; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_create_info.pNext = nullptr; + device_create_info.flags = 0; + device_create_info.queueCreateInfoCount = device_queue_create_infos.size(); + device_create_info.pQueueCreateInfos = device_queue_create_infos.data(); + device_create_info.enabledLayerCount = 0; + device_create_info.ppEnabledLayerNames = nullptr; + device_create_info.enabledExtensionCount = device_extensions.size(); + if(device_extensions.size() == 0) + device_create_info.ppEnabledExtensionNames = nullptr; + else + device_create_info.ppEnabledExtensionNames = device_extensions.data(); + + device_create_info.pEnabledFeatures = &required_features; + + if(vkCreateDevice(this->physical_device, &device_create_info, nullptr, + &this->device) != VK_SUCCESS) + throw std::runtime_error("Failed to create Vulkan physical device."); + } + + // Load Shaders + { + std::string data_dir{""}; +#ifdef _WIN64 + HKEY hKey; + LPCSTR lpSubKey = "SOFTWARE\\CandyGear"; + LPCSTR lpValueName = "InstallLocation"; + DWORD dwType = REG_SZ; + DWORD dwSize = 0; + LPBYTE lpData = NULL; + + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hKey) == + ERROR_SUCCESS) + { + if(RegQueryValueEx(hKey, lpValueName, NULL, &dwType, NULL, &dwSize) == + ERROR_SUCCESS) + { + lpData = new BYTE[dwSize]; + if(RegQueryValueEx( + hKey, lpValueName, NULL, &dwType, lpData, &dwSize) == + ERROR_SUCCESS) + { + data_dir = reinterpret_cast(lpData); + } + delete[] lpData; + } + RegCloseKey(hKey); + } + + if(data_dir == "") + throw std::runtime_error("Failed to read CandyGear registry."); + + std::string vert_sprite_3d_shader_module{data_dir}; + vert_sprite_3d_shader_module.append("\\glsl\\shader_sprite_3d.vert.spv"); + this->vert_sprite_3d_shader_module = create_shader_module( + this->device, vert_sprite_3d_shader_module.c_str()); + + std::string frag_sprite_3d_shader_module{data_dir}; + frag_sprite_3d_shader_module.append("\\glsl\\shader_sprite_3d.frag.spv"); + this->frag_sprite_3d_shader_module = create_shader_module( + this->device, frag_sprite_3d_shader_module.c_str()); + + std::string vert3d_shader_module{data_dir}; + vert3d_shader_module.append("\\glsl\\shader_3d.vert.spv"); + this->vert3d_shader_module = create_shader_module( + this->device, vert3d_shader_module.c_str()); + + std::string vert3d_skeletal_shader_module{data_dir}; + vert3d_skeletal_shader_module.append( + "\\glsl\\shader_3d_skeletal.vert.spv"); + this->vert3d_skeletal_shader_module = create_shader_module( + this->device, vert3d_skeletal_shader_module.c_str()); + + std::string frag3d_shader_module{data_dir}; + frag3d_shader_module.append("\\glsl\\shader_3d.frag.spv"); + this->frag3d_shader_module = create_shader_module( + this->device, frag3d_shader_module.c_str()); + + std::string vert2d_solid_shader_module{data_dir}; + vert2d_solid_shader_module.append("\\glsl\\shader_2d_solid.vert.spv"); + this->vert2d_solid_shader_module = create_shader_module( + this->device, vert2d_solid_shader_module.c_str()); + + std::string frag2d_solid_shader_module{data_dir}; + frag2d_solid_shader_module.append("\\glsl\\shader_2d_solid.frag.spv"); + this->frag2d_solid_shader_module = create_shader_module( + this->device, frag2d_solid_shader_module.c_str()); + + std::string vert2d_wired_shader_module{data_dir}; + vert2d_wired_shader_module.append("\\glsl\\shader_2d_wired.vert.spv"); + this->vert2d_wired_shader_module = create_shader_module( + this->device, vert2d_wired_shader_module.c_str()); + + std::string frag2d_wired_shader_module{data_dir}; + frag2d_wired_shader_module.append("\\glsl\\shader_2d_wired.frag.spv"); + this->frag2d_wired_shader_module = create_shader_module( + this->device, frag2d_wired_shader_module.c_str()); +#else + data_dir = "/usr/local/share/candy_gear"; + + std::string vert_sprite_3d_shader_module{data_dir}; + vert_sprite_3d_shader_module.append("/glsl/shader_sprite_3d.vert.spv"); + this->vert_sprite_3d_shader_module = create_shader_module( + this->device, vert_sprite_3d_shader_module.c_str()); + + std::string frag_sprite_3d_shader_module{data_dir}; + frag_sprite_3d_shader_module.append("/glsl/shader_sprite_3d.frag.spv"); + this->frag_sprite_3d_shader_module = create_shader_module( + this->device, frag_sprite_3d_shader_module.c_str()); + + std::string vert3d_shader_module{data_dir}; + vert3d_shader_module.append("/glsl/shader_3d.vert.spv"); + this->vert3d_shader_module = create_shader_module( + this->device, vert3d_shader_module.c_str()); + + std::string vert3d_skeletal_shader_module{data_dir}; + vert3d_skeletal_shader_module.append("/glsl/shader_3d_skeletal.vert.spv"); + this->vert3d_skeletal_shader_module = create_shader_module( + this->device, vert3d_skeletal_shader_module.c_str()); + + std::string frag3d_shader_module{data_dir}; + frag3d_shader_module.append("/glsl/shader_3d.frag.spv"); + this->frag3d_shader_module = create_shader_module( + this->device, frag3d_shader_module.c_str()); + + std::string vert2d_solid_shader_module{data_dir}; + vert2d_solid_shader_module.append("/glsl/shader_2d_solid.vert.spv"); + this->vert2d_solid_shader_module = create_shader_module( + this->device, vert2d_solid_shader_module.c_str()); + + std::string frag2d_solid_shader_module{data_dir}; + frag2d_solid_shader_module.append("/glsl/shader_2d_solid.frag.spv"); + this->frag2d_solid_shader_module = create_shader_module( + this->device, frag2d_solid_shader_module.c_str()); + + std::string vert2d_wired_shader_module{data_dir}; + vert2d_wired_shader_module.append("/glsl/shader_2d_wired.vert.spv"); + this->vert2d_wired_shader_module = create_shader_module( + this->device, vert2d_wired_shader_module.c_str()); + + std::string frag2d_wired_shader_module{data_dir}; + frag2d_wired_shader_module.append("/glsl/shader_2d_wired.frag.spv"); + this->frag2d_wired_shader_module = create_shader_module( + this->device, frag2d_wired_shader_module.c_str()); +#endif + } + + this->queue_families = static_cast( + std::malloc(this->queue_families_count * sizeof(QueueFamily))); + for(auto i{0}; i < this->queue_families_count; i++) + { + new(&this->queue_families[i])QueueFamily( + this, i, queue_family_properties[i]); + + // Select families with graphics support. + auto &family_properties = this->queue_families[i].family_properties; + if(family_properties.queueCount > 0 && + family_properties.queueFlags & VK_QUEUE_GRAPHICS_BIT) + this->queue_families_with_graphics.push_back( + &this->queue_families[i]); + + // Select families with presentation support. + VkBool32 present_supported; + vkGetPhysicalDeviceSurfaceSupportKHR( + vk_physical_device, i, cg_core.window_surface, &present_supported); + if(present_supported) + this->queue_families_with_presentation.push_back( + &this->queue_families[i]); + } +} + +Device::~Device() +{ + for(auto i{0}; i < this->queue_families_count; i++) + this->queue_families[i].~QueueFamily(); + std::free(this->queue_families); + + // Destroy shaders + vkDestroyShaderModule( + this->device, this->vert_sprite_3d_shader_module, nullptr); + vkDestroyShaderModule( + this->device, this->frag_sprite_3d_shader_module, nullptr); + vkDestroyShaderModule(this->device, this->vert3d_shader_module, nullptr); + vkDestroyShaderModule( + this->device, this->vert3d_skeletal_shader_module, nullptr); + vkDestroyShaderModule(this->device, this->frag3d_shader_module, nullptr); + vkDestroyShaderModule( + this->device, this->vert2d_solid_shader_module, nullptr); + vkDestroyShaderModule( + this->device, this->frag2d_solid_shader_module, nullptr); + vkDestroyShaderModule( + this->device, this->vert2d_wired_shader_module, nullptr); + vkDestroyShaderModule( + this->device, this->frag2d_wired_shader_module, nullptr); + + vkDeviceWaitIdle(this->device); + vkDestroyDevice(this->device, nullptr); +} + +bool +Device::select_memory_type( + uint32_t *memory_type_index, VkMemoryRequirements *vk_memory_requirements, + VkMemoryPropertyFlags vk_property_flags) +{ + VkPhysicalDeviceMemoryProperties vk_memory_properties; + vkGetPhysicalDeviceMemoryProperties( + this->physical_device, &vk_memory_properties); + + for (auto i{0}; i < vk_memory_properties.memoryTypeCount; i++) + { + if(vk_memory_requirements->memoryTypeBits & (1 << i)) + { + const VkMemoryType& type = vk_memory_properties.memoryTypes[i]; + + if ((type.propertyFlags & vk_property_flags) == vk_property_flags) + { + *memory_type_index = i; + return true; + } + } + } + + return false; +} + +QueueFamily* +Device::get_queue_family_with_graphics() const +{ + /* + Returns a random queue family, so not all commands in the engine use the + same queue. + TODO: There must be a better way of doing this. + */ + std::uniform_int_distribution random_distribution{ + 0, this->queue_families_with_graphics.size() -1}; + auto random = random_distribution(random_number_generator); + return this->queue_families_with_graphics[0]; +} + +QueueFamily* +Device::get_queue_family_with_presentation() const +{ + /* + Returns a random queue family, so not all commands in the engine use the + same queue. + TODO: There must be a better way of doing this. + */ + std::uniform_int_distribution random_distribution{ + 0, this->queue_families_with_presentation.size() -1}; + auto random = random_distribution(random_number_generator); + return this->queue_families_with_presentation[0]; +} + +} diff --git a/src/blucat/device.hpp b/src/blucat/device.hpp new file mode 100644 index 0000000..bcfca4d --- /dev/null +++ b/src/blucat/device.hpp @@ -0,0 +1,69 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_DEVICE_H +#define CANDY_GEAR_BLUCAT_DEVICE_H 1 + +#include +#include + +#include "core.hpp" +#include "queue_family.hpp" + +namespace BluCat +{ + +struct Device +{ + uint32_t queue_families_count; + QueueFamily *queue_families; + std::vector queue_families_with_graphics; + std::vector queue_families_with_presentation; + +public: + VkDevice device; + VkPhysicalDevice physical_device; + + VkShaderModule vert_sprite_3d_shader_module; + VkShaderModule frag_sprite_3d_shader_module; + VkShaderModule vert3d_shader_module; + VkShaderModule vert3d_skeletal_shader_module; + VkShaderModule frag3d_shader_module; + VkShaderModule vert2d_solid_shader_module; + VkShaderModule frag2d_solid_shader_module; + VkShaderModule vert2d_wired_shader_module; + VkShaderModule frag2d_wired_shader_module; + + bool with_swapchain; + + Device(VkPhysicalDevice vk_physical_device, bool with_swapchain); + ~Device(); + + bool + select_memory_type( + uint32_t *memoryTypeIndex, VkMemoryRequirements *vk_memory_requirements, + VkMemoryPropertyFlags vk_property_flags); + + QueueFamily* + get_queue_family_with_graphics() const; + + QueueFamily* + get_queue_family_with_presentation() const; +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_DEVICE_H */ diff --git a/src/blucat/font.cpp b/src/blucat/font.cpp new file mode 100644 index 0000000..4195b57 --- /dev/null +++ b/src/blucat/font.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "font.hpp" + +#include "../core.hpp" + +namespace BluCat +{ + +Font::Font(const char* font_path, int font_size) +{ + FT_Error error; + error = FT_New_Face(cg_core.font_library, font_path, 0, &this->face); + if(error == FT_Err_Unknown_File_Format) throw std::invalid_argument( + "The font file could be opened and read, but it appears that its font " + "format is unsupported."); + else if(error) throw std::invalid_argument( + "The font file could not be opened or read, or it is broken."); + + error = FT_Set_Pixel_Sizes(this->face, 0, font_size); + if(error) throw std::invalid_argument("Failed to load font size."); +} + +Font::~Font() +{ + FT_Done_Face(this->face); +} + +std::shared_ptr +Font::character(uint32_t character_code) +{ + if(!this->characters.contains(character_code)) + this->characters.emplace( + character_code, std::make_shared(this->face, character_code)); + + return this->characters.at(character_code); +} + +} diff --git a/src/blucat/font.hpp b/src/blucat/font.hpp new file mode 100644 index 0000000..1b9be69 --- /dev/null +++ b/src/blucat/font.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_FONT_H +#define CANDY_GEAR_BLUCAT_FONT_H 1 + +#include +#include + +#include "character.hpp" + +namespace BluCat +{ + +struct Font +{ + FT_Face face; + std::unordered_map> characters; + + Font(const char* font_path, int font_size); + ~Font(); + + std::shared_ptr + character(uint32_t character_code); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_FONT_H */ diff --git a/src/blucat/framebuffer.cpp b/src/blucat/framebuffer.cpp new file mode 100644 index 0000000..e761ff2 --- /dev/null +++ b/src/blucat/framebuffer.cpp @@ -0,0 +1,198 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "framebuffer.hpp" + +#include "../core.hpp" +#include "image.hpp" + +namespace +{ +void +load_depth_image(void *obj) +{ + auto self = static_cast(obj); + + VkExtent3D extent3d{}; + extent3d.width = cg_core.display_width; + extent3d.height = cg_core.display_height; + extent3d.depth = 1; + + try + { + BluCat::Image::create( + cg_core.vk_device_with_swapchain, + &self->depth_image, + &self->depth_image_memory, + VK_FORMAT_D32_SFLOAT, + extent3d, + 1, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + ); + } + catch(BluCat::Image::Error error) + { + std::string error_message{"Failed to create depth image → "}; + error_message += error.what(); + throw CommandError{error_message}; + } +} + +void +unload_depth_image(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyImage( + cg_core.vk_device_with_swapchain->device, self->depth_image, + nullptr); + vkFreeMemory( + cg_core.vk_device_with_swapchain->device, + self->depth_image_memory, nullptr); +} + +void +load_depth_image_view(void *obj) +{ + auto self = static_cast(obj); + + try + { + BluCat::Image::create_view( + cg_core.vk_device_with_swapchain, &self->depth_image_view, + self->depth_image, + VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT); + } + catch(BluCat::Image::Error error) + { + std::string error_message{"Failed to create depth image view → "}; + error_message += error.what(); + throw CommandError{error_message}; + } +} + +void +unload_depth_image_view(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyImageView( + cg_core.vk_device_with_swapchain->device, self->depth_image_view, nullptr); +} + +void +load_3d(void *obj) +{ + auto self = static_cast(obj); + + self->pipeline_3d.resize(cg_core.vk_swapchain->images_count); + for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + std::array attachments = { + cg_core.vk_swapchain->image_views[i], + self->depth_image_view + }; + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = cg_core.vk_render_pass->pipeline_3d; + framebuffer_info.attachmentCount = attachments.size(); + framebuffer_info.pAttachments = attachments.data(); + framebuffer_info.width = cg_core.display_width; + framebuffer_info.height = cg_core.display_height; + + framebuffer_info.layers = 1; + + if(vkCreateFramebuffer( + cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, + &self->pipeline_3d[i]) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Framebuffer."}; + } +} + +void +unload_3d(void *obj) +{ + auto self = static_cast(obj); + + for(auto framebuffer: self->pipeline_3d) + vkDestroyFramebuffer( + cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); +} + +void +load_2d(void *obj) +{ + auto self = static_cast(obj); + + self->pipeline_2d.resize(cg_core.vk_swapchain->images_count); + for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + std::array attachments = { + cg_core.vk_swapchain->image_views[i] + }; + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = cg_core.vk_render_pass->pipeline_2d; + framebuffer_info.attachmentCount = attachments.size(); + framebuffer_info.pAttachments = attachments.data(); + framebuffer_info.width = cg_core.display_width; + framebuffer_info.height = cg_core.display_height; + framebuffer_info.layers = 1; + + if(vkCreateFramebuffer( + cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, + &self->pipeline_2d[i]) + != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Framebuffer."}; + } +} + +void +unload_2d(void *obj) +{ + auto self = static_cast(obj); + + for(auto framebuffer: self->pipeline_2d) + vkDestroyFramebuffer( + cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); +} + +const CommandChain loader{ + {&load_depth_image, &unload_depth_image}, + {&load_depth_image_view, &unload_depth_image_view}, + {&load_3d, &unload_3d}, + {&load_2d, &unload_2d} +}; + +} + +namespace BluCat +{ + +Framebuffer::Framebuffer() +{ + loader.execute(this); +} + +Framebuffer::~Framebuffer() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/framebuffer.hpp b/src/blucat/framebuffer.hpp new file mode 100644 index 0000000..32968a6 --- /dev/null +++ b/src/blucat/framebuffer.hpp @@ -0,0 +1,43 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_FRAMEBUFFER_H +#define CANDY_GEAR_BLUCAT_FRAMEBUFFER_H 1 + +#include + +#include "core.hpp" + +namespace BluCat +{ + +struct Framebuffer +{ + // Depth image. + VkImage depth_image; + VkDeviceMemory depth_image_memory; + VkImageView depth_image_view; + + std::vector pipeline_3d; + std::vector pipeline_2d; + + Framebuffer(); + ~Framebuffer(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_FRAMEBUFFER_H */ diff --git a/src/blucat/graphics_pipeline_2d_solid.cpp b/src/blucat/graphics_pipeline_2d_solid.cpp new file mode 100644 index 0000000..28b19b6 --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_solid.cpp @@ -0,0 +1,297 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_2d_solid.hpp" + +#include + +#include "../core.hpp" +#include "sprite.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert2d_solid_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag2d_solid_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(glm::vec2); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertex_attribute{}; + // Texture coordinate. + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[0].offset = 0; + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_TRUE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment.dstColorBlendFactor = + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + std::array dynamic_states{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_BLEND_CONSTANTS + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = dynamic_states.size(); + dynamic_state_info.pDynamicStates = dynamic_states.data(); + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = nullptr; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = + cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline; + pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_2d; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) + != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline2DSolid::GraphicsPipeline2DSolid() +{ + loader.execute(this); +} + +GraphicsPipeline2DSolid::~GraphicsPipeline2DSolid() +{ + loader.revert(this); +} + +void +GraphicsPipeline2DSolid::draw( + std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const size_t next_frame, + const uint32_t image_index) +{ + // TODO set viewport just once per view, not once per pipeline. + { // Set viewport + VkViewport vk_viewport{}; + vk_viewport.x = view->region.x; + vk_viewport.y = view->region.y; + vk_viewport.width = view->region.z; + vk_viewport.height = view->region.w; + vk_viewport.minDepth = 0.0f; + vk_viewport.maxDepth = 1.0f; + vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); + + VkRect2D vk_scissor{}; + vk_scissor.offset.x = static_cast(view->region.x); + vk_scissor.offset.y = static_cast(view->region.y); + vk_scissor.extent.width = static_cast(view->region.z); + vk_scissor.extent.height = static_cast(view->region.w); + vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); + } + + vkCmdBindPipeline( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + this->graphic_pipeline); + + // FIXME: I know sorting is expensive, but I need to figure out better what + // to do here. + std::sort(view->sprites_to_draw[current_frame].begin(), + view->sprites_to_draw[current_frame].end()); + + // Draw sprites + for(auto& sprite_to_draw: view->sprites_to_draw[current_frame]) + { + std::array vk_descriptor_sets{ + view->descriptor_sets_2d[image_index], + sprite_to_draw.sprite->texture->descriptor_sets[image_index]}; + VkDeviceSize offsets[]{0}; + + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline, 0, + vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); + vkCmdBindVertexBuffers( + draw_command_buffer, 0, 1, &sprite_to_draw.sprite->vertex_buffer->buffer, + offsets); + + UDOVector4D position{sprite_to_draw.position}; + vkCmdPushConstants( + draw_command_buffer, + cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline, + VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UDOVector4D), &position); + vkCmdDraw(draw_command_buffer, Sprite::vertex_count, 1, 0, 0); + } + + // Prepare for the next frame. + view->sprites_to_draw[next_frame].clear(); +} + +} diff --git a/src/blucat/graphics_pipeline_2d_solid.hpp b/src/blucat/graphics_pipeline_2d_solid.hpp new file mode 100644 index 0000000..eae54ae --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_solid.hpp @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_SOLID_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_SOLID_H 1 + +#include + +#include "core.hpp" +#include "command_pool.hpp" +#include "view_2d.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline2DSolid +{ + VkPipeline graphic_pipeline; + + GraphicsPipeline2DSolid(); + ~GraphicsPipeline2DSolid(); + + void + draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const size_t next_frame, + const uint32_t image_index); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_SOLID_H */ diff --git a/src/blucat/graphics_pipeline_2d_solid_layout.cpp b/src/blucat/graphics_pipeline_2d_solid_layout.cpp new file mode 100644 index 0000000..7b537a2 --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_solid_layout.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_2d_solid_layout.hpp" + +#include + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + std::array set_layouts{ + cg_core.vk_descriptor_set_layout->view, + cg_core.vk_descriptor_set_layout->texture + }; + + std::array push_constants; + push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constants[0].offset = 0; + push_constants[0].size = sizeof(BluCat::UDOVector4D); + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = set_layouts.size(); + pipeline_layout_info.pSetLayouts = set_layouts.data(); + pipeline_layout_info.pushConstantRangeCount = push_constants.size(); + pipeline_layout_info.pPushConstantRanges = push_constants.data(); + + if(vkCreatePipelineLayout( + cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, + nullptr, &self->pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan pipeline layout."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipelineLayout( + cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline2DSolidLayout::GraphicsPipeline2DSolidLayout() +{ + loader.execute(this); +} + +GraphicsPipeline2DSolidLayout::~GraphicsPipeline2DSolidLayout() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/graphics_pipeline_2d_solid_layout.hpp b/src/blucat/graphics_pipeline_2d_solid_layout.hpp new file mode 100644 index 0000000..77172be --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_solid_layout.hpp @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_LAYOUT_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_LAYOUT_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline2DSolidLayout +{ + VkPipelineLayout pipeline; + + GraphicsPipeline2DSolidLayout(); + ~GraphicsPipeline2DSolidLayout(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/blucat/graphics_pipeline_2d_wired.cpp b/src/blucat/graphics_pipeline_2d_wired.cpp new file mode 100644 index 0000000..192a9d6 --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_wired.cpp @@ -0,0 +1,313 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_2d_wired.hpp" + +#include + +#include "../core.hpp" +#include "rectangle.hpp" +#include "sprite.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_indexes(void *obj) +{ + auto self = static_cast(obj); + + self->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + + std::array indexes{0, 1, 2, 3}; + void *indexes_data{indexes.data()}; + size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; + BluCat::SourceBuffer source_index_buffer{ + self->queue_family->device, indexes_data, indexes_size}; + self->index_buffer = new BluCat::DestinationBuffer{ + self->queue_family, &source_index_buffer, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; +} + +void +unload_indexes(void *obj) +{ + auto self = static_cast(obj); + + delete self->index_buffer; +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert2d_wired_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag2d_wired_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 0; + vertex_input_info.pVertexBindingDescriptions = nullptr; + vertex_input_info.vertexAttributeDescriptionCount = 0; + vertex_input_info.pVertexAttributeDescriptions = nullptr; + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_LINE; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_FALSE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = 2; + dynamic_state_info.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = nullptr; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = + cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline; + pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_2d; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_indexes, &unload_indexes}, + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline2DWired::GraphicsPipeline2DWired() +{ + loader.execute(this); +} + +GraphicsPipeline2DWired::~GraphicsPipeline2DWired() +{ + loader.revert(this); +} + +void +GraphicsPipeline2DWired::draw( + std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const size_t next_frame, + const uint32_t image_index) +{ + // Set viewport + { + VkViewport vk_viewport{}; + vk_viewport.x = view->region.x; + vk_viewport.y = view->region.y; + vk_viewport.width = view->region.z; + vk_viewport.height = view->region.w; + vk_viewport.minDepth = 0.0f; + vk_viewport.maxDepth = 1.0f; + vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); + + VkRect2D vk_scissor{}; + vk_scissor.offset.x = static_cast(view->region.x); + vk_scissor.offset.y = static_cast(view->region.y); + vk_scissor.extent.width = static_cast(view->region.z); + vk_scissor.extent.height = static_cast(view->region.w); + vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); + } + + // Draw rectangles + { + std::array vk_descriptor_sets{ + view->descriptor_sets_2d[image_index]}; + VkDeviceSize offsets[]{0}; + + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline, 0, + vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); + vkCmdBindPipeline( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + this->graphic_pipeline); + vkCmdBindIndexBuffer( + draw_command_buffer, this->index_buffer->buffer, 0, + VK_INDEX_TYPE_UINT32); + + for(auto i{0}; i < view->rectangles_to_draw[current_frame].size(); i++) + { + auto &rect{view->rectangles_to_draw[current_frame][i]}; + + UDOVector4D position{rect.position}; + UDOVector3D color{rect.color}; + vkCmdPushConstants( + draw_command_buffer, + cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline, + VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UDOVector4D), &position); + vkCmdPushConstants( + draw_command_buffer, + cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline, + VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(UDOVector4D), sizeof(UDOVector3D), + &color); + vkCmdDrawIndexed( + draw_command_buffer, Rectangle::VertexCount, 1, 0, 0, 0); + } + } + + // Prepare for the next frame. + view->rectangles_to_draw[next_frame].clear(); +} + +} diff --git a/src/blucat/graphics_pipeline_2d_wired.hpp b/src/blucat/graphics_pipeline_2d_wired.hpp new file mode 100644 index 0000000..32d965b --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_wired.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_WIRED_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_WIRED_H 1 + +#include + +#include "core.hpp" +#include "view_2d.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline2DWired +{ + QueueFamily *queue_family; + + VkPipeline graphic_pipeline; + + DestinationBuffer *index_buffer; + + GraphicsPipeline2DWired(); + ~GraphicsPipeline2DWired(); + + void + draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const size_t next_frame, + const uint32_t image_index); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_WIRED_H */ diff --git a/src/blucat/graphics_pipeline_2d_wired_layout.cpp b/src/blucat/graphics_pipeline_2d_wired_layout.cpp new file mode 100644 index 0000000..eaa6af7 --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_wired_layout.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_2d_wired_layout.hpp" + +#include + +#include "../core.hpp" +#include "graphics_pipeline_2d_solid_layout.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + std::array set_layouts{ + cg_core.vk_descriptor_set_layout->view + }; + + std::array push_constants; + push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constants[0].offset = 0; + push_constants[0].size = sizeof(BluCat::UDOVector4D); + + push_constants[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + push_constants[1].offset = sizeof(BluCat::UDOVector4D); + push_constants[1].size = sizeof(BluCat::UDOVector3D); + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = set_layouts.size(); + pipeline_layout_info.pSetLayouts = set_layouts.data(); + pipeline_layout_info.pushConstantRangeCount = push_constants.size(); + pipeline_layout_info.pPushConstantRanges = push_constants.data(); + + if(vkCreatePipelineLayout( + cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, + nullptr, &self->pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan pipeline layout."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipelineLayout( + cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline2DWiredLayout::GraphicsPipeline2DWiredLayout() +{ + loader.execute(this); +} + +GraphicsPipeline2DWiredLayout::~GraphicsPipeline2DWiredLayout() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/graphics_pipeline_2d_wired_layout.hpp b/src/blucat/graphics_pipeline_2d_wired_layout.hpp new file mode 100644 index 0000000..d447230 --- /dev/null +++ b/src/blucat/graphics_pipeline_2d_wired_layout.hpp @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline2DWiredLayout +{ + VkPipelineLayout pipeline; + + GraphicsPipeline2DWiredLayout(); + ~GraphicsPipeline2DWiredLayout(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/blucat/graphics_pipeline_3d.cpp b/src/blucat/graphics_pipeline_3d.cpp new file mode 100644 index 0000000..c1b60a6 --- /dev/null +++ b/src/blucat/graphics_pipeline_3d.cpp @@ -0,0 +1,307 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_3d.hpp" + +#include +#include + +#include "../core.hpp" +#include "core.hpp" +#include "static_mesh_vertex.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert3d_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag3d_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(BluCat::StaticMeshVertex); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertex_attribute{}; + // Position. + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32B32_SFLOAT; + vertex_attribute[0].offset = offsetof(BluCat::StaticMeshVertex, position); + // Normal. + vertex_attribute[1].location = 1; + vertex_attribute[1].binding = 0; + vertex_attribute[1].format = VK_FORMAT_R32G32B32_SFLOAT; + vertex_attribute[1].offset = offsetof(BluCat::StaticMeshVertex, normal); + // Texture coordinate. + vertex_attribute[2].location = 2; + vertex_attribute[2].binding = 0; + vertex_attribute[2].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[2].offset = offsetof(BluCat::StaticMeshVertex, texture_coord); + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; + depth_stencil.sType = + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil.depthTestEnable = VK_TRUE; + depth_stencil.depthWriteEnable = VK_TRUE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.minDepthBounds = 0.0f; + depth_stencil.maxDepthBounds = 1.0f; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.front = {}; + depth_stencil.back = {}; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_FALSE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = 2; + dynamic_state_info.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = &depth_stencil; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; + pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_3d; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) + != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline3D::GraphicsPipeline3D() +{ + loader.execute(this); +} + +GraphicsPipeline3D::~GraphicsPipeline3D() +{ + loader.revert(this); +} + +void +GraphicsPipeline3D::draw( + std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index) +{ + vkCmdBindPipeline( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + this->graphic_pipeline); + + // Draw models + for(auto& [static_mesh, instances]: + cg_core.vk_renderer->static_models_to_draw[current_frame]) + { + VkBuffer vertex_buffers[]{static_mesh->vertex_buffer->buffer}; + VkDeviceSize offsets[]{0}; + + vkCmdBindVertexBuffers( + draw_command_buffer, 0, 1, vertex_buffers, offsets); + vkCmdBindIndexBuffer( + draw_command_buffer, static_mesh->index_buffer->buffer, 0, + VK_INDEX_TYPE_UINT32); + + for(auto &instance: instances) + { // Object matrix. + glm::mat4 translation_matrix{1.0f}; + translation_matrix = glm::translate( + translation_matrix, *instance->position); + glm::mat4 rotation_matrix{glm::toMat4(*instance->orientation)}; + + std::array vk_descriptor_sets{ + cg_core.vk_light->descriptor_sets_world[image_index], + view->descriptor_sets_3d[image_index], + instance->descriptor_sets[image_index], + instance->texture->descriptor_sets[image_index]}; + + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, + vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); + + vkCmdDrawIndexed( + draw_command_buffer, static_mesh->index_count, 1, 0, 0, 0); + + BluCat::UDOStaticModel udo_static_model{}; + udo_static_model.base_matrix = translation_matrix * rotation_matrix; + instance->uniform_buffers[image_index].copy_data(&udo_static_model); + } + } +} + +} diff --git a/src/blucat/graphics_pipeline_3d.hpp b/src/blucat/graphics_pipeline_3d.hpp new file mode 100644 index 0000000..de0c422 --- /dev/null +++ b/src/blucat/graphics_pipeline_3d.hpp @@ -0,0 +1,43 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_H 1 + +#include + +#include "core.hpp" +#include "command_pool.hpp" +#include "view_3d.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline3D +{ + VkPipeline graphic_pipeline; + + GraphicsPipeline3D(); + ~GraphicsPipeline3D(); + + void + draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_H */ diff --git a/src/blucat/graphics_pipeline_3d_layout.cpp b/src/blucat/graphics_pipeline_3d_layout.cpp new file mode 100644 index 0000000..b2a54d6 --- /dev/null +++ b/src/blucat/graphics_pipeline_3d_layout.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_3d_layout.hpp" + +#include + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + std::array set_layouts{ + cg_core.vk_descriptor_set_layout->world, + cg_core.vk_descriptor_set_layout->view, + cg_core.vk_descriptor_set_layout->model, + cg_core.vk_descriptor_set_layout->texture}; + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = set_layouts.size(); + pipeline_layout_info.pSetLayouts = set_layouts.data(); + pipeline_layout_info.pushConstantRangeCount = 0; + pipeline_layout_info.pPushConstantRanges = nullptr; + + if(vkCreatePipelineLayout( + cg_core.vk_device_with_swapchain->device, + &pipeline_layout_info, nullptr, &self->pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan pipeline layout."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipelineLayout( + cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline3DLayout::GraphicsPipeline3DLayout() +{ + loader.execute(this); +} + +GraphicsPipeline3DLayout::~GraphicsPipeline3DLayout() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/graphics_pipeline_3d_layout.hpp b/src/blucat/graphics_pipeline_3d_layout.hpp new file mode 100644 index 0000000..2b44dac --- /dev/null +++ b/src/blucat/graphics_pipeline_3d_layout.hpp @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_LAYOUT_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_LAYOUT_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline3DLayout +{ + VkPipelineLayout pipeline; + + GraphicsPipeline3DLayout(); + ~GraphicsPipeline3DLayout(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_LAYOUT_H */ diff --git a/src/blucat/graphics_pipeline_3d_skeletal.cpp b/src/blucat/graphics_pipeline_3d_skeletal.cpp new file mode 100644 index 0000000..b039c00 --- /dev/null +++ b/src/blucat/graphics_pipeline_3d_skeletal.cpp @@ -0,0 +1,322 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_3d.hpp" + +#include +#include + +#include "../core.hpp" +#include "core.hpp" +#include "skeletal_mesh_vertex.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert3d_skeletal_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag3d_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(BluCat::SkeletalMeshVertex); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertex_attribute{}; + // Position. + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32B32_SFLOAT; + vertex_attribute[0].offset = offsetof(BluCat::SkeletalMeshVertex, position); + // Normal. + vertex_attribute[1].location = 1; + vertex_attribute[1].binding = 0; + vertex_attribute[1].format = VK_FORMAT_R32G32B32_SFLOAT; + vertex_attribute[1].offset = offsetof(BluCat::SkeletalMeshVertex, normal); + // Texture coordinate. + vertex_attribute[2].location = 2; + vertex_attribute[2].binding = 0; + vertex_attribute[2].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[2].offset = offsetof(BluCat::SkeletalMeshVertex, texture_coord); + // Bones ids. + vertex_attribute[3].location = 3; + vertex_attribute[3].binding = 0; + vertex_attribute[3].format = VK_FORMAT_R32G32B32A32_SINT; + vertex_attribute[3].offset = offsetof(BluCat::SkeletalMeshVertex, bone_ids); + // Bones weights. + vertex_attribute[4].location = 4; + vertex_attribute[4].binding = 0; + vertex_attribute[4].format = VK_FORMAT_R32G32B32A32_SFLOAT; + vertex_attribute[4].offset = offsetof(BluCat::SkeletalMeshVertex, bone_weights); + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; + depth_stencil.sType = + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil.depthTestEnable = VK_TRUE; + depth_stencil.depthWriteEnable = VK_TRUE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.minDepthBounds = 0.0f; + depth_stencil.maxDepthBounds = 1.0f; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.front = {}; + depth_stencil.back = {}; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_FALSE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = 2; + dynamic_state_info.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = &depth_stencil; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; + pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_3d; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) + != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipeline3DSkeletal::GraphicsPipeline3DSkeletal() +{ + loader.execute(this); +} + +GraphicsPipeline3DSkeletal::~GraphicsPipeline3DSkeletal() +{ + loader.revert(this); +} + +void +GraphicsPipeline3DSkeletal::draw( + std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index) +{ + vkCmdBindPipeline( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + this->graphic_pipeline); + + // Draw models + for(auto& [skeletal_mesh, instances]: + cg_core.vk_renderer->skeletal_models_to_draw[current_frame]) + { + VkBuffer vertex_buffers[]{skeletal_mesh->vertex_buffer->buffer}; + VkDeviceSize offsets[]{0}; + + vkCmdBindVertexBuffers( + draw_command_buffer, 0, 1, vertex_buffers, offsets); + vkCmdBindIndexBuffer( + draw_command_buffer, skeletal_mesh->index_buffer->buffer, 0, + VK_INDEX_TYPE_UINT32); + + for(auto &instance: instances) + { // Object matrix. + glm::mat4 translation_matrix{1.0f}; + translation_matrix = glm::translate( + translation_matrix, *instance->position); + glm::mat4 rotation_matrix{glm::toMat4(*instance->orientation)}; + + std::array vk_descriptor_sets{ + cg_core.vk_light->descriptor_sets_world[image_index], + view->descriptor_sets_3d[image_index], + instance->descriptor_sets[image_index], + instance->texture->descriptor_sets[image_index]}; + + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, + vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); + + vkCmdDrawIndexed( + draw_command_buffer, skeletal_mesh->index_count, 1, 0, 0, 0); + + BluCat::UDOSkeletalModel udo_skeletal_model{}; + instance->tick(cg_core.delta_time); + udo_skeletal_model.base_matrix = translation_matrix * rotation_matrix; + std::copy(instance->bone_transforms.begin(), + instance->bone_transforms.end(), + udo_skeletal_model.bone_matrices); + instance->uniform_buffers[image_index].copy_data(&udo_skeletal_model); + } + } + +} + +} diff --git a/src/blucat/graphics_pipeline_3d_skeletal.hpp b/src/blucat/graphics_pipeline_3d_skeletal.hpp new file mode 100644 index 0000000..430d2ec --- /dev/null +++ b/src/blucat/graphics_pipeline_3d_skeletal.hpp @@ -0,0 +1,43 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_SKELETAL_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_3D_SKELETAL_H 1 + +#include + +#include "core.hpp" +#include "command_pool.hpp" +#include "view_3d.hpp" + +namespace BluCat +{ + +struct GraphicsPipeline3DSkeletal +{ + VkPipeline graphic_pipeline; + + GraphicsPipeline3DSkeletal(); + ~GraphicsPipeline3DSkeletal(); + + void + draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_SKELETAL_3D_H */ diff --git a/src/blucat/graphics_pipeline_sprite_3d.cpp b/src/blucat/graphics_pipeline_sprite_3d.cpp new file mode 100644 index 0000000..a71e8bc --- /dev/null +++ b/src/blucat/graphics_pipeline_sprite_3d.cpp @@ -0,0 +1,315 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics_pipeline_sprite_3d.hpp" + +#include + +#include "../core.hpp" +#include "core.hpp" +#include "sprite.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +struct Sprite3DOrder +{ + std::shared_ptr sprite_3d; + float distance; +}; + +bool +operator<(const Sprite3DOrder &a, const Sprite3DOrder &b) +{ + return a.distance < b.distance; +} + +bool +operator>(const Sprite3DOrder &a, const Sprite3DOrder &b) +{ + return a.distance > b.distance; +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert_sprite_3d_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag_sprite_3d_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(glm::vec2); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertex_attribute{}; + // Texture coordinate. + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[0].offset = 0; + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; + depth_stencil.sType = + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil.depthTestEnable = VK_TRUE; + depth_stencil.depthWriteEnable = VK_TRUE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.minDepthBounds = 0.0f; + depth_stencil.maxDepthBounds = 1.0f; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.front = {}; + depth_stencil.back = {}; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_TRUE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment.dstColorBlendFactor = + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + std::array dynamic_states{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_BLEND_CONSTANTS + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = dynamic_states.size(); + dynamic_state_info.pDynamicStates = dynamic_states.data(); + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = &depth_stencil; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; + pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_3d; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) + != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline sprite 3d."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace BluCat +{ + +GraphicsPipelineSprite3D::GraphicsPipelineSprite3D() +{ + loader.execute(this); +} + +GraphicsPipelineSprite3D::~GraphicsPipelineSprite3D() +{ + loader.revert(this); +} + +void +GraphicsPipelineSprite3D::draw( + std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index) +{ + vkCmdBindPipeline( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + this->graphic_pipeline); + + std::vector sprite_3d_order; + { // Sort sprites 3D + sprite_3d_order.reserve( + cg_core.vk_renderer->sprites_3d_to_draw[current_frame].size()); + + for(std::shared_ptr sprite: + cg_core.vk_renderer->sprites_3d_to_draw[current_frame]) + sprite_3d_order.emplace_back( + sprite, glm::distance(*view->camera_position, *sprite->position)); + + std::sort(sprite_3d_order.rbegin(), sprite_3d_order.rend()); + } + + // Draw sprites + for(auto& sprite: sprite_3d_order) + { + std::array vk_descriptor_sets{ + cg_core.vk_light->descriptor_sets_world[image_index], + view->descriptor_sets_3d[image_index], + sprite.sprite_3d->descriptor_sets[image_index], + sprite.sprite_3d->sprite->texture->descriptor_sets[image_index]}; + VkDeviceSize offsets[]{0}; + + vkCmdBindVertexBuffers( + draw_command_buffer, 0, 1, + &sprite.sprite_3d->sprite->vertex_buffer->buffer, offsets); + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, + vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); + + UDOSprite3D ubo_sprite_3d{}; + ubo_sprite_3d.position = *sprite.sprite_3d->position; + ubo_sprite_3d.size = sprite.sprite_3d->size; + sprite.sprite_3d->uniform_buffers[image_index].copy_data(&ubo_sprite_3d); + + vkCmdDraw(draw_command_buffer, Sprite::vertex_count, 1, 0, 0); + } +} + +} diff --git a/src/blucat/graphics_pipeline_sprite_3d.hpp b/src/blucat/graphics_pipeline_sprite_3d.hpp new file mode 100644 index 0000000..969f905 --- /dev/null +++ b/src/blucat/graphics_pipeline_sprite_3d.hpp @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_SPRITE_3D_H +#define CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_SPRITE_3D_H 1 + +#include + +#include "core.hpp" +#include "command_pool.hpp" +#include "sprite_3d.hpp" +#include "view_3d.hpp" + +namespace BluCat +{ + +struct GraphicsPipelineSprite3D +{ + VkPipeline graphic_pipeline; + + GraphicsPipelineSprite3D(); + ~GraphicsPipelineSprite3D(); + + void + draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_GRAPHICS_PIPELINE_SPRITE_3D_H */ diff --git a/src/blucat/image.cpp b/src/blucat/image.cpp new file mode 100644 index 0000000..7f8633f --- /dev/null +++ b/src/blucat/image.cpp @@ -0,0 +1,149 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image.hpp" + +#include "../core.hpp" + +namespace BluCat::Image +{ + +Error::Error(const std::string &m): + error(m) +{ +} + +Error::Error(const char &m): + Error{std::string{m}} +{ +} + +const char* +Error::what() const noexcept +{ + return this->error.c_str(); +} + +void +create( + BluCat::Device *device, + VkImage *image, + VkDeviceMemory *image_memory, + VkFormat format, + const VkExtent3D &extent3d, + uint32_t mip_levels, + VkImageTiling image_tiling, + VkImageUsageFlags usage) +{ + VkImageCreateInfo image_info{}; + image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_info.pNext = nullptr; + image_info.flags = 0; + image_info.imageType = VK_IMAGE_TYPE_2D; + image_info.format = format; + image_info.extent = extent3d; + image_info.mipLevels = mip_levels; + image_info.arrayLayers = 1; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_info.tiling = image_tiling; + image_info.usage = usage; + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_info.queueFamilyIndexCount = 0; + image_info.pQueueFamilyIndices = nullptr; + image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + if(vkCreateImage( + device->device, &image_info, nullptr, image) != VK_SUCCESS) + throw Error{"Failed to create Vulkan image."}; + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements(device->device, *image, &memory_requirements); + + VkMemoryAllocateInfo memory_alloc_info{}; + memory_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_alloc_info.allocationSize = memory_requirements.size; + device->select_memory_type(&memory_alloc_info.memoryTypeIndex, + &memory_requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + if(vkAllocateMemory( + device->device, &memory_alloc_info, nullptr, image_memory) + != VK_SUCCESS) + { + vkDestroyImage(device->device, *image, nullptr); + throw Error{"Failed to allocate memory for Vulkan image."}; + } + + vkBindImageMemory(device->device, *image, *image_memory, 0); +} + +void move_image_state( + VkCommandBuffer vk_command_buffer, VkImage vk_image, VkFormat format, + VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask, + VkImageLayout old_layout, VkImageLayout new_layout, + VkPipelineStageFlags source_stage, VkPipelineStageFlags destination_stage) +{ + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = nullptr; + barrier.srcAccessMask = src_access_mask; + barrier.dstAccessMask = dst_access_mask; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = vk_image; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier( + vk_command_buffer, source_stage, destination_stage, 0, 0, nullptr, + 0, nullptr, 1, &barrier); +} + +void create_view( + BluCat::Device *device, + VkImageView *image_view, + const VkImage &image, + VkFormat format, + VkImageAspectFlags image_aspect_flags) +{ + VkImageViewCreateInfo image_view_info{}; + image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_info.pNext = nullptr; + image_view_info.flags = 0; + image_view_info.image = image; + image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + image_view_info.format = format; + image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.subresourceRange.aspectMask = image_aspect_flags; + image_view_info.subresourceRange.baseMipLevel = 0; + image_view_info.subresourceRange.levelCount = 1; + image_view_info.subresourceRange.baseArrayLayer = 0; + image_view_info.subresourceRange.layerCount = 1; + + if(vkCreateImageView(device->device, &image_view_info, + nullptr, image_view) != VK_SUCCESS) + throw Error{"Failed to create texture view."}; + +} + +} diff --git a/src/blucat/image.hpp b/src/blucat/image.hpp new file mode 100644 index 0000000..cb6cfd4 --- /dev/null +++ b/src/blucat/image.hpp @@ -0,0 +1,73 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BLUE_KITTY_BLUCAT_IMAGE_H +#define BLUE_KITTY_BLUCAT_IMAGE_H 1 + +#include +#include + +#include "core.hpp" +#include "device.hpp" + +namespace BluCat::Image +{ + +struct Error: public std::exception +{ + Error(const std::string &m); + Error(const char &m); + + const char* + what() const noexcept; + +private: + std::string error; +}; + +void +create( + BluCat::Device *device, + VkImage *image, + VkDeviceMemory *image_memory, + VkFormat format, + const VkExtent3D &extent3d, + uint32_t mip_levels, + VkImageTiling image_tiling, + VkImageUsageFlags usage); + +void +move_image_state( + VkCommandBuffer vk_command_buffer, + VkImage vk_image, + VkFormat format, + VkAccessFlags src_access_mask, + VkAccessFlags dst_access_mask, + VkImageLayout old_layout, + VkImageLayout new_layout, + VkPipelineStageFlags source_stage, + VkPipelineStageFlags destination_stage); + +void +create_view( + BluCat::Device *device, + VkImageView *image_view, + const VkImage &image, + VkFormat format, + VkImageAspectFlags image_aspect_flags); +} + +#endif /* CANDY_GEAR_BLUCAT_IMAGE_H */ diff --git a/src/blucat/light.cpp b/src/blucat/light.cpp new file mode 100644 index 0000000..5efc6ec --- /dev/null +++ b/src/blucat/light.cpp @@ -0,0 +1,205 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "light.hpp" + +#include + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_world_vert_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->ub_world_vert.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_world_vert.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOWorld3D_Vert)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_world_vert_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + self->ub_world_vert.clear(); +} + +void +load_world_frag_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->ub_world_frag.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_world_frag.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOWorld3D_Frag)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_world_frag_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + self->ub_world_frag.clear(); +} + +void +load_descriptor_pool(void *obj) +{ + auto self = static_cast(obj); + + uint32_t uniform_buffers_count = + self->ub_world_vert.size() + self->ub_world_vert.size(); + + VkDescriptorPoolSize descriptor_pool_size{}; + descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_size.descriptorCount = uniform_buffers_count; + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = uniform_buffers_count; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &descriptor_pool_size; + + if(vkCreateDescriptorPool( + cg_core.vk_device_with_swapchain->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_pool(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorPool( + cg_core.vk_device_with_swapchain->device, self->descriptor_pool, + nullptr); +} + +void +load_descriptor_sets_world(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->world); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets_world.resize(layouts.size()); + if(vkAllocateDescriptorSets( + cg_core.vk_device_with_swapchain->device, &alloc_info, + self->descriptor_sets_world.data()) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan world descriptor set."}; +} + +void +load_resources_to_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + VkDescriptorBufferInfo world_vert_info{}; + world_vert_info.buffer = self->ub_world_vert[i].buffer; + world_vert_info.offset = 0; + world_vert_info.range = sizeof(BluCat::UDOWorld3D_Vert); + + VkDescriptorBufferInfo world_frag_info{}; + world_frag_info.buffer = self->ub_world_frag[i].buffer; + world_frag_info.offset = 0; + world_frag_info.range = sizeof(BluCat::UDOWorld3D_Frag); + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets_world[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &world_vert_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + write_descriptors[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[1].dstSet = self->descriptor_sets_world[i]; + write_descriptors[1].dstBinding = 1; + write_descriptors[1].dstArrayElement = 0; + write_descriptors[1].descriptorCount = 1; + write_descriptors[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[1].pBufferInfo = &world_frag_info; + write_descriptors[1].pImageInfo = nullptr; + write_descriptors[1].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +const CommandChain loader{ + {&load_world_vert_uniform_buffer, &unload_world_vert_uniform_buffer}, + {&load_world_frag_uniform_buffer, &unload_world_frag_uniform_buffer}, + {&load_descriptor_pool, &unload_descriptor_pool}, + // By destroying the pool the sets are also destroyed. + {&load_descriptor_sets_world, nullptr}, + {&load_resources_to_descriptor_sets, nullptr} +}; + +} + +namespace BluCat +{ + +Light::Light() +{ + loader.execute(this); +} + +Light::~Light() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/light.hpp b/src/blucat/light.hpp new file mode 100644 index 0000000..7e1d3a1 --- /dev/null +++ b/src/blucat/light.hpp @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_LIGHT_H +#define CANDY_GEAR_BLUCAT_LIGHT_H 1 + +#include "core.hpp" +#include "uniform_buffer.hpp" + +namespace BluCat +{ + +struct Light +{ + // FIXME: if this vector get resized, it will cause a segmentation fault! + std::vector ub_world_vert; + std::vector ub_world_frag; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets_world; + + Light(); + ~Light(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_LIGHT_H */ diff --git a/src/blucat/qoi.cpp b/src/blucat/qoi.cpp new file mode 100644 index 0000000..663e4e9 --- /dev/null +++ b/src/blucat/qoi.cpp @@ -0,0 +1,205 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "qoi.hpp" + +#include +#include + +#include "../binary_reader.hpp" + +namespace +{ + +const char MAGIC[]{"qoif"}; +const int HEADER_SIZE{14}; +const uint8_t PADDING[8]{0,0,0,0,0,0,0,1}; +const unsigned int PIXELS_MAX{400000000}; + +const int OP_INDEX{0b00000000}; +const int OP_DIFF {0b01000000}; +const int OP_LUMA {0b10000000}; +const int OP_RUN {0b11000000}; +const int OP_RGB {0b11111110}; +const int OP_RGBA {0b11111111}; + +const int MASK_2_BITS{0b11000000}; + +struct RGBA +{ + uint8_t red, green, blue, alpha; + + RGBA(); + RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); +}; + +RGBA::RGBA(): + red{0}, + green{0}, + blue{0}, + alpha{0} +{ +} + +RGBA::RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha): + red{red}, + green{green}, + blue{blue}, + alpha{alpha} +{ +} + +struct Pixel +{ + union + { + RGBA colors; + uint32_t value; + }; + + Pixel(); + Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); +}; + +Pixel::Pixel(): + colors{} +{ +} + +Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha): + colors(red, green, blue, alpha) +{ +} + +inline int +color_hash(const RGBA &colors) +{ + return colors.red*3 + colors.green*5 + colors.blue*7 + colors.alpha*11; +} + +} + +namespace BluCat::QOI +{ + +Image::Image(const char *file_path, uint8_t channels): + channels{channels} +{ + if(this->channels != 0 && this->channels != 3 && this->channels != 4) + { + throw std::invalid_argument{"invalid number of channels"}; + } + + BinaryReader input{file_path}; + if(input.size() < HEADER_SIZE + (int)sizeof(PADDING)) + { + throw std::runtime_error{"invalid QOI file"}; + } + + input.read_chars(this->header.magic, 4); + this->header.width = input.read_ui32(); + this->header.height = input.read_ui32(); + this->header.channels = input.read_ui8(); + this->header.colorspace = input.read_ui8(); + + if(this->header.width == 0 || this->header.height == 0 || + this->header.channels < 3 || this->header.channels > 4 || + this->header.colorspace > 1 || + this->header.height >= PIXELS_MAX / this->header.width) + { + throw std::runtime_error{"QOI file have an invalid header"}; + } + + if(this->channels == 0) this->channels = this->header.channels; + + uint32_t num_pixels{this->header.width * this->header.height}; + this->pixels_len = num_pixels * this->channels; + this->pixels = new uint8_t[this->pixels_len]; + + std::array index; + Pixel pixel(0, 0, 0, 255); + int chunks_len = input.size() - (int)sizeof(PADDING); + + /* + This algorithm is based on the original implementation that is in GitHub: + https://github.com/phoboslab/qoi + + For information about the QOI image format, see: https://qoiformat.org/ + */ + int pixel_p{0}; + int run{0}; + for(uint32_t decoded_pixel{0}; decoded_pixel < num_pixels; decoded_pixel++) + { + if(run > 0) + { + run--; + } + else if(input.pointer() < chunks_len) + { + int b1 = input.read_ui8(); + + if (b1 == OP_RGB) + { + pixel.colors.red = input.read_ui8(); + pixel.colors.green = input.read_ui8(); + pixel.colors.blue = input.read_ui8(); + } + else if (b1 == OP_RGBA) + { + pixel.colors.red = input.read_ui8(); + pixel.colors.green = input.read_ui8(); + pixel.colors.blue = input.read_ui8(); + pixel.colors.alpha = input.read_ui8(); + } + else if ((b1 & MASK_2_BITS) == OP_INDEX) + { + pixel = index[b1]; + } + else if ((b1 & MASK_2_BITS) == OP_DIFF) + { + pixel.colors.red += ((b1 >> 4) & 0x03) - 2; + pixel.colors.green += ((b1 >> 2) & 0x03) - 2; + pixel.colors.blue += (b1 & 0x03) - 2; + } + else if ((b1 & MASK_2_BITS) == OP_LUMA) + { + int b2 = input.read_ui8(); + int vg = (b1 & 0x3f) - 32; + pixel.colors.red += vg - 8 + ((b2 >> 4) & 0x0f); + pixel.colors.green += vg; + pixel.colors.blue += vg - 8 + (b2 & 0x0f); + } + else if ((b1 & MASK_2_BITS) == OP_RUN) + { + run = (b1 & 0x3f); + } + + index[color_hash(pixel.colors) % 64] = pixel; + } + + this->pixels[pixel_p++] = pixel.colors.red; + this->pixels[pixel_p++] = pixel.colors.green; + this->pixels[pixel_p++] = pixel.colors.blue; + if(this->channels == 4) this->pixels[pixel_p++] = pixel.colors.alpha; + } +} + +Image::~Image() +{ + delete[] this->pixels; +} + +} diff --git a/src/blucat/qoi.hpp b/src/blucat/qoi.hpp new file mode 100644 index 0000000..cd33205 --- /dev/null +++ b/src/blucat/qoi.hpp @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace BluCat::QOI +{ + struct Header + { + char magic[4]; + uint32_t width; + uint32_t height; + uint8_t channels; + uint8_t colorspace; + }; + + struct Image + { + Header header; + uint32_t pixels_len; + uint8_t channels; + uint8_t *pixels; + + Image(const char *file_path, uint8_t channels); + ~Image(); + }; + +} diff --git a/src/blucat/queue.cpp b/src/blucat/queue.cpp new file mode 100644 index 0000000..c00d874 --- /dev/null +++ b/src/blucat/queue.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "queue.hpp" + +#include "queue_family.hpp" + +namespace BluCat +{ + +Queue::Queue( + BluCat::QueueFamily *queue_family, VkQueue queue, int queue_index): + queue_family{queue_family}, + queue{queue}, + queue_index{queue_index} +{ + this->queue_family->queue_states[this->queue_index].busy = true; +} + +Queue::Queue(Queue &&that): + queue{that.queue}, + queue_family{that.queue_family}, + queue_index{that.queue_index} +{ + that.queue_family = nullptr; +} + +Queue& Queue::operator=(Queue &&that) +{ + this->queue = that.queue; + this->queue_family = that.queue_family; + this->queue_index = that.queue_index; + + that.queue_family = nullptr; + + return *this; +} + +Queue::~Queue() +{ + if(this->queue_family) + { + std::unique_lock lock{this->queue_family->queue_mutex}; + this->queue_family->queue_states[this->queue_index].busy = false; + } +} + +} diff --git a/src/blucat/queue.hpp b/src/blucat/queue.hpp new file mode 100644 index 0000000..a71dc9d --- /dev/null +++ b/src/blucat/queue.hpp @@ -0,0 +1,82 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_QUEUE_H +#define CANDY_GEAR_BLUCAT_QUEUE_H 1 + +#include "core.hpp" + +namespace BluCat +{ +class QueueFamily; + +struct Queue +{ + friend class BluCat::QueueFamily; + + Queue(const Queue &t) = delete; + Queue& operator=(const Queue &t) = delete; + + VkQueue queue; + + template + void submit_one_time_command( + const VkCommandBuffer vk_command_buffer, T commands); + + Queue(Queue &&that); + Queue& operator=(Queue &&that); + + ~Queue(); + +private: + BluCat::QueueFamily *queue_family; + int queue_index; + + Queue(BluCat::QueueFamily *queue_family, VkQueue queue, int queue_index); +}; + +template void +Queue::submit_one_time_command( + const VkCommandBuffer vk_command_buffer, T commands) +{ + VkCommandBufferBeginInfo buffer_begin_info{}; + buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(vk_command_buffer, &buffer_begin_info); + + commands(); + + vkEndCommandBuffer(vk_command_buffer); + + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = nullptr; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = nullptr; + submit_info.pWaitDstStageMask = nullptr; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &vk_command_buffer; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = nullptr; + + vkQueueSubmit(this->queue, 1, &submit_info, VK_NULL_HANDLE); + vkQueueWaitIdle(this->queue); +} + +} + +#endif /* CANDY_GEAR_BLUCAT_QUEUE_H */ diff --git a/src/blucat/queue_family.cpp b/src/blucat/queue_family.cpp new file mode 100644 index 0000000..32aaf4b --- /dev/null +++ b/src/blucat/queue_family.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "queue_family.hpp" + +#ifdef DEBUG +#include +#endif + +#include "../core.hpp" + +namespace BluCat +{ + +QueueFamily::QueueFamily( + BluCat::Device *device, uint32_t family_index, + const VkQueueFamilyProperties &queue_family_properties): + queue_mutex{} +{ + +#ifdef DEBUG + std::stringstream message{}; + message << "Queue quantity: " << queue_family_properties.queueCount << + std::endl; + message << "Graphics: " << + (queue_family_properties.queueFlags & VK_QUEUE_GRAPHICS_BIT ? + "true" : "false") << std::endl; + message << "Compute: " << + (queue_family_properties.queueFlags & VK_QUEUE_COMPUTE_BIT ? + "true" : "false") << std::endl; + message << "Transfer: " << + (queue_family_properties.queueFlags & VK_QUEUE_TRANSFER_BIT ? + "true" : "false") << std::endl; + message << "Sparse Binding: " << + (queue_family_properties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT ? + "true" : "false") << std::endl; + cg_core.log.message(Log::Level::Trace, message.str()); +#endif + + this->device = device; + this->family_index = family_index; + this->family_properties = queue_family_properties; + + // Create queues + { + auto queue_count = this->family_properties.queueCount; + this->queue_states.resize(queue_count); + + for(auto i{0}; i < queue_count; i++) + { + vkGetDeviceQueue(device->device, this->family_index, i, + &this->queue_states[i].queue); + if(this->queue_states[i].queue == VK_NULL_HANDLE) + throw std::runtime_error("Failed to get Vulkan queue."); + } + } +} + +Queue +QueueFamily::get_queue() +{ + std::unique_lock lock{this->queue_mutex}; + + for(auto i{0}; i < this->queue_states.size(); i++) + if(!this->queue_states[i].busy) + return Queue(this, this->queue_states[i].queue, i); + + throw std::length_error("No free queues found."); +} + +} diff --git a/src/blucat/queue_family.hpp b/src/blucat/queue_family.hpp new file mode 100644 index 0000000..2486316 --- /dev/null +++ b/src/blucat/queue_family.hpp @@ -0,0 +1,58 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_QUEUE_FAMILY_H +#define CANDY_GEAR_BLUCAT_QUEUE_FAMILY_H 1 + +#include +#include + +#include "core.hpp" +#include "queue.hpp" + +namespace BluCat +{ +class Device; + +struct QueueState +{ + VkQueue queue; + bool busy; +}; + +class QueueFamily +{ + friend class Queue; + + std::mutex queue_mutex; + std::vector queue_states; + +public: + BluCat::Device *device; + + uint32_t family_index; + VkQueueFamilyProperties family_properties; + + QueueFamily(BluCat::Device *device, uint32_t family_index, + const VkQueueFamilyProperties &queue_family_properties); + + Queue + get_queue(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_QUEUE_FAMILY_H */ diff --git a/src/blucat/rectangle.cpp b/src/blucat/rectangle.cpp new file mode 100644 index 0000000..34f844d --- /dev/null +++ b/src/blucat/rectangle.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rectangle.hpp" + +namespace BluCat +{ + +const int Rectangle::VertexCount{4}; + +Rectangle::Rectangle(glm::vec4 position, glm::vec3 color): + position{position}, + color{color} +{ +} + +} diff --git a/src/blucat/rectangle.hpp b/src/blucat/rectangle.hpp new file mode 100644 index 0000000..876508c --- /dev/null +++ b/src/blucat/rectangle.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_RECTANGLE_H +#define CANDY_GEAR_BLUCAT_RECTANGLE_H 1 + +#include + +#include "core.hpp" +#include "destination_buffer.hpp" +#include "queue_family.hpp" +#include "uniform_buffer.hpp" + +namespace BluCat +{ + +struct Rectangle +{ + static const int VertexCount; + + glm::vec4 position; + glm::vec3 color; + + Rectangle(glm::vec4 position, glm::vec3 color); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_RECTANGLE_H */ diff --git a/src/blucat/render_pass.cpp b/src/blucat/render_pass.cpp new file mode 100644 index 0000000..0eb30e3 --- /dev/null +++ b/src/blucat/render_pass.cpp @@ -0,0 +1,203 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render_pass.hpp" + +#include + +#include "../core.hpp" + +namespace +{ + +void +load_3d(void *obj) +{ + auto self = static_cast(obj); + + std::array attachments{}; + // Color attachment. + attachments[0].flags = 0; + attachments[0].format = cg_core.vk_swapchain->image_format; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + // Depth attachment. + attachments[1].flags = 0; + attachments[1].format = VK_FORMAT_D32_SFLOAT; + attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[1].finalLayout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentReference color_attachment_ref{}; + color_attachment_ref.attachment = 0; + color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference depth_attachment_ref{}; + depth_attachment_ref.attachment = 1; + depth_attachment_ref.layout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_ref; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = &depth_attachment_ref; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo render_pass_info{}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.pNext = nullptr; + render_pass_info.flags = 0; + render_pass_info.attachmentCount = attachments.size(); + render_pass_info.pAttachments = attachments.data(); + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; + + if(vkCreateRenderPass( + cg_core.vk_device_with_swapchain->device, &render_pass_info, nullptr, + &self->pipeline_3d) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Render Pass 3D."}; +} + +void +unload_3d(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyRenderPass( + cg_core.vk_device_with_swapchain->device, self->pipeline_3d, nullptr); +} + +void +load_2d(void *obj) +{ + auto self = static_cast(obj); + + std::array attachments{}; + // Color attachment. + attachments[0].flags = 0; + attachments[0].format = cg_core.vk_swapchain->image_format; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference color_attachment_ref{}; + color_attachment_ref.attachment = 0; + color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_ref; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo render_pass_info{}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.pNext = nullptr; + render_pass_info.flags = 0; + render_pass_info.attachmentCount = attachments.size(); + render_pass_info.pAttachments = attachments.data(); + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; + + if(vkCreateRenderPass( + cg_core.vk_device_with_swapchain->device, &render_pass_info, + nullptr, &self->pipeline_2d) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Render Pass 2D."}; +} + +void +unload_2d(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyRenderPass( + cg_core.vk_device_with_swapchain->device, self->pipeline_2d, nullptr); +} + +const CommandChain loader{ + {&load_3d, &unload_3d}, + {&load_2d, &unload_2d} +}; + +} + +namespace BluCat +{ + +RenderPass::RenderPass() +{ + loader.execute(this); +} + +RenderPass::~RenderPass() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/render_pass.hpp b/src/blucat/render_pass.hpp new file mode 100644 index 0000000..196ce97 --- /dev/null +++ b/src/blucat/render_pass.hpp @@ -0,0 +1,36 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_RENDER_PASS_H +#define CANDY_GEAR_BLUCAT_RENDER_PASS_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +struct RenderPass +{ + VkRenderPass pipeline_2d; + VkRenderPass pipeline_3d; + + RenderPass(); + ~RenderPass(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_RENDER_PASS_H */ diff --git a/src/blucat/renderer.cpp b/src/blucat/renderer.cpp new file mode 100644 index 0000000..75822e0 --- /dev/null +++ b/src/blucat/renderer.cpp @@ -0,0 +1,413 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "renderer.hpp" + +#include + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_descriptor_pool(void *obj) +{ + auto self = static_cast(obj); + + uint32_t uniform_buffer_count = 0; + for(auto &view : self->views_3d) + uniform_buffer_count += (view->ub_3d.size() + view->ub_2d.size()); + for(auto &view : self->views_2d) + uniform_buffer_count += (view->ub_2d.size()); + + VkDescriptorPoolSize descriptor_pool_size{}; + descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_size.descriptorCount = uniform_buffer_count; + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = uniform_buffer_count; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &descriptor_pool_size; + + if(vkCreateDescriptorPool( + cg_core.vk_device_with_swapchain->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; + + for(auto &view : self->views_3d) + view->load_descriptor_sets(self->descriptor_pool); + for(auto &view : self->views_2d) + view->load_descriptor_sets(self->descriptor_pool); +} + +void +unload_descriptor_pool(void *obj) +{ + auto self = static_cast(obj); + + for(auto &view : self->views_3d) view->unload_descriptor_sets(); + for(auto &view : self->views_2d) view->unload_descriptor_sets(); + + vkDestroyDescriptorPool( + cg_core.vk_device_with_swapchain->device, self->descriptor_pool, + nullptr); +} + +void +load_queue_family(void *obj) +{ + auto self = static_cast(obj); + + self->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_presentation(); +} + +void +load_command_pool(void *obj) +{ + auto self = static_cast(obj); + + VkCommandPoolCreateInfo create_info{}; + create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + create_info.pNext = nullptr; + create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + create_info.queueFamilyIndex = self->queue_family->family_index; + + vkCreateCommandPool( + self->queue_family->device->device, &create_info, nullptr, + &self->command_pool); +} + +void +unload_command_pool(void *obj) +{ + auto self = static_cast(obj); + + vkWaitForFences(cg_core.vk_device_with_swapchain->device, + BluCat::Swapchain::max_frames_in_flight, + cg_core.vk_swapchain->in_flight_fences.data(), VK_TRUE, + std::numeric_limits::max()); + vkDestroyCommandPool( + self->queue_family->device->device, self->command_pool, nullptr); +} + +void +load_draw_command_buffer(void *obj) +{ + auto self = static_cast(obj); + + // FIXME: 3 is a magical number, triple buffering. + self->draw_command_buffers.resize(3); + + VkCommandBufferAllocateInfo allocate_info{}; + allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocate_info.pNext = nullptr; + allocate_info.commandPool = self->command_pool; + allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocate_info.commandBufferCount = self->draw_command_buffers.size(); + + if(vkAllocateCommandBuffers( + self->queue_family->device->device, &allocate_info, + self->draw_command_buffers.data()) != VK_SUCCESS) + throw CommandError{"Vulkan draw command buffers could not be allocated."}; +} + +const CommandChain loader{ + {&load_descriptor_pool, &unload_descriptor_pool}, + {&load_queue_family, nullptr}, + {&load_command_pool, &unload_command_pool}, + {&load_draw_command_buffer, nullptr} +}; + +} + +namespace BluCat +{ + +Renderer::Renderer(std::vector> views_2d, + std::vector> views_3d): + skeletal_models_to_draw{cg_core.vk_swapchain->images_count}, + static_models_to_draw{cg_core.vk_swapchain->images_count}, + sprites_3d_to_draw{cg_core.vk_swapchain->images_count}, + views_2d{views_2d}, + views_3d{views_3d} +{ + loader.execute(this); +} + +Renderer::Renderer(std::initializer_list> views_2d, + std::initializer_list> views_3d): + Renderer(std::vector(views_2d), std::vector(views_3d)) +{ +} + +Renderer::~Renderer() +{ + loader.revert(this); +} + +void +Renderer::draw() +{ + auto fence_status = vkGetFenceStatus( + cg_core.vk_device_with_swapchain->device, + cg_core.vk_swapchain->in_flight_fences[ + cg_core.vk_swapchain->current_frame]); + + if(fence_status == VK_SUCCESS) + { + auto next_frame = cg_core.vk_swapchain->current_frame + 1; + if(next_frame == Swapchain::max_frames_in_flight) next_frame = 0; + + vkResetFences(cg_core.vk_device_with_swapchain->device, 1, + &cg_core.vk_swapchain->in_flight_fences[ + cg_core.vk_swapchain->current_frame]); + + uint32_t image_index; + vkAcquireNextImageKHR( + cg_core.vk_device_with_swapchain->device, + cg_core.vk_swapchain->swapchain, std::numeric_limits::max(), + cg_core.vk_swapchain->image_available_semaphores[ + cg_core.vk_swapchain->current_frame], VK_NULL_HANDLE, &image_index); + + VkCommandBuffer draw_command_buffer = + this->draw_command_buffers[cg_core.vk_swapchain->current_frame]; + vkResetCommandBuffer(draw_command_buffer, 0); + + // Begin command buffer. + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags = 0; + begin_info.pInheritanceInfo = nullptr; + if (vkBeginCommandBuffer(draw_command_buffer, &begin_info) != VK_SUCCESS) + throw std::runtime_error{"Failed to beggin draw command buffer."}; + } + + // 3D drawing. + { + // Dark gray blue. + std::array clear_values{}; + clear_values[0].color = {0.12f, 0.12f, 0.18f, 1.0f}; + clear_values[1].depthStencil = {1.0f, 0}; + + { // Update world uniform buffer + UDOWorld3D_Vert ubo_world_3d_vert{}; + ubo_world_3d_vert.ambient_light_color = + glm::vec4{0.25, 0.25, 0.25, 1.0}; + cg_core.vk_light->ub_world_vert[image_index].copy_data( + &ubo_world_3d_vert); + + UDOWorld3D_Frag ubo_world_3d_frag{}; + ubo_world_3d_frag.directional_light_direction = + glm::vec3{-0.57735, 0.57735, -0.57735}; + ubo_world_3d_frag.directional_light_color = + glm::vec4{0.8, 0.8, 0.8, 1.0}; + cg_core.vk_light->ub_world_frag[image_index].copy_data( + &ubo_world_3d_frag); + } + + VkRenderPassBeginInfo render_pass_begin{}; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = nullptr; + render_pass_begin.renderPass = cg_core.vk_render_pass->pipeline_3d; + render_pass_begin.framebuffer = + cg_core.vk_framebuffer->pipeline_3d[image_index]; + render_pass_begin.renderArea.offset = {0, 0}; + render_pass_begin.renderArea.extent = { + static_cast(cg_core.display_width), + static_cast(cg_core.display_height)}; + render_pass_begin.clearValueCount = clear_values.size(); + render_pass_begin.pClearValues = clear_values.data(); + + vkCmdBeginRenderPass( + draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); + } + + for(auto &view: this->views_3d) + { + { // Set viewport + VkViewport vk_viewport{}; + vk_viewport.x = view->region.x; + vk_viewport.y = view->region.y; + vk_viewport.width = view->region.z; + vk_viewport.height = view->region.w; + vk_viewport.minDepth = 0.0f; + vk_viewport.maxDepth = 1.0f; + vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); + + VkRect2D vk_scissor{}; + vk_scissor.offset.x = static_cast(view->region.x); + vk_scissor.offset.y = static_cast(view->region.y); + vk_scissor.extent.width = static_cast(view->region.z); + vk_scissor.extent.height = static_cast(view->region.w); + vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); + } + + cg_core.vk_graphics_pipeline_3d->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + image_index); + + cg_core.vk_graphics_pipeline_sprite_3d->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + image_index); + + cg_core.vk_graphics_pipeline_3d_skeletal->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + image_index); + + { // Update view uniform buffers + BluCat::UDOView3D ubo_view_3d{}; + + // View matrix. + glm::mat4 translation_matrix{1.0f}; + translation_matrix = glm::translate( + translation_matrix, *view->camera_position); + glm::mat4 rotation_matrix{glm::toMat4(*view->camera_orientation)}; + ubo_view_3d.view = glm::inverse(translation_matrix * rotation_matrix); + + // Projection matrix. + ubo_view_3d.proj = glm::perspective( + glm::radians(view->field_of_view), + view->region.z / view->region.w, + 0.1f, 100.0f); + + view->ub_3d[image_index].copy_data(&ubo_view_3d); + } + } + + vkCmdEndRenderPass(draw_command_buffer); + + { // 2D render pass + VkRenderPassBeginInfo render_pass_begin{}; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = nullptr; + render_pass_begin.renderPass = cg_core.vk_render_pass->pipeline_2d; + render_pass_begin.framebuffer = + cg_core.vk_framebuffer->pipeline_2d[image_index]; + render_pass_begin.renderArea.offset = {0, 0}; + render_pass_begin.renderArea.extent = { + static_cast(cg_core.display_width), + static_cast(cg_core.display_height)}; + render_pass_begin.clearValueCount = 0; + render_pass_begin.pClearValues = nullptr; + + vkCmdBeginRenderPass( + draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); + + } + + { // 2D solid drawing + for(auto &view: this->views_2d) + cg_core.vk_graphics_pipeline_2d_solid->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + next_frame, image_index); + + for(auto &view: this->views_3d) + cg_core.vk_graphics_pipeline_2d_solid->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + next_frame, image_index); + } + + { // 2D wired drawing + for(auto &view: this->views_2d) + cg_core.vk_graphics_pipeline_2d_wired->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + next_frame, image_index); + + for(auto &view: this->views_3d) + cg_core.vk_graphics_pipeline_2d_wired->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + next_frame, image_index); + } + + vkCmdEndRenderPass(draw_command_buffer); + + // End command buffer. + if(vkEndCommandBuffer(draw_command_buffer) != VK_SUCCESS) + throw std::runtime_error{"Failed to end draw command buffer."}; + + // Submit drawing command. + { + auto queue{this->queue_family->get_queue()}; + + VkSemaphore wait_semaphores[]{ + cg_core.vk_swapchain->image_available_semaphores[ + cg_core.vk_swapchain->current_frame]}; + VkPipelineStageFlags wait_stages[] = + {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + VkSemaphore signal_semaphores[]{ + cg_core.vk_swapchain->render_finished_semaphores[ + cg_core.vk_swapchain->current_frame]}; + + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = nullptr; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = wait_semaphores; + submit_info.pWaitDstStageMask = wait_stages; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &draw_command_buffer; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal_semaphores; + + if(vkQueueSubmit( + queue.queue, 1, &submit_info, cg_core.vk_swapchain->in_flight_fences[ + cg_core.vk_swapchain->current_frame]) != VK_SUCCESS) + throw std::runtime_error{"Failed to submit draw command buffer."}; + + VkSwapchainKHR swap_chains[]{cg_core.vk_swapchain->swapchain}; + + VkPresentInfoKHR present_info{}; + present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_info.pNext = nullptr; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = signal_semaphores; + present_info.swapchainCount = 1; + present_info.pSwapchains = swap_chains; + present_info.pImageIndices = &image_index; + present_info.pResults = nullptr; + + vkQueuePresentKHR(queue.queue, &present_info); + } + + // Prepare for the next frame. + { + this->skeletal_models_to_draw[next_frame].clear(); + this->static_models_to_draw[next_frame].clear(); + this->sprites_3d_to_draw[next_frame].clear(); + cg_core.vk_swapchain->current_frame = next_frame; + } + } + else + { + // Clear images for the current frame because we are skipping this frame. + this->skeletal_models_to_draw[cg_core.vk_swapchain->current_frame].clear(); + this->static_models_to_draw[cg_core.vk_swapchain->current_frame].clear(); + this->sprites_3d_to_draw[cg_core.vk_swapchain->current_frame].clear(); + for(auto &view: this->views_2d) + view->sprites_to_draw[cg_core.vk_swapchain->current_frame].clear(); + for(auto &view: this->views_3d) + view->sprites_to_draw[cg_core.vk_swapchain->current_frame].clear(); + } +} + +} diff --git a/src/blucat/renderer.hpp b/src/blucat/renderer.hpp new file mode 100644 index 0000000..d23ebe5 --- /dev/null +++ b/src/blucat/renderer.hpp @@ -0,0 +1,72 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_RENDERER_H +#define CANDY_GEAR_BLUCAT_RENDERER_H 1 + +#include +#include +#include + +#include "core.hpp" +#include "skeletal_mesh.hpp" +#include "skeletal_model.hpp" +#include "sprite_3d.hpp" +#include "static_mesh.hpp" +#include "static_model.hpp" +#include "queue_family.hpp" +#include "view_2d.hpp" +#include "view_3d.hpp" + +namespace BluCat +{ + +struct Renderer +{ + std::vector< + std::unordered_map< + std::shared_ptr, + std::vector>>> + skeletal_models_to_draw; + + std::vector< + std::unordered_map< + std::shared_ptr, + std::vector>>> + static_models_to_draw; + + std::vector>> sprites_3d_to_draw; + + VkDescriptorPool descriptor_pool; + std::vector> views_2d; + std::vector> views_3d; + QueueFamily *queue_family; + VkCommandPool command_pool; + std::vector draw_command_buffers; + + Renderer(std::vector> views_2d, + std::vector> views_3d); + Renderer(std::initializer_list> views_2d, + std::initializer_list> views_3d); + ~Renderer(); + + void + draw(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_RENDERER_H */ diff --git a/src/blucat/skeletal_mesh.cpp b/src/blucat/skeletal_mesh.cpp new file mode 100644 index 0000000..baea635 --- /dev/null +++ b/src/blucat/skeletal_mesh.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "skeletal_mesh.hpp" + +#include "../binary_reader.hpp" +#include "../command.hpp" +#include "../core.hpp" +#include "skeletal_mesh_vertex.hpp" + +namespace +{ + +// Data that is only needed for the command chain but not for the SkeletalMesh +// goes here. +struct MeshBuilder +{ + std::string mesh_path; + BluCat::SkeletalMesh *mesh; + + MeshBuilder(BluCat::SkeletalMesh *m, std::string mp); + MeshBuilder(BluCat::SkeletalMesh *m, const char* mp); +}; + +MeshBuilder::MeshBuilder(BluCat::SkeletalMesh *m, std::string mp): + mesh{m}, + mesh_path{mp} +{ +} + +MeshBuilder::MeshBuilder(BluCat::SkeletalMesh *m, const char *mp): + MeshBuilder{m, std::string(mp)} +{ +} + +void +load_mesh(void *obj) +{ + auto self = static_cast(obj); + + BinaryReader input{self->mesh_path}; + + self->mesh->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + + { // Load vertexes. + auto vertex_count{input.read_ui32()}; + std::vector vertexes{vertex_count}; + + for(auto i{0}; i < vertex_count; i++) + { + vertexes[i].position = input.read_vec3(); + vertexes[i].normal = input.read_vec3(); + vertexes[i].texture_coord = input.read_vec2(); + + for(auto ii{0}; ii < BluCat::SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES; + ii++) + vertexes[i].bone_ids[ii] = input.read_ui32(); + + for(auto ii{0}; ii < BluCat::SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES; + ii++) + vertexes[i].bone_weights[ii] = input.read_float(); + } + + void *vertexes_data{vertexes.data()}; + size_t vertexes_size = sizeof(vertexes[0]) * vertexes.size(); + self->mesh->source_vertex_buffer = new BluCat::SourceBuffer{ + self->mesh->queue_family->device, vertexes_data, vertexes_size}; + self->mesh->vertex_buffer = new BluCat::DestinationBuffer{ + self->mesh->queue_family, self->mesh->source_vertex_buffer, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; + } + + { // Load indexes. + self->mesh->index_count = input.read_ui32(); + std::vector indexes(self->mesh->index_count); + + for(auto i{0}; i < self->mesh->index_count; i++) + indexes[i] = input.read_ui32(); + + void *indexes_data{indexes.data()}; + size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; + BluCat::SourceBuffer source_index_buffer{ + self->mesh->queue_family->device, indexes_data, indexes_size}; + self->mesh->index_buffer = new BluCat::DestinationBuffer{ + self->mesh->queue_family, &source_index_buffer, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; + } + + { // Load bones + auto bone_count{input.read_ui32()}; + self->mesh->bones.reserve(bone_count); + for(int i{0}; i < bone_count; i++) + self->mesh->bones.emplace_back(input.read_mat4()); + } + + { // Load animations + auto num_animations{input.read_ui32()}; + self->mesh->animations.resize(num_animations); + for(uint32_t i{0}; i < num_animations; i++) + { + auto duration{input.read_double()}; + self->mesh->animations[i].final_time = (float)duration; + + auto ticks_per_second{input.read_double()}; + + auto num_bone_transforms{input.read_ui32()}; + std::vector *bone_transforms = + &(self->mesh->animations[i].bone_transforms); + bone_transforms->resize(num_bone_transforms); + for(uint32_t bone_transform_index{0}; + bone_transform_index < num_bone_transforms; bone_transform_index++) + { + auto bone_id{input.read_ui32()}; + + auto num_positions{input.read_ui32()}; + BluCat::Channel *positions = + &((*bone_transforms)[bone_transform_index].positions); + for(auto position_key_index{0}; position_key_index < num_positions; + position_key_index++) + { + auto vec3{input.read_vec3()}; + auto timestamp{input.read_double()}; + positions->key_frames.emplace_back( + vec3, static_cast(timestamp)); + } + + auto num_rotations{input.read_ui32()}; + BluCat::Channel *rotations = + &((*bone_transforms)[bone_transform_index].rotations); + for(auto rotation_key_index{0}; rotation_key_index < num_rotations; + rotation_key_index++) + { + auto quat{input.read_quat()}; + auto timestamp{input.read_double()}; + rotations->key_frames.emplace_back( + quat, static_cast(timestamp)); + } + + auto num_scales{input.read_ui32()}; + BluCat::Channel *scales = + &((*bone_transforms)[bone_transform_index].scales); + for(auto scaling_key_index{0}; scaling_key_index < num_scales; + scaling_key_index++) + { + auto vec3{input.read_vec3()}; + auto timestamp{input.read_double()}; + scales->key_frames.emplace_back(vec3, static_cast(timestamp)); + } + } + } + } +} + +void +unload_mesh(void *obj) +{ + auto self = static_cast(obj); + + delete self->mesh->index_buffer; + delete self->mesh->vertex_buffer; + delete self->mesh->source_vertex_buffer; +} + +static const CommandChain loader{ + {&load_mesh, &unload_mesh} +}; + +} + +namespace BluCat +{ + +SkeletalMesh::SkeletalMesh(std::string mesh_path) +{ + MeshBuilder mesh_builder(this, mesh_path); + loader.execute(&mesh_builder); +} + +SkeletalMesh::SkeletalMesh(const char* mesh_path): + SkeletalMesh{std::string(mesh_path)} +{ +} + +SkeletalMesh::~SkeletalMesh() +{ + MeshBuilder mesh_builder(this, ""); + loader.revert(&mesh_builder); +} + +} diff --git a/src/blucat/skeletal_mesh.hpp b/src/blucat/skeletal_mesh.hpp new file mode 100644 index 0000000..8b7d0fe --- /dev/null +++ b/src/blucat/skeletal_mesh.hpp @@ -0,0 +1,52 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SKELETAL_MESH_H +#define CANDY_GEAR_BLUCAT_SKELETAL_MESH_H 1 + +#include +#include + +#include "animation.hpp" +#include "core.hpp" +#include "destination_buffer.hpp" +#include "queue_family.hpp" +#include "uniform_buffer.hpp" +#include "texture.hpp" + +namespace BluCat +{ + +struct SkeletalMesh +{ + QueueFamily *queue_family; + + uint32_t index_count; + SourceBuffer *source_vertex_buffer; + DestinationBuffer *index_buffer; + DestinationBuffer *vertex_buffer; + + std::vector bones; + std::vector animations; + + SkeletalMesh(std::string mesh_path); + SkeletalMesh(const char* mesh_path); + ~SkeletalMesh(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SKELETAL_MESH_H */ diff --git a/src/blucat/skeletal_mesh_vertex.hpp b/src/blucat/skeletal_mesh_vertex.hpp new file mode 100644 index 0000000..533c2ab --- /dev/null +++ b/src/blucat/skeletal_mesh_vertex.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SKELETAL_MESH_VERTEX_H +#define CANDY_GEAR_BLUCAT_SKELETAL_MESH_VERTEX_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +// This variable define the maximum ammount of bones that can influence a +// vertex. +const int SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES{4}; +const int SKELETAL_MESH_MAX_NUM_OF_BONES{50}; + +struct SkeletalMeshVertex +{ + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texture_coord; + + uint32_t bone_ids[SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES]; + float bone_weights[SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES]; +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SKELETAL_MESH_VERTEX_H */ diff --git a/src/blucat/skeletal_model.cpp b/src/blucat/skeletal_model.cpp new file mode 100644 index 0000000..8761bc8 --- /dev/null +++ b/src/blucat/skeletal_model.cpp @@ -0,0 +1,238 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "skeletal_model.hpp" + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_uniform_buffers(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->uniform_buffers.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->uniform_buffers.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOSkeletalModel)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_uniform_buffers(void *obj) +{ + auto self = static_cast(obj); + + self->uniform_buffers.clear(); +} + +void +load_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + std::array descriptor_pool_sizes{}; + descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_sizes[0].descriptorCount = + self->uniform_buffers.size(); + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = self->uniform_buffers.size(); + pool_info.poolSizeCount = descriptor_pool_sizes.size(); + pool_info.pPoolSizes = descriptor_pool_sizes.data(); + + if(vkCreateDescriptorPool( + self->skeletal_mesh->queue_family->device->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorPool( + self->skeletal_mesh->queue_family->device->device, self->descriptor_pool, + nullptr); +} + +void +load_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->model); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets.resize(layouts.size()); + if(vkAllocateDescriptorSets( + self->skeletal_mesh->queue_family->device->device, &alloc_info, + self->descriptor_sets.data()) != VK_SUCCESS) + CommandError{"Failed to create Vulkan descriptor set."}; +} + +void +load_buffers_to_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->uniform_buffers.size(); i++) + { + VkDescriptorBufferInfo buffer_info{}; + buffer_info.buffer = self->uniform_buffers[i].buffer; + buffer_info.offset = 0; + buffer_info.range = sizeof(BluCat::UDOSkeletalModel); + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &buffer_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +static const CommandChain loader{ + {&load_uniform_buffers, &unload_uniform_buffers}, + {&load_descriptor_set_pool, &unload_descriptor_set_pool}, + {&load_descriptor_sets, nullptr}, + {&load_buffers_to_descriptor_sets, nullptr} +}; + +} + +namespace BluCat +{ + +SkeletalModel::SkeletalModel( + std::shared_ptr skeletal_mesh, + std::shared_ptr texture, std::shared_ptr position, + std::shared_ptr orientation): + skeletal_mesh{skeletal_mesh}, + texture{texture}, + position{position}, + orientation{orientation}, + animation_index{0}, + animation_time{0.0f}, + bone_transforms(SKELETAL_MESH_MAX_NUM_OF_BONES) +{ + loader.execute(this); + + for(int i{0}; i < skeletal_mesh->bones.size(); i++) + this->bone_transforms[i] = skeletal_mesh->bones[i].offset_matrix; +} + +SkeletalModel::~SkeletalModel() +{ + loader.revert(this); +} + +void +SkeletalModel::tick(float delta) +{ + BluCat::Animation *current_animation = + &this->skeletal_mesh->animations[this->animation_index]; + + { // update time + this->animation_time += delta; + if(this->animation_time > current_animation->final_time) + { + this->animation_time -= current_animation->final_time; + for(BluCat::BoneTransform &bone_transform: + current_animation->bone_transforms) + { + bone_transform.positions.current_index = 0; + bone_transform.rotations.current_index = 0; + bone_transform.scales.current_index = 0; + } + } + } + + for(int i{0}; i < current_animation->bone_transforms.size(); i++) + { + BluCat::BoneTransform *bone_transform = ¤t_animation->bone_transforms[i]; + + auto position{bone_transform->positions.interpolate( + this->animation_time, + [](glm::vec3 frame) + { + return glm::translate(glm::mat4(1.0f), frame); + }, + [](glm::vec3 previous_frame, glm::vec3 next_frame, float scale_factor) + { + glm::vec3 final_position{glm::mix( + previous_frame, next_frame, scale_factor)}; + return glm::translate(glm::mat4(1.0f), final_position); + })}; + + auto rotation{bone_transform->rotations.interpolate( + this->animation_time, + [](glm::quat frame) + { + return glm::toMat4(glm::normalize(frame)); + }, + [](glm::quat previous_frame, glm::quat next_frame, float scale_factor) + { + return glm::toMat4(glm::slerp( + previous_frame, next_frame, scale_factor)); + })}; + + auto scale{bone_transform->scales.interpolate( + this->animation_time, + [](glm::vec3 frame) + { + return glm::scale(glm::mat4(1.0f), frame); + }, + [](glm::vec3 previous_frame, glm::vec3 next_frame, float scale_factor) + { + glm::vec3 scale{glm::mix( + previous_frame, next_frame, scale_factor)}; + return glm::scale(glm::mat4(1.0f), scale); + })}; + + this->bone_transforms[i] = position * rotation * scale; + } +} + +} diff --git a/src/blucat/skeletal_model.hpp b/src/blucat/skeletal_model.hpp new file mode 100644 index 0000000..cd3685e --- /dev/null +++ b/src/blucat/skeletal_model.hpp @@ -0,0 +1,55 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SKELETAL_MODEL_H +#define CANDY_GEAR_BLUCAT_SKELETAL_MODEL_H 1 + +#include +#include + +#include "core.hpp" +#include "skeletal_mesh.hpp" + +namespace BluCat +{ + +struct SkeletalModel +{ + std::shared_ptr skeletal_mesh; + std::shared_ptr texture; + std::vector uniform_buffers; + std::shared_ptr position; + std::shared_ptr orientation; + int animation_index; + float animation_time; + std::vector bone_transforms; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets; + + SkeletalModel( + std::shared_ptr skeletal_mesh, + std::shared_ptr texture, std::shared_ptr position, + std::shared_ptr orientation); + ~SkeletalModel(); + + void + tick(float delta); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SKELETAL_MODEL_H */ diff --git a/src/blucat/source_buffer.cpp b/src/blucat/source_buffer.cpp new file mode 100644 index 0000000..41c40b9 --- /dev/null +++ b/src/blucat/source_buffer.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "source_buffer.hpp" + +#include + +namespace BluCat +{ + +SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size) +{ + this->device = device; + this->device_size = data_size; + this->buffer_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + this->memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + try + { + BluCat::BaseBuffer::loader.execute(static_cast(this)); + } + catch(const CommandError &command_error) + { + std::string error{"Could not initialize Vulkan source buffer → "}; + error += command_error.what(); + throw std::runtime_error{error}; + } + this->copy_data(data); +} + +SourceBuffer::SourceBuffer(SourceBuffer &&that) +{ + this->buffer = that.buffer; + this->device_memory = that.device_memory; + this->device_size = that.device_size; + this->buffer_usage = that.buffer_usage; + this->memory_properties = that.memory_properties; + + that.buffer = VK_NULL_HANDLE; + that.device_memory = VK_NULL_HANDLE; +} + +SourceBuffer& +SourceBuffer::operator=(SourceBuffer &&that) +{ + this->buffer = that.buffer; + this->device_memory = that.device_memory; + this->device_size = that.device_size; + this->buffer_usage = that.buffer_usage; + this->memory_properties = that.memory_properties; + + that.buffer = VK_NULL_HANDLE; + that.device_memory = VK_NULL_HANDLE; + + return *this; +} + +SourceBuffer::~SourceBuffer() +{ + BluCat::BaseBuffer::loader.revert(static_cast(this)); +} + +void +SourceBuffer::copy_data(void *src_data) +{ + void *dst_data; + vkMapMemory(this->device->device, this->device_memory, 0, this->device_size, + 0, &dst_data); + memcpy(dst_data, src_data, static_cast(this->device_size)); + vkUnmapMemory(this->device->device, this->device_memory); +} + +} diff --git a/src/blucat/source_buffer.hpp b/src/blucat/source_buffer.hpp new file mode 100644 index 0000000..dd52acc --- /dev/null +++ b/src/blucat/source_buffer.hpp @@ -0,0 +1,45 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SOURCE_BUFFER_H +#define CANDY_GEAR_BLUCAT_SOURCE_BUFFER_H 1 + +#include "base_buffer.hpp" + +namespace BluCat +{ + +struct SourceBuffer: public BaseBuffer +{ + SourceBuffer(const SourceBuffer &t) = delete; + SourceBuffer& + operator=(const SourceBuffer &t) = delete; + + SourceBuffer(Device *device, void *data, size_t data_size); + + SourceBuffer(SourceBuffer &&that); + SourceBuffer& + operator=(SourceBuffer &&that); + + ~SourceBuffer(); + + void + copy_data(void *src_data); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SOURCE_BUFFER_H */ diff --git a/src/blucat/sprite.cpp b/src/blucat/sprite.cpp new file mode 100644 index 0000000..a275df8 --- /dev/null +++ b/src/blucat/sprite.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sprite.hpp" + +#include + +#include "../core.hpp" +#include "sprite.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +struct SpriteBuilder +{ + BluCat::Sprite *sprite; + glm::vec4 ▭ + + SpriteBuilder(BluCat::Sprite *sprite, glm::vec4 &rect); +}; + +SpriteBuilder::SpriteBuilder(BluCat::Sprite *sprite, glm::vec4 &rect): + sprite{sprite}, + rect{rect} +{ +} + +void +load_mesh(void *obj) +{ + auto self = static_cast(obj); + + self->sprite->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + + glm::vec2 rect[BluCat::Sprite::vertex_count]{ + glm::vec2{self->rect.x, self->rect.y}, + glm::vec2{self->rect.x, self->rect.w}, + glm::vec2{self->rect.z, self->rect.y}, + glm::vec2{self->rect.z, self->rect.w} + }; + + void *vertexes_data{&rect}; + static const size_t vertexes_size = + sizeof(glm::vec2) * BluCat::Sprite::vertex_count; + self->sprite->source_buffer = new BluCat::SourceBuffer{ + self->sprite->queue_family->device, vertexes_data, vertexes_size}; + self->sprite->vertex_buffer = new BluCat::DestinationBuffer{ + self->sprite->queue_family, self->sprite->source_buffer, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; +} + +void +unload_mesh(void *obj) +{ + auto self = static_cast(obj); + + delete self->sprite->vertex_buffer; + delete self->sprite->source_buffer; +} + +static const CommandChain loader{ + {&load_mesh, &unload_mesh}, +}; + +} + +namespace BluCat +{ + +Sprite::Sprite(std::shared_ptr texture, glm::vec4 &rect): + texture{texture} +{ + SpriteBuilder sprite_builder(this, rect); + loader.execute(&sprite_builder); +} + +Sprite::~Sprite() +{ + glm::vec4 vector_4d{}; + SpriteBuilder sprite_builder(this, vector_4d); + loader.revert(&sprite_builder); +} + +} diff --git a/src/blucat/sprite.hpp b/src/blucat/sprite.hpp new file mode 100644 index 0000000..6252d00 --- /dev/null +++ b/src/blucat/sprite.hpp @@ -0,0 +1,50 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SPRITE_H +#define CANDY_GEAR_BLUCAT_SPRITE_H 1 + +#include +#include +#include + +#include "core.hpp" +#include "destination_buffer.hpp" +#include "queue_family.hpp" +#include "uniform_buffer.hpp" +#include "texture.hpp" + +namespace BluCat +{ + +struct Sprite +{ + static const uint32_t vertex_count{4}; + + QueueFamily *queue_family; + + SourceBuffer *source_buffer; + DestinationBuffer *vertex_buffer; + + std::shared_ptr texture; + + Sprite(std::shared_ptr texture, glm::vec4 &rect); + ~Sprite(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SPRITE_H */ diff --git a/src/blucat/sprite_3d.cpp b/src/blucat/sprite_3d.cpp new file mode 100644 index 0000000..6fa6d49 --- /dev/null +++ b/src/blucat/sprite_3d.cpp @@ -0,0 +1,168 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sprite_3d.hpp" + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_uniform_buffers(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->uniform_buffers.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->uniform_buffers.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOSprite3D)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_uniform_buffers(void *obj) +{ + auto self = static_cast(obj); + + self->uniform_buffers.clear(); +} + +void +load_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + std::array descriptor_pool_sizes{}; + descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_sizes[0].descriptorCount = + self->uniform_buffers.size(); + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = self->uniform_buffers.size(); + pool_info.poolSizeCount = descriptor_pool_sizes.size(); + pool_info.pPoolSizes = descriptor_pool_sizes.data(); + + if(vkCreateDescriptorPool( + self->queue_family->device->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorPool( + self->queue_family->device->device, self->descriptor_pool, nullptr); +} +void +load_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->model); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets.resize(layouts.size()); + if(vkAllocateDescriptorSets( + self->queue_family->device->device, &alloc_info, + self->descriptor_sets.data()) != VK_SUCCESS) + CommandError{"Failed to create Vulkan descriptor set."}; +} + +void +load_buffers_to_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->uniform_buffers.size(); i++) + { + VkDescriptorBufferInfo buffer_info{}; + buffer_info.buffer = self->uniform_buffers[i].buffer; + buffer_info.offset = 0; + buffer_info.range = sizeof(BluCat::UDOSprite3D); + + VkDescriptorImageInfo image_info{}; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info.imageView = self->sprite->texture->view; + image_info.sampler = self->sprite->texture->sampler; + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &buffer_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +static const CommandChain loader{ + {&load_uniform_buffers, &unload_uniform_buffers}, + {&load_descriptor_set_pool, &unload_descriptor_set_pool}, + {&load_descriptor_sets, nullptr}, + {&load_buffers_to_descriptor_sets, nullptr} +}; + +} + +namespace BluCat +{ + +Sprite3D::Sprite3D( + std::shared_ptr sprite, std::shared_ptr position, + glm::vec2 size): + sprite{sprite}, + position{position}, + size{size} +{ + this->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + loader.execute(this); +} + +Sprite3D::~Sprite3D() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/sprite_3d.hpp b/src/blucat/sprite_3d.hpp new file mode 100644 index 0000000..dd0f16e --- /dev/null +++ b/src/blucat/sprite_3d.hpp @@ -0,0 +1,46 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SPRITE_3D_H +#define CANDY_GEAR_BLUCAT_SPRITE_3D_H 1 + +#include "core.hpp" +#include "sprite.hpp" + +namespace BluCat +{ + +struct Sprite3D +{ + std::shared_ptr sprite; + std::shared_ptr position; + glm::vec2 size; + + QueueFamily *queue_family; + + std::vector uniform_buffers; + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets; + + Sprite3D( + std::shared_ptr sprite, std::shared_ptr position, + glm::vec2 size); + ~Sprite3D(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SPRITE_3D_H */ diff --git a/src/blucat/sprite_to_draw.cpp b/src/blucat/sprite_to_draw.cpp new file mode 100644 index 0000000..9013adb --- /dev/null +++ b/src/blucat/sprite_to_draw.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sprite_to_draw.hpp" + +namespace BluCat +{ + SpriteToDraw::SpriteToDraw( + std::shared_ptr sprite, const glm::vec4 &position, float z_index): + sprite{sprite}, + position{position}, + z_index{z_index} + { + } + + bool + operator<(const SpriteToDraw& a, const SpriteToDraw& b) + { + return a.z_index < b.z_index; + } + + bool + operator>(const SpriteToDraw& a, const SpriteToDraw& b) + { + return a.z_index > b.z_index; + } +} diff --git a/src/blucat/sprite_to_draw.hpp b/src/blucat/sprite_to_draw.hpp new file mode 100644 index 0000000..fb46eac --- /dev/null +++ b/src/blucat/sprite_to_draw.hpp @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SPRITES_TO_DRAW_H +#define CANDY_GEAR_BLUCAT_SPRITES_TO_DRAW_H 1 + +#include + +#include "core.hpp" +#include "sprite.hpp" + +namespace BluCat +{ + struct SpriteToDraw + { + std::shared_ptr sprite; + glm::vec4 position; + float z_index; + + SpriteToDraw(std::shared_ptr sprite, const glm::vec4 &position, + float z_index); + }; + + bool + operator<(const SpriteToDraw &a, const SpriteToDraw &b); + + bool + operator>(const SpriteToDraw &a, const SpriteToDraw &b); +} + +#endif /* CANDY_GEAR_BLUCAT_SPRITES_TO_DRAW_H */ diff --git a/src/blucat/static_mesh.cpp b/src/blucat/static_mesh.cpp new file mode 100644 index 0000000..ab45ca9 --- /dev/null +++ b/src/blucat/static_mesh.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "static_mesh.hpp" + +#include "../binary_reader.hpp" +#include "../command.hpp" +#include "../core.hpp" +#include "static_mesh_vertex.hpp" + +namespace +{ + +// Data that is only needed for the command chain but not for the StaticMesh +// goes here. +struct MeshBuilder +{ + std::string mesh_path; + BluCat::StaticMesh *mesh; + + MeshBuilder(BluCat::StaticMesh *m, std::string mp); + MeshBuilder(BluCat::StaticMesh *m, const char* mp); +}; + +MeshBuilder::MeshBuilder(BluCat::StaticMesh *m, std::string mp): + mesh{m}, + mesh_path{mp} +{ +} + +MeshBuilder::MeshBuilder(BluCat::StaticMesh *m, const char *mp): + MeshBuilder{m, std::string(mp)} +{ +} + +void +load_mesh(void *obj) +{ + auto self = static_cast(obj); + + BinaryReader input{self->mesh_path}; + + self->mesh->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + + { // Load vertexes. + auto vertex_count{input.read_ui32()}; + std::vector vertexes{vertex_count}; + + for(auto i{0}; i < vertex_count; i++) + { + vertexes[i].position = input.read_vec3(); + vertexes[i].normal = input.read_vec3(); + vertexes[i].texture_coord = input.read_vec2(); + } + + void *vertexes_data{vertexes.data()}; + size_t vertexes_size = sizeof(vertexes[0]) * vertexes.size(); + self->mesh->source_vertex_buffer = new BluCat::SourceBuffer{ + self->mesh->queue_family->device, vertexes_data, vertexes_size}; + self->mesh->vertex_buffer = new BluCat::DestinationBuffer{ + self->mesh->queue_family, self->mesh->source_vertex_buffer, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; + } + + { // Load indexes + self->mesh->index_count = input.read_ui32(); + std::vector indexes(self->mesh->index_count); + + for(auto i{0}; i < self->mesh->index_count; i++) + indexes[i] = input.read_ui32(); + + void *indexes_data{indexes.data()}; + size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; + BluCat::SourceBuffer source_index_buffer{ + self->mesh->queue_family->device, indexes_data, indexes_size}; + self->mesh->index_buffer = new BluCat::DestinationBuffer{ + self->mesh->queue_family, &source_index_buffer, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; + } +} + +void +unload_mesh(void *obj) +{ + auto self = static_cast(obj); + + delete self->mesh->index_buffer; + delete self->mesh->vertex_buffer; + delete self->mesh->source_vertex_buffer; +} + +static const CommandChain loader{ + {&load_mesh, &unload_mesh} +}; + +} + +namespace BluCat +{ + +StaticMesh::StaticMesh(std::string mesh_path) +{ + MeshBuilder mesh_builder(this, mesh_path); + loader.execute(&mesh_builder); +} + +StaticMesh::StaticMesh(const char* mesh_path): + StaticMesh{std::string(mesh_path)} +{ +} + +StaticMesh::~StaticMesh() +{ + MeshBuilder mesh_builder(this, ""); + loader.revert(&mesh_builder); +} + +} diff --git a/src/blucat/static_mesh.hpp b/src/blucat/static_mesh.hpp new file mode 100644 index 0000000..0efcfc1 --- /dev/null +++ b/src/blucat/static_mesh.hpp @@ -0,0 +1,48 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_STATIC_MESH_H +#define CANDY_GEAR_BLUCAT_STATIC_MESH_H 1 + +#include +#include + +#include "core.hpp" +#include "destination_buffer.hpp" +#include "queue_family.hpp" +#include "uniform_buffer.hpp" +#include "texture.hpp" + +namespace BluCat +{ + +struct StaticMesh +{ + QueueFamily *queue_family; + + uint32_t index_count; + SourceBuffer *source_vertex_buffer; + DestinationBuffer *index_buffer; + DestinationBuffer *vertex_buffer; + + StaticMesh(std::string mesh_path); + StaticMesh(const char* mesh_path); + ~StaticMesh(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_STATIC_MESH_H */ diff --git a/src/blucat/static_mesh_vertex.hpp b/src/blucat/static_mesh_vertex.hpp new file mode 100644 index 0000000..025ad63 --- /dev/null +++ b/src/blucat/static_mesh_vertex.hpp @@ -0,0 +1,34 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_STATIC_MESH_VERTEX_H +#define CANDY_GEAR_BLUCAT_STATIC_MESH_VERTEX_H 1 + +#include "core.hpp" + +namespace BluCat +{ + +struct StaticMeshVertex +{ + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texture_coord; +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_STATIC_MESH_VERTEX_H */ diff --git a/src/blucat/static_model.cpp b/src/blucat/static_model.cpp new file mode 100644 index 0000000..e3c6482 --- /dev/null +++ b/src/blucat/static_model.cpp @@ -0,0 +1,165 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "static_model.hpp" + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_uniform_buffers(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->uniform_buffers.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->uniform_buffers.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOStaticModel)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_uniform_buffers(void *obj) +{ + auto self = static_cast(obj); + + self->uniform_buffers.clear(); +} + +void +load_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + std::array descriptor_pool_sizes{}; + descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_sizes[0].descriptorCount = + self->uniform_buffers.size(); + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = self->uniform_buffers.size(); + pool_info.poolSizeCount = descriptor_pool_sizes.size(); + pool_info.pPoolSizes = descriptor_pool_sizes.data(); + + if(vkCreateDescriptorPool( + self->static_mesh->queue_family->device->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorPool( + self->static_mesh->queue_family->device->device, self->descriptor_pool, + nullptr); +} + +void +load_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->model); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets.resize(layouts.size()); + if(vkAllocateDescriptorSets( + self->static_mesh->queue_family->device->device, &alloc_info, + self->descriptor_sets.data()) != VK_SUCCESS) + CommandError{"Failed to create Vulkan descriptor set."}; +} + +void +load_buffers_to_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->uniform_buffers.size(); i++) + { + VkDescriptorBufferInfo buffer_info{}; + buffer_info.buffer = self->uniform_buffers[i].buffer; + buffer_info.offset = 0; + buffer_info.range = sizeof(BluCat::UDOStaticModel); + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &buffer_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +static const CommandChain loader{ + {&load_uniform_buffers, &unload_uniform_buffers}, + {&load_descriptor_set_pool, &unload_descriptor_set_pool}, + {&load_descriptor_sets, nullptr}, + {&load_buffers_to_descriptor_sets, nullptr} +}; + +} + +namespace BluCat +{ + +StaticModel::StaticModel( + std::shared_ptr static_mesh, + std::shared_ptr texture, std::shared_ptr position, + std::shared_ptr orientation): + static_mesh{static_mesh}, + texture{texture}, + position{position}, + orientation{orientation} +{ + loader.execute(this); +} + +StaticModel::~StaticModel() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/static_model.hpp b/src/blucat/static_model.hpp new file mode 100644 index 0000000..68c5ea1 --- /dev/null +++ b/src/blucat/static_model.hpp @@ -0,0 +1,49 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_STATIC_MODEL_H +#define CANDY_GEAR_BLUCAT_STATIC_MODEL_H 1 + +#include +#include + +#include "core.hpp" +#include "static_mesh.hpp" + +namespace BluCat +{ + +struct StaticModel +{ + std::shared_ptr static_mesh; + std::shared_ptr texture; + std::vector uniform_buffers; + std::shared_ptr position; + std::shared_ptr orientation; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets; + + StaticModel( + std::shared_ptr static_mesh, + std::shared_ptr texture, std::shared_ptr position, + std::shared_ptr orientation); + ~StaticModel(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_STATIC_MODEL_H */ diff --git a/src/blucat/swapchain.cpp b/src/blucat/swapchain.cpp new file mode 100644 index 0000000..1e521e4 --- /dev/null +++ b/src/blucat/swapchain.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "swapchain.hpp" + +#include "../core.hpp" + +#include + +namespace +{ + +void +load_swapchain(void *obj) +{ + auto self = static_cast(obj); + + // Surface formats. + uint32_t vk_surface_format_count; + std::vector vk_surface_formats; + vkGetPhysicalDeviceSurfaceFormatsKHR( + cg_core.vk_device_with_swapchain->physical_device, cg_core.window_surface, + &vk_surface_format_count, nullptr); + vk_surface_formats.resize(vk_surface_format_count); + vkGetPhysicalDeviceSurfaceFormatsKHR( + cg_core.vk_device_with_swapchain->physical_device, cg_core.window_surface, + &vk_surface_format_count, vk_surface_formats.data()); + + VkSwapchainCreateInfoKHR swapchain_create_info = {}; + swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchain_create_info.pNext = nullptr; + swapchain_create_info.flags = 0; + swapchain_create_info.surface = cg_core.window_surface; + swapchain_create_info.minImageCount = 3; // triple buffering. + + self->image_format = vk_surface_formats[0].format; + swapchain_create_info.imageFormat = self->image_format; + swapchain_create_info.imageColorSpace = vk_surface_formats[0].colorSpace; + + swapchain_create_info.imageExtent = { + cg_core.display_width, cg_core.display_height}; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_create_info.queueFamilyIndexCount = 0; + swapchain_create_info.pQueueFamilyIndices = nullptr; + swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; + swapchain_create_info.clipped = VK_FALSE; + swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; + + if(vkCreateSwapchainKHR( + cg_core.vk_device_with_swapchain->device, &swapchain_create_info, + nullptr, &self->swapchain) != VK_SUCCESS) + throw CommandError{"Vulkan failed to create swapchain."}; + + vkGetSwapchainImagesKHR( + cg_core.vk_device_with_swapchain->device, self->swapchain, + &self->images_count, nullptr); + self->images = new VkImage[self->images_count]; + vkGetSwapchainImagesKHR( + cg_core.vk_device_with_swapchain->device, self->swapchain, + &self->images_count, self->images); +} + +void +unload_swapchain(void *obj) +{ + auto self = static_cast(obj); + + delete[] self->images; + vkDestroySwapchainKHR( + cg_core.vk_device_with_swapchain->device, self->swapchain, nullptr); +} + +void +load_image_view(void *obj) +{ + auto self = static_cast(obj); + + self->image_views = new VkImageView[self->images_count]; + for(auto i{0}; i < self->images_count; i++) + { + VkImageViewCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + create_info.image = self->images[i]; + create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + create_info.format = self->image_format; + create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.levelCount = 1; + create_info.subresourceRange.baseArrayLayer = 0; + create_info.subresourceRange.layerCount = 1; + + if(vkCreateImageView( + cg_core.vk_device_with_swapchain->device, &create_info, nullptr, + &self->image_views[i])) + throw CommandError{"Could no create Image View for swapchain."}; + } +} + +void +unload_image_view(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->images_count; i++) + vkDestroyImageView( + cg_core.vk_device_with_swapchain->device, self->image_views[i], nullptr); +} + +void +load_frame_sync(void *obj) +{ + auto self = static_cast(obj); + + self->image_available_semaphores.resize(self->max_frames_in_flight); + self->render_finished_semaphores.resize(self->max_frames_in_flight); + self->in_flight_fences.resize(self->max_frames_in_flight); + + VkSemaphoreCreateInfo semaphore_info = {}; + semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphore_info.pNext = nullptr; + semaphore_info.flags = 0; + + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_info.pNext = nullptr; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + // FIXME: if this loop fails, it will not destroy the semaphores. + for(auto i{0}; i < self->max_frames_in_flight; i++) + { + if(vkCreateSemaphore( + cg_core.vk_device_with_swapchain->device, &semaphore_info, + nullptr, &self->image_available_semaphores[i]) != VK_SUCCESS || + vkCreateSemaphore( + cg_core.vk_device_with_swapchain->device, &semaphore_info, + nullptr, &self->render_finished_semaphores[i]) != VK_SUCCESS || + vkCreateFence(cg_core.vk_device_with_swapchain->device, &fence_info, + nullptr, &self->in_flight_fences[i]) != VK_SUCCESS) + throw CommandError{"Failed to create semaphores."}; + } +} + +void +unload_frame_sync(void *obj) +{ + auto self = static_cast(obj); + + vkDeviceWaitIdle(cg_core.vk_device_with_swapchain->device); + + for(auto i{0}; i < self->max_frames_in_flight; i++) + { + vkDestroySemaphore(cg_core.vk_device_with_swapchain->device, + self->render_finished_semaphores[i], nullptr); + vkDestroySemaphore(cg_core.vk_device_with_swapchain->device, + self->image_available_semaphores[i], nullptr); + vkDestroyFence(cg_core.vk_device_with_swapchain->device, + self->in_flight_fences[i], nullptr); + } +} + +const CommandChain loader{ + {&load_swapchain, &unload_swapchain}, + {&load_image_view, &unload_image_view}, + {&load_frame_sync, &unload_frame_sync} +}; + +} + +namespace BluCat +{ + +Swapchain::Swapchain(): + current_frame{0} +{ + loader.execute(this); +} + +Swapchain::~Swapchain() +{ + loader.revert(this); +} + +} diff --git a/src/blucat/swapchain.hpp b/src/blucat/swapchain.hpp new file mode 100644 index 0000000..979fe08 --- /dev/null +++ b/src/blucat/swapchain.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_SWAPCHAIN_H +#define CANDY_GEAR_BLUCAT_SWAPCHAIN_H 1 + +#include "core.hpp" +#include "../command.hpp" + +namespace BluCat +{ + +struct Swapchain +{ + VkSwapchainKHR swapchain; + VkFormat image_format; + + uint32_t images_count; + VkImage *images; + VkImageView *image_views; + + static const int max_frames_in_flight{2}; + size_t current_frame; + std::vector image_available_semaphores; + std::vector render_finished_semaphores; + std::vector in_flight_fences; + + Swapchain(); + ~Swapchain(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_SWAPCHAIN_H */ diff --git a/src/blucat/texture.cpp b/src/blucat/texture.cpp new file mode 100644 index 0000000..1213528 --- /dev/null +++ b/src/blucat/texture.cpp @@ -0,0 +1,559 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "texture.hpp" + +#include "../command.hpp" +#include "../core.hpp" +#include "image.hpp" +#include "qoi.hpp" +#include "source_buffer.hpp" + +namespace +{ + +inline void +create_vulkan_image( + VkImage *image, VkDeviceMemory *device_memory, int width, int height, + uint32_t mip_levels) +{ + VkExtent3D vk_extent3d{}; + vk_extent3d.width = width; + vk_extent3d.height = height; + vk_extent3d.depth = 1; + + BluCat::Image::create( + cg_core.vk_device_with_swapchain, + image, + device_memory, + VK_FORMAT_R8G8B8A8_UNORM, + vk_extent3d, + mip_levels, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); +} + +struct ImageBuilder +{ + BluCat::Texture *texture; +}; + +struct ImageTextureBuilder: public ImageBuilder +{ + std::string texture_path; + + ImageTextureBuilder(BluCat::Texture *t, std::string tp); + ImageTextureBuilder(BluCat::Texture *t, const char* tp); +}; + +ImageTextureBuilder::ImageTextureBuilder(BluCat::Texture *t, std::string tp): + texture_path{tp} +{ + this->texture = t; +} + +ImageTextureBuilder::ImageTextureBuilder(BluCat::Texture *t, const char* tp): + ImageTextureBuilder{t, std::string(tp)} +{ +} + +void +load_image(void *obj) +{ + auto self = static_cast(obj); + + const int num_channels = 4; // all images are converted to RGBA + BluCat::QOI::Image qoi_image(self->texture_path.c_str(), num_channels); + uint8_t *pixels; + + { // Load file image from file. + self->texture->width = qoi_image.header.width; + self->texture->height = qoi_image.header.height; + self->texture->mip_levels = 1; + + pixels = qoi_image.pixels; + } + + // Load file image into a vulkan buffer. + size_t image_size{static_cast( + qoi_image.header.width * qoi_image.header.height * num_channels)}; + BluCat::SourceBuffer source_image_buffer{ + cg_core.vk_device_with_swapchain, pixels, image_size}; + + { // Create vulkan image. + try + { + create_vulkan_image( + &self->texture->image, + &self->texture->device_memory, + self->texture->width, + self->texture->height, + self->texture->mip_levels); + } + catch(BluCat::Image::Error error) + { + throw CommandError{error.what()}; + } + } + + // Copy image from vulkan buffer into vulkan image. + { + auto queue_family = self->texture->queue_family; + auto queue{queue_family->get_queue()}; + BluCat::CommandPool command_pool{queue_family, 1}; + VkCommandBuffer vk_command_buffer{command_pool.command_buffers[0]}; + + queue.submit_one_time_command(vk_command_buffer, [&](){ + BluCat::Image::move_image_state( + vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkBufferImageCopy image_copy{}; + image_copy.bufferOffset = 0; + image_copy.bufferRowLength = 0; + image_copy.bufferImageHeight = 0; + image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_copy.imageSubresource.mipLevel = 0; + image_copy.imageSubresource.baseArrayLayer = 0; + image_copy.imageSubresource.layerCount = 1; + image_copy.imageOffset = {0, 0, 0}; + image_copy.imageExtent = { + self->texture->width, self->texture->height, 1}; + + vkCmdCopyBufferToImage( + vk_command_buffer, source_image_buffer.buffer, self->texture->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); + + BluCat::Image::move_image_state( + vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + }); + } +} + +void +unload_image(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyImage( + cg_core.vk_device_with_swapchain->device, self->texture->image, nullptr); + vkFreeMemory( + cg_core.vk_device_with_swapchain->device, self->texture->device_memory, + nullptr); +} + +void +load_sampler(void *obj) +{ + auto self = static_cast(obj); + + VkSamplerCreateInfo sampler_info{}; + sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + sampler_info.pNext = nullptr; + sampler_info.flags = 0; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.mipLodBias = 0.0f; + sampler_info.anisotropyEnable = VK_TRUE; + sampler_info.maxAnisotropy = 16; + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_NEVER; + sampler_info.minLod = 0.0f; + sampler_info.maxLod = 0.0f; + sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + sampler_info.unnormalizedCoordinates = VK_FALSE; + + if(vkCreateSampler( + cg_core.vk_device_with_swapchain->device, &sampler_info, nullptr, + &self->texture->sampler) != VK_SUCCESS) + throw CommandError{"Failed to create texture sampler."}; +} + +void +unload_sampler(void *obj) +{ + auto self = static_cast(obj); + + vkDestroySampler( + cg_core.vk_device_with_swapchain->device, self->texture->sampler, nullptr); +} + +void +load_view(void *obj) +{ + auto self = static_cast(obj); + + try + { + BluCat::Image::create_view( + cg_core.vk_device_with_swapchain, &self->texture->view, + self->texture->image, + VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + } + catch(BluCat::Image::Error error) + { + throw CommandError{error.what()}; + } +} + +void +unload_view(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyImageView( + cg_core.vk_device_with_swapchain->device, self->texture->view, nullptr); +} + +const CommandChain image_loader{ + {&load_image, &unload_image}, + {&load_sampler, &unload_sampler}, + {&load_view, &unload_view} +}; + +struct CharacterToDraw +{ + int pos_x; + std::shared_ptr character; + + CharacterToDraw(int x, std::shared_ptr character): + pos_x{x}, + character{character} + {}; +}; + +struct TextTextureBuilder: public ImageBuilder +{ + BluCat::Font *font; + const char* str; + uint32_t max_bearing_y; + std::vector chars_to_draw; + + TextTextureBuilder(BluCat::Texture *texture, BluCat::Font *font, const char* str): + font{font}, + str{str} + { + this->texture = texture; + } +}; + +void +load_text_proportions(void *obj) +{ + auto self = static_cast(obj); + + uint32_t texture_width{0}, texture_descender{0}; + auto unicode_text{BluCat::Character::str_to_unicode(self->str)}; + + auto first_image{self->font->character(unicode_text[0])}; + if(first_image->bearing_x < 0) texture_width = - first_image->bearing_x; + + self->max_bearing_y = 0; + self->chars_to_draw.reserve(unicode_text.size()); + + // FIXME: I need to test several different fonts to find all bugs in this + // code. + std::shared_ptr char_image{}; + { // Calculate image size + int max_height; + for(auto char_code : unicode_text) + { + char_image = self->font->character(char_code); + uint32_t descender{char_image->height - char_image->bearing_y}; + uint32_t pos_x{texture_width + char_image->bearing_x}; + + if(char_image->image != VK_NULL_HANDLE) + self->chars_to_draw.emplace_back(pos_x, char_image); + + if(char_image->bearing_y > self->max_bearing_y) + self->max_bearing_y = char_image->bearing_y; + if(descender > texture_descender) texture_descender = descender; + + texture_width += char_image->advance; + } + } + + { // Restore image width if last character have a negative bearing. + int bearing_x_pluss_width = char_image->bearing_x + char_image->width; + if(bearing_x_pluss_width > char_image->advance) + texture_width += bearing_x_pluss_width - char_image->advance; + } + + self->texture->width = texture_width; + self->texture->height = self->max_bearing_y + texture_descender; + self->texture->mip_levels = 1; +} + +void +load_text_image(void *obj) +{ + auto self = static_cast(obj); + + const int NumChannels = 4; + + size_t image_size{static_cast( + self->texture->width * self->texture->height * NumChannels)}; + std::vector pixels(image_size); + for(auto x{0}; x < self->texture->width; x++) + { + for(auto y{0}; y < self->texture->height; y++) + { + auto image_coord = y * self->font->face->glyph->bitmap.width + + x * NumChannels; + pixels[image_coord] = 0; // Red + pixels[image_coord + 1] = 0; // Green + pixels[image_coord + 2] = 0; // Blue + pixels[image_coord + 3] = 0; // Alpha + } + } + BluCat::SourceBuffer source_image_buffer{ + cg_core.vk_device_with_swapchain, pixels.data(), image_size}; + + { // Create vulkan image. + try + { + create_vulkan_image( + &self->texture->image, + &self->texture->device_memory, + self->texture->width, + self->texture->height, + self->texture->mip_levels); + } + catch(BluCat::Image::Error error) + { + throw CommandError{error.what()}; + } + } + + { // Render text + auto queue_family{ + cg_core.vk_device_with_swapchain->get_queue_family_with_presentation()}; + auto queue{queue_family->get_queue()}; + BluCat::CommandPool command_pool{queue_family, 1}; + VkCommandBuffer vk_command_buffer{command_pool.command_buffers[0]}; + + queue.submit_one_time_command(vk_command_buffer, [&](){ + BluCat::Image::move_image_state( + vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkBufferImageCopy image_copy{}; + image_copy.bufferOffset = 0; + image_copy.bufferRowLength = 0; + image_copy.bufferImageHeight = 0; + image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_copy.imageSubresource.mipLevel = 0; + image_copy.imageSubresource.baseArrayLayer = 0; + image_copy.imageSubresource.layerCount = 1; + image_copy.imageOffset = {0, 0, 0}; + image_copy.imageExtent = {self->texture->width, self->texture->height, 1}; + + vkCmdCopyBufferToImage( + vk_command_buffer, source_image_buffer.buffer, self->texture->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); + + for(auto &to_draw: self->chars_to_draw) + { + VkImageSubresourceLayers + source_subresources{}, destination_subresources{}; + source_subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + source_subresources.mipLevel = 0; + source_subresources.baseArrayLayer = 0; + source_subresources.layerCount = 1; + + destination_subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + destination_subresources.mipLevel = 0; + destination_subresources.baseArrayLayer = 0; + destination_subresources.layerCount = 1; + + VkImageCopy image_copy{}; + image_copy.srcSubresource = source_subresources; + image_copy.srcOffset = {0, 0, 0}; + image_copy.dstSubresource = destination_subresources; + image_copy.dstOffset = { + to_draw.pos_x, + (int)(self->max_bearing_y - to_draw.character->bearing_y), + 0}; + image_copy.extent = { + to_draw.character->width, to_draw.character->height, 1}; + + vkCmdCopyImage( + vk_command_buffer, + to_draw.character->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + self->texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &image_copy); + } + + BluCat::Image::move_image_state( + vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + }); + } +} + +const CommandChain text_loader{ + {&load_text_proportions, nullptr}, + {&load_text_image, &unload_image}, + {&load_sampler, &unload_sampler}, + {&load_view, &unload_view} +}; + +void +load_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + std::array descriptor_pool_sizes{}; + descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor_pool_sizes[0].descriptorCount = + cg_core.vk_swapchain->images_count; + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = cg_core.vk_swapchain->images_count; + pool_info.poolSizeCount = descriptor_pool_sizes.size(); + pool_info.pPoolSizes = descriptor_pool_sizes.data(); + + if(vkCreateDescriptorPool( + self->queue_family->device->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorPool( + self->queue_family->device->device, self->descriptor_pool, nullptr); +} + +void +load_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->texture); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets.resize(layouts.size()); + if(vkAllocateDescriptorSets( + self->queue_family->device->device, &alloc_info, + self->descriptor_sets.data()) != VK_SUCCESS) + CommandError{"Failed to create Vulkan descriptor set."}; +} + +void +load_data_to_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + VkDescriptorImageInfo image_info{}; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info.imageView = self->view; + image_info.sampler = self->sampler; + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_descriptors[0].pBufferInfo = nullptr; + write_descriptors[0].pImageInfo = &image_info; + write_descriptors[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +const CommandChain descriptor_loader{ + {&load_descriptor_set_pool, &unload_descriptor_set_pool}, + {&load_descriptor_sets, nullptr}, + {&load_data_to_descriptor_sets, nullptr} +}; + +} + +namespace BluCat +{ + +Texture::Texture(Font *font, const char* str) +{ + this->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_presentation(); + + TextTextureBuilder text_builder(this, font, str); + text_loader.execute(&text_builder); + descriptor_loader.execute(this); +} + +Texture::Texture(std::string texture_path) +{ + this->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_presentation(); + + ImageTextureBuilder texture_builder(this, texture_path); + image_loader.execute(&texture_builder); + descriptor_loader.execute(this); +} + +Texture::Texture(const char* texture_path): + Texture{std::string(texture_path)} +{ +} + +Texture::~Texture() +{ + ImageTextureBuilder texture_builder(this, ""); + image_loader.revert(&texture_builder); + descriptor_loader.revert(this); +} + +} diff --git a/src/blucat/texture.hpp b/src/blucat/texture.hpp new file mode 100644 index 0000000..bee61e6 --- /dev/null +++ b/src/blucat/texture.hpp @@ -0,0 +1,51 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_TEXTURE_H +#define CANDY_GEAR_BLUCAT_TEXTURE_H 1 + +#include + +#include "core.hpp" +#include "font.hpp" +#include "queue_family.hpp" + +namespace BluCat +{ + +struct Texture +{ + QueueFamily *queue_family; + + VkImage image; + VkSampler sampler; + VkImageView view; + VkDeviceMemory device_memory; + uint32_t width, height; + uint32_t mip_levels; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets; + + Texture(Font *font, const char *str); + Texture(std::string texture_path); + Texture(const char* texture_path); + ~Texture(); +}; + +} + +#endif /* CANDY_GEAR_TEXTURE_H */ diff --git a/src/blucat/uniform_buffer.cpp b/src/blucat/uniform_buffer.cpp new file mode 100644 index 0000000..4b6194a --- /dev/null +++ b/src/blucat/uniform_buffer.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "uniform_buffer.hpp" + +#include +#include + +namespace BluCat +{ + +UniformBuffer::UniformBuffer(Device *device, VkDeviceSize data_size) +{ + this->device = device; + this->device_size = data_size; + this->buffer_usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + this->memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + try + { + BaseBuffer::loader.execute(static_cast(this)); + } + catch(const CommandError &command_error) + { + std::string error{"Could not initialize Vulkan uniform buffer → "}; + error += command_error.what(); + throw CommandError{error}; + } +} + +UniformBuffer::~UniformBuffer() +{ + BaseBuffer::loader.revert(static_cast(this)); +} + +UniformBuffer::UniformBuffer(UniformBuffer &&that) +{ + this->device = that.device; + this->buffer = that.buffer; + this->device_memory = that.device_memory; + this->device_size = that.device_size; + this->buffer_usage = that.buffer_usage; + this->memory_properties = that.memory_properties; + + that.buffer = VK_NULL_HANDLE; + that.device_memory = VK_NULL_HANDLE; +} + +UniformBuffer& +UniformBuffer::operator=(UniformBuffer &&that) +{ + this->device = that.device; + this->buffer = that.buffer; + this->device_memory = that.device_memory; + this->device_size = that.device_size; + this->buffer_usage = that.buffer_usage; + this->memory_properties = that.memory_properties; + + that.buffer = VK_NULL_HANDLE; + that.device_memory = VK_NULL_HANDLE; + + return *this; +} + +void +UniformBuffer::copy_data(void *ubo) +{ + void *data; + vkMapMemory(this->device->device, this->device_memory, 0, + this->device_size, 0, &data); + memcpy(data, ubo, this->device_size); + vkUnmapMemory(this->device->device, this->device_memory); +} + +} diff --git a/src/blucat/uniform_buffer.hpp b/src/blucat/uniform_buffer.hpp new file mode 100644 index 0000000..2131ee1 --- /dev/null +++ b/src/blucat/uniform_buffer.hpp @@ -0,0 +1,49 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_UNIFORM_BUFFER_H +#define CANDY_GEAR_BLUCAT_UNIFORM_BUFFER_H 1 + +#include + +#include "core.hpp" + +#include "base_buffer.hpp" + +namespace BluCat +{ + +// FIXME: this class need to delete or create custom copy constructors! +class UniformBuffer: public BaseBuffer +{ + UniformBuffer(const UniformBuffer &t) = delete; + UniformBuffer& + operator=(const UniformBuffer &t) = delete; + +public: + UniformBuffer(Device *device, VkDeviceSize data_size); + ~UniformBuffer(); + + UniformBuffer(UniformBuffer &&that); + UniformBuffer& + operator=(UniformBuffer &&that); + + void copy_data(void* ubo); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_UNIFORM_BUFFER_H */ diff --git a/src/blucat/uniform_data_object.hpp b/src/blucat/uniform_data_object.hpp new file mode 100644 index 0000000..d2292b1 --- /dev/null +++ b/src/blucat/uniform_data_object.hpp @@ -0,0 +1,80 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_UNIFORM_DATA_OBJECT_H +#define CANDY_GEAR_BLUCAT_UNIFORM_DATA_OBJECT_H 1 + +#include "core.hpp" +#include "skeletal_mesh_vertex.hpp" + +namespace BluCat +{ + +// UDO = "uniform data object" + +struct UDOView2D +{ + glm::mat4 proj; +}; + +struct UDOView3D +{ + glm::mat4 view; + glm::mat4 proj; +}; + +struct UDOWorld3D_Vert +{ + glm::vec4 ambient_light_color; +}; + +struct UDOWorld3D_Frag +{ + glm::vec3 directional_light_direction; + glm::vec4 directional_light_color; +}; + +struct UDOStaticModel +{ + glm::mat4 base_matrix; +}; + +struct UDOSkeletalModel +{ + glm::mat4 base_matrix; + glm::mat4 bone_matrices[SKELETAL_MESH_MAX_NUM_OF_BONES]; +}; + +struct UDOVector4D +{ + glm::vec4 vector; +}; + +struct UDOVector3D +{ + glm::vec3 vectors; +}; + +struct UDOSprite3D +{ + glm::vec3 position; + uint32_t padding; + glm::vec2 size; +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_UNIFORM_DATA_OBJECT_H */ diff --git a/src/blucat/view_2d.cpp b/src/blucat/view_2d.cpp new file mode 100644 index 0000000..f27b4c4 --- /dev/null +++ b/src/blucat/view_2d.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "view_2d.hpp" + +#include + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_2d_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->ub_2d.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_2d.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOView2D)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_2d_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + self->ub_2d.clear(); +} + +void +load_descriptor_sets_2d(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->view); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets_2d.resize(layouts.size()); + if(vkAllocateDescriptorSets( + cg_core.vk_device_with_swapchain->device, &alloc_info, + self->descriptor_sets_2d.data()) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan descriptor sets for view."}; +} + +void +load_resources_to_descriptor_sets_2d(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->ub_2d.size(); i++) + { + VkDescriptorBufferInfo view_2d_info{}; + view_2d_info.buffer = self->ub_2d[i].buffer; + view_2d_info.offset = 0; + view_2d_info.range = sizeof(BluCat::UDOView2D); + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets_2d[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &view_2d_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + + BluCat::UDOView2D ubo_view_2d; + ubo_view_2d.proj = glm::ortho( + 0.0f, self->projection_width, + 0.0f, self->projection_height, + 0.0f, 100.0f); + self->ub_2d[i].copy_data(&ubo_view_2d); + } +} + +} + +namespace BluCat +{ + +const CommandChain View2D::loader{ + {&load_2d_uniform_buffer, &unload_2d_uniform_buffer} +}; + +const CommandChain View2D::descriptor_sets_loader{ + {&load_descriptor_sets_2d, nullptr}, + {&load_resources_to_descriptor_sets_2d, nullptr} +}; + +View2D::View2D( + glm::vec4 region, float projection_width, float projection_height): + projection_width{projection_width}, + projection_height{projection_height}, + region{region}, + descriptor_pool{VK_NULL_HANDLE}, + rectangles_to_draw{cg_core.vk_swapchain->images_count}, + sprites_to_draw{cg_core.vk_swapchain->images_count} +{ + loader.execute(this); +} + +View2D::~View2D() +{ + loader.revert(this); +} + +void +View2D::load_descriptor_sets(VkDescriptorPool descriptor_pool) +{ + if(this->descriptor_pool != VK_NULL_HANDLE) return; + + this->descriptor_pool = descriptor_pool; + descriptor_sets_loader.execute(this); +} + +void +View2D::unload_descriptor_sets() +{ + if(this->descriptor_pool == VK_NULL_HANDLE) return; + + this->descriptor_pool = VK_NULL_HANDLE; + descriptor_sets_loader.revert(this); +} + +} diff --git a/src/blucat/view_2d.hpp b/src/blucat/view_2d.hpp new file mode 100644 index 0000000..b369334 --- /dev/null +++ b/src/blucat/view_2d.hpp @@ -0,0 +1,60 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_VIEW_2D_H +#define CANDY_GEAR_BLUCAT_VIEW_2D_H 1 + +#include +#include +#include + +#include "core.hpp" +#include "sprite_to_draw.hpp" +#include "rectangle.hpp" + +namespace BluCat +{ + +struct View2D +{ + glm::vec4 region; + float projection_width, projection_height; + + // FIXME: if these vectors get resized, they can cause a segmentation fault! + std::vector ub_2d; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets_2d; + + std::vector> rectangles_to_draw; + std::vector> sprites_to_draw; + + View2D(glm::vec4 region, float projection_width, float projection_height); + virtual ~View2D(); + + void + virtual load_descriptor_sets(VkDescriptorPool descriptor_pool); + + void + virtual unload_descriptor_sets(); + +protected: + static const CommandChain loader, descriptor_sets_loader; +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_VIEW_2D_H */ diff --git a/src/blucat/view_3d.cpp b/src/blucat/view_3d.cpp new file mode 100644 index 0000000..4b7b959 --- /dev/null +++ b/src/blucat/view_3d.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "view_3d.hpp" + +#include + +#include "../core.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_3d_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + try + { + self->ub_3d.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_3d.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(BluCat::UDOView3D)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_3d_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + self->ub_3d.clear(); +} + +void +load_descriptor_sets_3d(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_descriptor_set_layout->view); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets_3d.resize(layouts.size()); + if(vkAllocateDescriptorSets( + cg_core.vk_device_with_swapchain->device, &alloc_info, + self->descriptor_sets_3d.data()) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan descriptor sets for view."}; +} + +void +load_resources_to_descriptor_sets_3d(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->ub_3d.size(); i++) + { + VkDescriptorBufferInfo view_3d_info{}; + view_3d_info.buffer = self->ub_3d[i].buffer; + view_3d_info.offset = 0; + view_3d_info.range = sizeof(BluCat::UDOView3D); + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets_3d[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &view_3d_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +const CommandChain loader{ + {&load_3d_uniform_buffer, &unload_3d_uniform_buffer} +}; + +const CommandChain descriptor_sets_loader{ + {&load_descriptor_sets_3d, nullptr}, + {&load_resources_to_descriptor_sets_3d, nullptr} +}; + +} + +namespace BluCat +{ + +View3D::View3D( + glm::vec4 region, float projection_width, float projection_height): + View2D{region, projection_width, projection_height}, + field_of_view{45.0f}, + camera_position{std::make_shared(0.0f, 0.0f, 0.0f)}, + camera_orientation{std::make_shared(0.0f, 0.0f, 0.0f, 0.0f)} +{ + ::loader.execute(this); +} + +View3D::~View3D() +{ + ::loader.revert(this); +} + +void +View3D::load_descriptor_sets(VkDescriptorPool descriptor_pool) +{ + if(this->descriptor_pool != VK_NULL_HANDLE) return; + + auto parent = dynamic_cast(this); + this->descriptor_pool = descriptor_pool; + View2D::descriptor_sets_loader.execute(parent); + ::descriptor_sets_loader.execute(this); +} + +void +View3D::unload_descriptor_sets() +{ + if(this->descriptor_pool == VK_NULL_HANDLE) return; + + auto parent = dynamic_cast(this); + this->descriptor_pool = VK_NULL_HANDLE; + ::descriptor_sets_loader.revert(this); + View2D::descriptor_sets_loader.revert(parent); +} + +} diff --git a/src/blucat/view_3d.hpp b/src/blucat/view_3d.hpp new file mode 100644 index 0000000..05cae6b --- /dev/null +++ b/src/blucat/view_3d.hpp @@ -0,0 +1,48 @@ +/* + * Copyright 2022-2024 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_BLUCAT_VIEW_3D_H +#define CANDY_GEAR_BLUCAT_VIEW_3D_H 1 + +#include "view_2d.hpp" + +namespace BluCat +{ + +struct View3D: public View2D +{ + float field_of_view; + // FIXME: if this vector get resized, it can cause a segmentation fault! + std::vector ub_3d; + + std::vector descriptor_sets_3d; + + std::shared_ptr camera_position; + std::shared_ptr camera_orientation; + + View3D(glm::vec4 region, float projection_width, float projection_height); + ~View3D(); + + void + load_descriptor_sets(VkDescriptorPool descriptor_pool); + + void + unload_descriptor_sets(); +}; + +} + +#endif /* CANDY_GEAR_BLUCAT_VIEW_3D_H */ diff --git a/src/candy_gear.cpp b/src/candy_gear.cpp index 426db4b..78bb716 100644 --- a/src/candy_gear.cpp +++ b/src/candy_gear.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,8 +42,8 @@ cg_mCandyGear_set_views(mrb_state *mrb, mrb_value self) mrb_value *array; mrb_int array_len; - std::vector> views_2d; - std::vector> views_3d; + std::vector> views_2d; + std::vector> views_3d; cg_m = mrb_module_get(mrb, "CandyGear"); cg_cView2D = mrb_class_get_under(mrb, cg_m, "View2D"); @@ -54,12 +54,12 @@ cg_mCandyGear_set_views(mrb_state *mrb, mrb_value self) { if(mrb_obj_is_kind_of(mrb, array[i], cg_cView2D)) { - auto v = (std::shared_ptr*)DATA_PTR(array[i]); + auto v = (std::shared_ptr*)DATA_PTR(array[i]); views_2d.push_back(*v); } else if(mrb_obj_is_kind_of(mrb, array[i], cg_cView3D)) { - auto v = (std::shared_ptr*)DATA_PTR(array[i]); + auto v = (std::shared_ptr*)DATA_PTR(array[i]); views_3d.push_back(*v); } } @@ -68,7 +68,7 @@ cg_mCandyGear_set_views(mrb_state *mrb, mrb_value self) if(views_2d.size() > 0 || views_3d.size() > 0) { delete cg_core.vk_renderer; - cg_core.vk_renderer = new VK::Renderer({views_2d, views_3d}); + cg_core.vk_renderer = new BluCat::Renderer({views_2d, views_3d}); } return self; diff --git a/src/core.cpp b/src/core.cpp index 1aeb111..f524e36 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -258,7 +258,7 @@ unload_font_library(void *obj) } void -load_vk_instance(void *obj) +load_blucat_instance(void *obj) { std::vector vk_extensions; std::vector vk_required_layers_names; @@ -397,7 +397,7 @@ load_vk_instance(void *obj) } void -unload_vk_instance(void *obj) +unload_blucat_instance(void *obj) { vkDestroyInstance(cg_core.vk_instance, nullptr); } @@ -422,14 +422,14 @@ unload_window_surface(void *obj) #ifdef DEBUG void -load_vk_debug_callback(void *obj) +load_blucat_debug_callback(void *obj) { PFN_vkCreateDebugUtilsMessengerEXT debug_messenger; // A Vulkan instance extension named VK_EXT_debug_utils and a Vulkan instance // layer named VK_LAYER_LUNARG_standard_validation are required to enable // this callback. These instance extension and instance layer are loaded at - // Instance::load_vk_instance. + // Instance::load_blucat_instance. VkDebugUtilsMessengerCreateInfoEXT create_info; create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; create_info.pNext = nullptr; @@ -455,7 +455,7 @@ load_vk_debug_callback(void *obj) } void -unload_vk_debug_callback(void *obj) +unload_blucat_debug_callback(void *obj) { PFN_vkDestroyDebugUtilsMessengerEXT debug_messenger; @@ -468,7 +468,7 @@ unload_vk_debug_callback(void *obj) #endif void -load_vk_devices(void *obj) +load_blucat_devices(void *obj) { uint32_t devices_count; std::vector vk_physical_devices; @@ -502,15 +502,15 @@ load_vk_devices(void *obj) } void -unload_vk_devices(void *obj) +unload_blucat_devices(void *obj) { cg_core.vk_devices.clear(); } static void -load_vk_swapchain(void *obj) +load_blucat_swapchain(void *obj) { - try { cg_core.vk_swapchain = new VK::Swapchain(); } + try { cg_core.vk_swapchain = new BluCat::Swapchain(); } catch(const CommandError &error) { std::string error_message{"Failed to create swapchain → "}; @@ -520,17 +520,17 @@ load_vk_swapchain(void *obj) } void -unload_vk_swapchain(void *obj) +unload_blucat_swapchain(void *obj) { delete cg_core.vk_swapchain; } void -load_vk_framebuffer(void *obj) +load_blucat_framebuffer(void *obj) { try { - cg_core.vk_framebuffer = new VK::Framebuffer(); + cg_core.vk_framebuffer = new BluCat::Framebuffer(); } catch(const CommandError &e) { @@ -539,17 +539,17 @@ load_vk_framebuffer(void *obj) } void -unload_vk_framebuffer(void *obj) +unload_blucat_framebuffer(void *obj) { delete cg_core.vk_framebuffer; } void -load_vk_render_pass(void *obj) +load_blucat_render_pass(void *obj) { try { - cg_core.vk_render_pass = new VK::RenderPass(); + cg_core.vk_render_pass = new BluCat::RenderPass(); } catch(const CommandError &e) { @@ -558,17 +558,17 @@ load_vk_render_pass(void *obj) } void -unload_vk_render_pass(void *obj) +unload_blucat_render_pass(void *obj) { delete cg_core.vk_render_pass; } void -load_vk_descriptor_set_layout(void *obj) +load_blucat_descriptor_set_layout(void *obj) { try { - cg_core.vk_descriptor_set_layout = new VK::DescriptorSetLayout(); + cg_core.vk_descriptor_set_layout = new BluCat::DescriptorSetLayout(); } catch(const CommandError &e) { @@ -577,18 +577,18 @@ load_vk_descriptor_set_layout(void *obj) } void -unload_vk_descriptor_set_layout(void *obj) +unload_blucat_descriptor_set_layout(void *obj) { delete cg_core.vk_descriptor_set_layout; } void -load_vk_graphics_pipeline_3d_layout(void *obj) +load_blucat_graphics_pipeline_3d_layout(void *obj) { try { cg_core.vk_graphics_pipeline_3d_layout = - new VK::GraphicsPipeline3DLayout(); + new BluCat::GraphicsPipeline3DLayout(); } catch(const CommandError &e) { @@ -597,18 +597,18 @@ load_vk_graphics_pipeline_3d_layout(void *obj) } void -unload_vk_graphics_pipeline_3d_layout(void *obj) +unload_blucat_graphics_pipeline_3d_layout(void *obj) { delete cg_core.vk_graphics_pipeline_3d_layout; } void -load_vk_graphics_pipeline_2d_solid_layout(void *obj) +load_blucat_graphics_pipeline_2d_solid_layout(void *obj) { try { cg_core.vk_graphics_pipeline_2d_solid_layout = - new VK::GraphicsPipeline2DSolidLayout(); + new BluCat::GraphicsPipeline2DSolidLayout(); } catch(const CommandError &e) { @@ -617,18 +617,18 @@ load_vk_graphics_pipeline_2d_solid_layout(void *obj) } void -unload_vk_graphics_pipeline_2d_solid_layout(void *obj) +unload_blucat_graphics_pipeline_2d_solid_layout(void *obj) { delete cg_core.vk_graphics_pipeline_2d_solid_layout; } void -load_vk_graphics_pipeline_2d_wired_layout(void *obj) +load_blucat_graphics_pipeline_2d_wired_layout(void *obj) { try { cg_core.vk_graphics_pipeline_2d_wired_layout = - new VK::GraphicsPipeline2DWiredLayout(); + new BluCat::GraphicsPipeline2DWiredLayout(); } catch(const CommandError &e) { @@ -637,17 +637,17 @@ load_vk_graphics_pipeline_2d_wired_layout(void *obj) } void -unload_vk_graphics_pipeline_2d_wired_layout(void *obj) +unload_blucat_graphics_pipeline_2d_wired_layout(void *obj) { delete cg_core.vk_graphics_pipeline_2d_wired_layout; } void -load_vk_light(void *obj) +load_blucat_light(void *obj) { try { - cg_core.vk_light = new VK::Light(); + cg_core.vk_light = new BluCat::Light(); } catch(const CommandError &e) { @@ -656,18 +656,18 @@ load_vk_light(void *obj) } void -unload_vk_light(void *obj) +unload_blucat_light(void *obj) { delete cg_core.vk_light; } void -load_vk_graphics_pipeline_3d(void *obj) +load_blucat_graphics_pipeline_3d(void *obj) { try { cg_core.vk_graphics_pipeline_3d = - std::make_unique(); + std::make_unique(); } catch(const CommandError &e) { @@ -676,18 +676,18 @@ load_vk_graphics_pipeline_3d(void *obj) } void -unload_vk_graphics_pipeline_3d(void *obj) +unload_blucat_graphics_pipeline_3d(void *obj) { cg_core.vk_graphics_pipeline_3d = nullptr; } void -load_vk_graphics_pipeline_3d_skeletal(void *obj) +load_blucat_graphics_pipeline_3d_skeletal(void *obj) { try { cg_core.vk_graphics_pipeline_3d_skeletal = - std::make_unique(); + std::make_unique(); } catch(const CommandError &e) { @@ -696,18 +696,18 @@ load_vk_graphics_pipeline_3d_skeletal(void *obj) } void -unload_vk_graphics_pipeline_3d_skeletal(void *obj) +unload_blucat_graphics_pipeline_3d_skeletal(void *obj) { cg_core.vk_graphics_pipeline_3d_skeletal = nullptr; } void -load_vk_graphics_pipeline_sprite_3d(void *obj) +load_blucat_graphics_pipeline_sprite_3d(void *obj) { try { cg_core.vk_graphics_pipeline_sprite_3d = - std::make_unique(); + std::make_unique(); } catch(const CommandError &e) { @@ -716,18 +716,18 @@ load_vk_graphics_pipeline_sprite_3d(void *obj) } void -unload_vk_graphics_pipeline_sprite_3d(void *obj) +unload_blucat_graphics_pipeline_sprite_3d(void *obj) { cg_core.vk_graphics_pipeline_sprite_3d = nullptr; } void -load_vk_graphics_pipeline_2d_solid(void *obj) +load_blucat_graphics_pipeline_2d_solid(void *obj) { try { cg_core.vk_graphics_pipeline_2d_solid = - std::make_unique(); + std::make_unique(); } catch(const CommandError &e) { @@ -736,18 +736,18 @@ load_vk_graphics_pipeline_2d_solid(void *obj) } void -unload_vk_graphics_pipeline_2d_solid(void *obj) +unload_blucat_graphics_pipeline_2d_solid(void *obj) { cg_core.vk_graphics_pipeline_2d_solid = nullptr; } void -load_vk_graphics_pipeline_2d_wired(void *obj) +load_blucat_graphics_pipeline_2d_wired(void *obj) { try { cg_core.vk_graphics_pipeline_2d_wired = - std::make_unique(); + std::make_unique(); } catch(const CommandError &e) { @@ -756,13 +756,13 @@ load_vk_graphics_pipeline_2d_wired(void *obj) } void -unload_vk_graphics_pipeline_2d_wired(void *obj) +unload_blucat_graphics_pipeline_2d_wired(void *obj) { cg_core.vk_graphics_pipeline_2d_wired = nullptr; } void -load_vk_renderer(void *obj) +load_blucat_renderer(void *obj) { try { @@ -770,9 +770,9 @@ load_vk_renderer(void *obj) 0.f, 0.f, static_cast(cg_core.display_width), static_cast(cg_core.display_height)); - cg_core.vk_renderer = new VK::Renderer( + cg_core.vk_renderer = new BluCat::Renderer( {}, - {std::make_shared(region, region.z, region.w)}); + {std::make_shared(region, region.z, region.w)}); } catch(const CommandError &e) { @@ -781,7 +781,7 @@ load_vk_renderer(void *obj) } void -unload_vk_renderer(void *obj) +unload_blucat_renderer(void *obj) { delete cg_core.vk_renderer; } @@ -818,33 +818,33 @@ const CommandChain cg_sCore::loader{ {&load_sdl_open_audio, &unload_sdl_open_audio}, {&load_window, &unload_window}, {&load_font_library, &unload_font_library}, - {&load_vk_instance, &unload_vk_instance}, + {&load_blucat_instance, &unload_blucat_instance}, {&load_window_surface, &unload_window_surface}, #ifdef DEBUG - {&load_vk_debug_callback, &unload_vk_debug_callback}, + {&load_blucat_debug_callback, &unload_blucat_debug_callback}, #endif - {&load_vk_devices, &unload_vk_devices}, - {&load_vk_swapchain, &unload_vk_swapchain}, - - {&load_vk_render_pass, &unload_vk_render_pass}, - {&load_vk_framebuffer, &unload_vk_framebuffer}, - {&load_vk_descriptor_set_layout, &unload_vk_descriptor_set_layout}, - {&load_vk_graphics_pipeline_3d_layout, - &unload_vk_graphics_pipeline_3d_layout}, - {&load_vk_graphics_pipeline_2d_solid_layout, - &unload_vk_graphics_pipeline_2d_solid_layout}, - {&load_vk_graphics_pipeline_2d_wired_layout, - &unload_vk_graphics_pipeline_2d_wired_layout}, - {&load_vk_light, &unload_vk_light}, + {&load_blucat_devices, &unload_blucat_devices}, + {&load_blucat_swapchain, &unload_blucat_swapchain}, + + {&load_blucat_render_pass, &unload_blucat_render_pass}, + {&load_blucat_framebuffer, &unload_blucat_framebuffer}, + {&load_blucat_descriptor_set_layout, &unload_blucat_descriptor_set_layout}, + {&load_blucat_graphics_pipeline_3d_layout, + &unload_blucat_graphics_pipeline_3d_layout}, + {&load_blucat_graphics_pipeline_2d_solid_layout, + &unload_blucat_graphics_pipeline_2d_solid_layout}, + {&load_blucat_graphics_pipeline_2d_wired_layout, + &unload_blucat_graphics_pipeline_2d_wired_layout}, + {&load_blucat_light, &unload_blucat_light}, // TODO: finish skeletal mesh animation - {&load_vk_graphics_pipeline_3d_skeletal, - &unload_vk_graphics_pipeline_3d_skeletal}, - {&load_vk_graphics_pipeline_3d, &unload_vk_graphics_pipeline_3d}, - {&load_vk_graphics_pipeline_sprite_3d, - &unload_vk_graphics_pipeline_sprite_3d}, - {&load_vk_graphics_pipeline_2d_solid, &unload_vk_graphics_pipeline_2d_solid}, - {&load_vk_graphics_pipeline_2d_wired, &unload_vk_graphics_pipeline_2d_wired}, - - {&load_vk_renderer, &unload_vk_renderer}, + {&load_blucat_graphics_pipeline_3d_skeletal, + &unload_blucat_graphics_pipeline_3d_skeletal}, + {&load_blucat_graphics_pipeline_3d, &unload_blucat_graphics_pipeline_3d}, + {&load_blucat_graphics_pipeline_sprite_3d, + &unload_blucat_graphics_pipeline_sprite_3d}, + {&load_blucat_graphics_pipeline_2d_solid, &unload_blucat_graphics_pipeline_2d_solid}, + {&load_blucat_graphics_pipeline_2d_wired, &unload_blucat_graphics_pipeline_2d_wired}, + + {&load_blucat_renderer, &unload_blucat_renderer}, {&load_mruby_interface, nullptr} }; diff --git a/src/core.hpp b/src/core.hpp index f9e1e80..c351917 100644 --- a/src/core.hpp +++ b/src/core.hpp @@ -49,21 +49,21 @@ #include "log.hpp" #include "worker.hpp" -#include "vk/device.hpp" -#include "vk/descriptor_set_layout.hpp" -#include "vk/render_pass.hpp" -#include "vk/framebuffer.hpp" -#include "vk/graphics_pipeline_2d_solid_layout.hpp" -#include "vk/graphics_pipeline_2d_wired_layout.hpp" -#include "vk/light.hpp" -#include "vk/graphics_pipeline_2d_solid.hpp" -#include "vk/graphics_pipeline_2d_wired.hpp" -#include "vk/graphics_pipeline_3d_layout.hpp" -#include "vk/graphics_pipeline_3d.hpp" -#include "vk/graphics_pipeline_3d_skeletal.hpp" -#include "vk/graphics_pipeline_sprite_3d.hpp" -#include "vk/renderer.hpp" -#include "vk/swapchain.hpp" +#include "blucat/device.hpp" +#include "blucat/descriptor_set_layout.hpp" +#include "blucat/render_pass.hpp" +#include "blucat/framebuffer.hpp" +#include "blucat/graphics_pipeline_2d_solid_layout.hpp" +#include "blucat/graphics_pipeline_2d_wired_layout.hpp" +#include "blucat/light.hpp" +#include "blucat/graphics_pipeline_2d_solid.hpp" +#include "blucat/graphics_pipeline_2d_wired.hpp" +#include "blucat/graphics_pipeline_3d_layout.hpp" +#include "blucat/graphics_pipeline_3d.hpp" +#include "blucat/graphics_pipeline_3d_skeletal.hpp" +#include "blucat/graphics_pipeline_sprite_3d.hpp" +#include "blucat/renderer.hpp" +#include "blucat/swapchain.hpp" extern std::random_device random_seed; extern std::mt19937 random_number_generator; @@ -120,25 +120,25 @@ struct cg_sCore #endif // Vulkan devices. - std::vector vk_devices; - VK::Device *vk_device_with_swapchain; - VK::Swapchain *vk_swapchain; - - VK::Framebuffer *vk_framebuffer; - VK::RenderPass *vk_render_pass; - VK::DescriptorSetLayout *vk_descriptor_set_layout; - VK::GraphicsPipeline3DLayout *vk_graphics_pipeline_3d_layout; - VK::GraphicsPipeline2DSolidLayout *vk_graphics_pipeline_2d_solid_layout; - VK::GraphicsPipeline2DWiredLayout *vk_graphics_pipeline_2d_wired_layout; - VK::Light *vk_light; - std::unique_ptr vk_graphics_pipeline_3d; - std::unique_ptr + std::vector vk_devices; + BluCat::Device *vk_device_with_swapchain; + BluCat::Swapchain *vk_swapchain; + + BluCat::Framebuffer *vk_framebuffer; + BluCat::RenderPass *vk_render_pass; + BluCat::DescriptorSetLayout *vk_descriptor_set_layout; + BluCat::GraphicsPipeline3DLayout *vk_graphics_pipeline_3d_layout; + BluCat::GraphicsPipeline2DSolidLayout *vk_graphics_pipeline_2d_solid_layout; + BluCat::GraphicsPipeline2DWiredLayout *vk_graphics_pipeline_2d_wired_layout; + BluCat::Light *vk_light; + std::unique_ptr vk_graphics_pipeline_3d; + std::unique_ptr vk_graphics_pipeline_3d_skeletal; - std::unique_ptr vk_graphics_pipeline_sprite_3d; - std::unique_ptr vk_graphics_pipeline_2d_solid; - std::unique_ptr vk_graphics_pipeline_2d_wired; + std::unique_ptr vk_graphics_pipeline_sprite_3d; + std::unique_ptr vk_graphics_pipeline_2d_solid; + std::unique_ptr vk_graphics_pipeline_2d_wired; - VK::Renderer *vk_renderer; + BluCat::Renderer *vk_renderer; bool quit_game; }; diff --git a/src/font.cpp b/src/font.cpp index 21559e1..919d271 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ #include "font.hpp" -#include "vk/font.hpp" +#include "blucat/font.hpp" void cg_free_font(mrb_state *mrb, void *obj) { - auto ptr = static_cast(obj); + auto ptr = static_cast(obj); ptr->~Font(); mrb_free(mrb, ptr); @@ -33,18 +33,18 @@ cg_font_type = {"CG_Font", cg_free_font}; static mrb_value cg_cFont_initialize(mrb_state *mrb, mrb_value self) { - VK::Font *ptr; + BluCat::Font *ptr; const char *font_path; mrb_int font_size; mrb_get_args(mrb, "zi", &font_path, &font_size); - ptr = (VK::Font*)DATA_PTR(self); + ptr = (BluCat::Font*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (VK::Font*)mrb_malloc(mrb, sizeof(VK::Font)); + ptr = (BluCat::Font*)mrb_malloc(mrb, sizeof(BluCat::Font)); try { - new(ptr)VK::Font(font_path, font_size); + new(ptr)BluCat::Font(font_path, font_size); } catch(const std::invalid_argument &e) { diff --git a/src/skeletal_mesh.cpp b/src/skeletal_mesh.cpp index b9d4b0e..90cbeee 100644 --- a/src/skeletal_mesh.cpp +++ b/src/skeletal_mesh.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,12 @@ #include "orientation_3d.hpp" #include "vector_3d.hpp" -#include "vk/skeletal_mesh.hpp" +#include "blucat/skeletal_mesh.hpp" void cg_free_skeletal_mesh(mrb_state *mrb, void* obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -37,16 +37,16 @@ cg_cSkeletalMesh_initialize(mrb_state *mrb, mrb_value self) { const char *file_path; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "z", &file_path); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared(file_path)); + new(ptr)std::shared_ptr( + std::make_shared(file_path)); mrb_data_init(self, ptr, &cg_skeletal_mesh_type); return self; diff --git a/src/skeletal_model.cpp b/src/skeletal_model.cpp index a8dc62a..3a3596e 100644 --- a/src/skeletal_model.cpp +++ b/src/skeletal_model.cpp @@ -20,12 +20,12 @@ #include "vector_3d.hpp" #include "skeletal_mesh.hpp" #include "texture.hpp" -#include "vk/skeletal_model.hpp" +#include "blucat/skeletal_model.hpp" void cg_free_skeletal_model(mrb_state *mrb, void *obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -37,23 +37,23 @@ const struct mrb_data_type cg_skeletal_model_type = { static mrb_value cg_cSkeletalModel_initialize(mrb_state *mrb, mrb_value self) { - std::shared_ptr *skeletal_mesh; - std::shared_ptr *texture; + std::shared_ptr *skeletal_mesh; + std::shared_ptr *texture; std::shared_ptr *position; std::shared_ptr *orientation; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args( mrb, "dddd", &skeletal_mesh, &cg_skeletal_mesh_type, &texture, &cg_texture_type, &position, &cg_vector_3d_type, &orientation, &cg_orientation_3d_type); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared( + new(ptr)std::shared_ptr( + std::make_shared( *skeletal_mesh, *texture, *position, *orientation)); mrb_data_init(self, ptr, &cg_skeletal_model_type); @@ -63,7 +63,7 @@ cg_cSkeletalModel_initialize(mrb_state *mrb, mrb_value self) static mrb_value cg_cSkeletalModel_set_orientation(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); std::shared_ptr *orientation; mrb_get_args(mrb, "d", &orientation, &cg_orientation_3d_type); @@ -75,7 +75,7 @@ cg_cSkeletalModel_set_orientation(mrb_state *mrb, mrb_value self) static mrb_value cg_cSkeletalModel_set_position(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); std::shared_ptr *position; mrb_get_args(mrb, "d", &position, &cg_vector_3d_type); @@ -87,7 +87,7 @@ cg_cSkeletalModel_set_position(mrb_state *mrb, mrb_value self) static mrb_value cg_cSkeletalModel_set_animation(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_int animation_index; mrb_get_args(mrb, "i", &animation_index); @@ -99,7 +99,7 @@ cg_cSkeletalModel_set_animation(mrb_state *mrb, mrb_value self) static mrb_value cg_cSkeletalModel_draw(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); auto &instances = cg_core.vk_renderer->skeletal_models_to_draw[ cg_core.vk_swapchain->current_frame][(*ptr)->skeletal_mesh]; diff --git a/src/sprite.cpp b/src/sprite.cpp index dba9e22..65a49f7 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,12 @@ #include "texture.hpp" #include "vector_4d.hpp" #include "view_2d.hpp" -#include "vk/sprite.hpp" +#include "blucat/sprite.hpp" void cg_free_sprite(mrb_state *mrb, void* obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -37,22 +37,22 @@ cg_cSprite_initialize(mrb_state *mrb, mrb_value self) { mrb_float x, y, w, h; glm::vec4 vector_4d; - std::shared_ptr *texture; - std::shared_ptr *ptr; + std::shared_ptr *texture; + std::shared_ptr *ptr; mrb_get_args( mrb, "dffff", &texture, &cg_texture_type, &x, &y, &w, &h); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); vector_4d.x = x; vector_4d.y = y; vector_4d.z = w; vector_4d.w = h; - new(ptr)std::shared_ptr( - std::make_shared(*texture, vector_4d)); + new(ptr)std::shared_ptr( + std::make_shared(*texture, vector_4d)); mrb_data_init(self, ptr, &cg_sprite_type); return self; @@ -62,9 +62,9 @@ static mrb_value cg_cSprite_draw(mrb_state *mrb, mrb_value self) { mrb_value view_value; - VK::View2D *view_2d; + BluCat::View2D *view_2d; mrb_float x, y, w, h, z_index{0.0}; - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "offff|f", &view_value, &x, &y, &w, &h, &z_index); diff --git a/src/sprite_3d.cpp b/src/sprite_3d.cpp index 3e4e29d..d0e3319 100644 --- a/src/sprite_3d.cpp +++ b/src/sprite_3d.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ void cg_free_sprite_3d(mrb_state *mrb, void *obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -34,21 +34,21 @@ const struct mrb_data_type cg_sprite_3d_type = { static mrb_value cg_cSprite3D_initialize(mrb_state *mrb, mrb_value self) { - std::shared_ptr *sprite; + std::shared_ptr *sprite; std::shared_ptr *position; mrb_float w, h; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "ddff", &sprite, &cg_sprite_type, &position, &cg_vector_3d_type, &w, &h); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); glm::vec3 size{w, h, 0.0}; - new(ptr)std::shared_ptr( - std::make_shared(*sprite, *position, size)); + new(ptr)std::shared_ptr( + std::make_shared(*sprite, *position, size)); mrb_data_init(self, ptr, &cg_sprite_3d_type); return self; @@ -57,7 +57,7 @@ cg_cSprite3D_initialize(mrb_state *mrb, mrb_value self) static mrb_value cg_cSprite3D_draw(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); auto &sprites_3d_to_draw = cg_core.vk_renderer->sprites_3d_to_draw[ cg_core.vk_swapchain->current_frame]; diff --git a/src/static_mesh.cpp b/src/static_mesh.cpp index 17d7be3..3ae616e 100644 --- a/src/static_mesh.cpp +++ b/src/static_mesh.cpp @@ -18,12 +18,12 @@ #include "orientation_3d.hpp" #include "vector_3d.hpp" -#include "vk/static_mesh.hpp" +#include "blucat/static_mesh.hpp" void cg_free_static_mesh(mrb_state *mrb, void* obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -37,16 +37,16 @@ cg_cStaticMesh_initialize(mrb_state *mrb, mrb_value self) { const char *file_path; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "z", &file_path); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared(file_path)); + new(ptr)std::shared_ptr( + std::make_shared(file_path)); mrb_data_init(self, ptr, &cg_static_mesh_type); return self; diff --git a/src/static_model.cpp b/src/static_model.cpp index eb9e4c9..3dd0c10 100644 --- a/src/static_model.cpp +++ b/src/static_model.cpp @@ -20,12 +20,12 @@ #include "static_mesh.hpp" #include "texture.hpp" #include "vector_3d.hpp" -#include "vk/static_model.hpp" +#include "blucat/static_model.hpp" void cg_free_static_model(mrb_state *mrb, void *obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -37,23 +37,23 @@ const struct mrb_data_type cg_static_model_type = { static mrb_value cg_cStaticModel_initialize(mrb_state *mrb, mrb_value self) { - std::shared_ptr *static_mesh; - std::shared_ptr *texture; + std::shared_ptr *static_mesh; + std::shared_ptr *texture; std::shared_ptr *position; std::shared_ptr *orientation; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args( mrb, "dddd", &static_mesh, &cg_static_mesh_type, &texture, &cg_texture_type, &position, &cg_vector_3d_type, &orientation, &cg_orientation_3d_type); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared( + new(ptr)std::shared_ptr( + std::make_shared( *static_mesh, *texture, *position, *orientation)); mrb_data_init(self, ptr, &cg_static_model_type); @@ -63,7 +63,7 @@ cg_cStaticModel_initialize(mrb_state *mrb, mrb_value self) static mrb_value cg_cStaticModel_set_orientation(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); std::shared_ptr *orientation; mrb_get_args(mrb, "d", &orientation, &cg_orientation_3d_type); @@ -75,7 +75,7 @@ cg_cStaticModel_set_orientation(mrb_state *mrb, mrb_value self) static mrb_value cg_cStaticModel_set_position(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); std::shared_ptr *position; mrb_get_args(mrb, "d", &position, &cg_vector_3d_type); @@ -87,8 +87,8 @@ cg_cStaticModel_set_position(mrb_state *mrb, mrb_value self) static mrb_value cg_cStaticModel_set_texture(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); - std::shared_ptr *texture; + auto ptr = (std::shared_ptr*)DATA_PTR(self); + std::shared_ptr *texture; mrb_get_args(mrb, "d", &texture, &cg_texture_type); (*ptr)->texture = *texture; @@ -99,7 +99,7 @@ cg_cStaticModel_set_texture(mrb_state *mrb, mrb_value self) static mrb_value cg_cStaticModel_draw(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); auto &instances = cg_core.vk_renderer->static_models_to_draw[ cg_core.vk_swapchain->current_frame][(*ptr)->static_mesh]; diff --git a/src/texture.cpp b/src/texture.cpp index 24cdc95..0bfac25 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,12 @@ #include "core.hpp" #include "font.hpp" -#include "vk/texture.hpp" +#include "blucat/texture.hpp" void cg_free_texture(mrb_state *mrb, void* obj) { - auto *ptr = static_cast*>(obj); + auto *ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -48,15 +48,15 @@ cg_cTexture_from_image(mrb_state *mrb, mrb_value self) { struct mrb_value texture = texture_alloc(mrb, self); const char *file_path; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "z", &file_path); - ptr = (std::shared_ptr*)DATA_PTR(texture); + ptr = (std::shared_ptr*)DATA_PTR(texture); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared(file_path)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); + new(ptr)std::shared_ptr( + std::make_shared(file_path)); mrb_data_init(texture, ptr, &cg_texture_type); return texture; @@ -68,17 +68,17 @@ cg_cTexture_from_text(mrb_state *mrb, mrb_value self) const char *text; unsigned int width, height; struct mrb_value texture = texture_alloc(mrb, self); - VK::Font *font_ptr; - std::shared_ptr *ptr; + BluCat::Font *font_ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "dz", &font_ptr, &cg_font_type, &text); - ptr = (std::shared_ptr*)DATA_PTR(texture); + ptr = (std::shared_ptr*)DATA_PTR(texture); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared(font_ptr, text)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); + new(ptr)std::shared_ptr( + std::make_shared(font_ptr, text)); mrb_data_init(texture, ptr, &cg_texture_type); return texture; @@ -87,14 +87,14 @@ cg_cTexture_from_text(mrb_state *mrb, mrb_value self) static mrb_value cg_cTexture_width(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); return mrb_int_value(mrb, (*ptr)->width); } static mrb_value cg_cTexture_height(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); return mrb_int_value(mrb, (*ptr)->height); } diff --git a/src/vector_4d.cpp b/src/vector_4d.cpp index 7bdcbab..ba46bda 100644 --- a/src/vector_4d.cpp +++ b/src/vector_4d.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -348,7 +348,7 @@ static mrb_value cg_cVector4D_draw_rectangle(mrb_state *mrb, mrb_value self) { mrb_value view_value; - VK::View2D *view_2d; + BluCat::View2D *view_2d; std::shared_ptr *color; auto ptr = (std::shared_ptr*)DATA_PTR(self); @@ -358,7 +358,7 @@ cg_cVector4D_draw_rectangle(mrb_state *mrb, mrb_value self) glm::vec4 position( (*ptr)->x, (*ptr)->y, (*ptr)->x + (*ptr)->z, (*ptr)->y + (*ptr)->w); - VK::Rectangle rect{position, (**color)}; + BluCat::Rectangle rect{position, (**color)}; auto &rectangles = view_2d->rectangles_to_draw[ cg_core.vk_swapchain->current_frame]; rectangles.push_back(rect); diff --git a/src/view_2d.cpp b/src/view_2d.cpp index 4a973d6..09cbac1 100644 --- a/src/view_2d.cpp +++ b/src/view_2d.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,13 @@ #include "sprite.hpp" #include "vector_4d.hpp" #include "view_3d.hpp" -#include "vk/sprite.hpp" -#include "vk/view_2d.hpp" +#include "blucat/sprite.hpp" +#include "blucat/view_2d.hpp" void cg_free_view_2d(mrb_state *mrb, void* obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -38,35 +38,35 @@ cg_cView2D_initialize(mrb_state *mrb, mrb_value self) { std::shared_ptr *region; mrb_float projection_width, projection_height; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "dff", ®ion, &cg_vector_4d_type, &projection_width, &projection_height); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared( + new(ptr)std::shared_ptr( + std::make_shared( *region->get(), projection_width, projection_height)); mrb_data_init(self, ptr, &cg_view_2d_type); return self; } -VK::View2D* +BluCat::View2D* cg_cView_to_view_2d(mrb_state *mrb, mrb_value view_value) { - VK::View2D* view_2d; + BluCat::View2D* view_2d; const mrb_data_type *type = DATA_TYPE(view_value); if(type == &cg_view_2d_type) - view_2d = static_cast*>( + view_2d = static_cast*>( DATA_PTR(view_value))->get(); else if (type == &cg_view_3d_type) - view_2d = static_cast( - static_cast*>( + view_2d = static_cast( + static_cast*>( DATA_PTR(view_value))->get()); else mrb_raisef( diff --git a/src/view_2d.hpp b/src/view_2d.hpp index f2ff5b6..a18937e 100644 --- a/src/view_2d.hpp +++ b/src/view_2d.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Frederico de Oliveira Linhares + * Copyright 2022-2024 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,8 @@ extern const struct mrb_data_type cg_view_2d_type; // Receives a mrb_value that points to a View2D or a View3D and returns a // pointer to View2D. If the mrb_value points to a View3D, the view will be -// cast to a VK::View2D. -VK::View2D* +// cast to a BluCat::View2D. +BluCat::View2D* cg_cView_to_view_2d(mrb_state *mrb, mrb_value view_value); void diff --git a/src/view_3d.cpp b/src/view_3d.cpp index 7db0015..ddaa3eb 100644 --- a/src/view_3d.cpp +++ b/src/view_3d.cpp @@ -20,13 +20,13 @@ #include "orientation_3d.hpp" #include "vector_3d.hpp" #include "vector_4d.hpp" -#include "vk/sprite.hpp" -#include "vk/view_3d.hpp" +#include "blucat/sprite.hpp" +#include "blucat/view_3d.hpp" void cg_free_view_3d(mrb_state *mrb, void* obj) { - auto ptr = static_cast*>(obj); + auto ptr = static_cast*>(obj); ptr->~shared_ptr(); mrb_free(mrb, ptr); @@ -39,17 +39,17 @@ cg_cView3D_initialize(mrb_state *mrb, mrb_value self) { std::shared_ptr *region; mrb_float projection_width, projection_height; - std::shared_ptr *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "dff", ®ion, &cg_vector_4d_type, &projection_width, &projection_height); - ptr = (std::shared_ptr*)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (std::shared_ptr*)mrb_malloc( - mrb, sizeof(std::shared_ptr)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - new(ptr)std::shared_ptr( - std::make_shared( + new(ptr)std::shared_ptr( + std::make_shared( *region->get(), projection_width, projection_height)); mrb_data_init(self, ptr, &cg_view_3d_type); @@ -60,7 +60,7 @@ static mrb_value cg_cView3D_set_camera_position(mrb_state *mrb, mrb_value self) { std::shared_ptr *camera_position; - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "d", &camera_position, &cg_vector_3d_type); (*ptr)->camera_position = (*camera_position); @@ -72,7 +72,7 @@ static mrb_value cg_cView3D_set_camera_orientation(mrb_state *mrb, mrb_value self) { std::shared_ptr *camera_orientation; - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "d", &camera_orientation, &cg_orientation_3d_type); (*ptr)->camera_orientation = (*camera_orientation); @@ -83,7 +83,7 @@ cg_cView3D_set_camera_orientation(mrb_state *mrb, mrb_value self) static mrb_value cg_cView3D_get_field_of_view(mrb_state *mrb, mrb_value self) { - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); return mrb_float_value(mrb, (*ptr)->field_of_view); @@ -94,7 +94,7 @@ static mrb_value cg_cView3D_set_field_of_view(mrb_state *mrb, mrb_value self) { mrb_float fov; - auto ptr = (std::shared_ptr*)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "f", &fov); (*ptr)->field_of_view = fov; diff --git a/src/vk/animation.cpp b/src/vk/animation.cpp deleted file mode 100644 index fec038e..0000000 --- a/src/vk/animation.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "animation.hpp" - -namespace VK -{ - -Bone::Bone(glm::mat4 offset_matrix): - offset_matrix{offset_matrix} -{ -} - -} diff --git a/src/vk/animation.hpp b/src/vk/animation.hpp deleted file mode 100644 index 46dd5bc..0000000 --- a/src/vk/animation.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_ANIMATION_H -#define CANDY_GEAR_VK_ANIMATION_H 1 - -#include - -#include "core.hpp" -#include "animation/frame.hpp" - -namespace VK -{ - -struct Bone -{ - glm::mat4x4 offset_matrix; - - Bone(glm::mat4 offset_matrix); -}; - -struct BoneTransform -{ - uint32_t bone_id; - Channel positions; - Channel rotations; - Channel scales; -}; - -struct Animation -{ - std::vector bone_transforms; - float final_time; -}; - -} - -#endif /* CANDY_GEAR_VK_ANIMATION_H */ diff --git a/src/vk/animation/frame.hpp b/src/vk/animation/frame.hpp deleted file mode 100644 index 953a6a6..0000000 --- a/src/vk/animation/frame.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_FRAME_H -#define CANDY_GEAR_VK_FRAME_H 1 - -#include - -#include "../core.hpp" - -namespace VK -{ - -template -struct Frame -{ - const T value; - const float timestamp; - - Frame(T value, float timestamp): - value{value}, - timestamp{timestamp} - { - } - -}; - -template -struct Channel -{ - int current_index{0}; - std::vector> key_frames; - - inline glm::mat4 - interpolate( - float animation_time, - glm::mat4 (*single_frame)(T frame), - glm::mat4 (*multiple_frames)(T current_frame, T next_frame, float scale)) - { - if(this->key_frames.size() == 1) - return single_frame(this->key_frames[0].value); - else - { - while(animation_time > this->key_frames[current_index].timestamp) - this->current_index++; - - float scale_factor; - Frame *previous_frame; - Frame *next_frame{&(this->key_frames[this->current_index])}; - if(this->current_index == 0) - { - previous_frame = &(this->key_frames[this->key_frames.size() - 1]); - float midway_length{animation_time - 0}; - float frames_diff{next_frame->timestamp - 0}; - scale_factor = midway_length / frames_diff; - } - else - { - previous_frame = &(this->key_frames[this->current_index - 1]); - float midway_length{animation_time - previous_frame->timestamp}; - float frames_diff{next_frame->timestamp - previous_frame->timestamp}; - scale_factor = midway_length / frames_diff; - } - - return multiple_frames( - previous_frame->value, next_frame->value, scale_factor); - } - }; -}; - -} -#endif /* CANDY_GEAR_VK_FRAME_H */ diff --git a/src/vk/base_buffer.cpp b/src/vk/base_buffer.cpp deleted file mode 100644 index 0846b20..0000000 --- a/src/vk/base_buffer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "base_buffer.hpp" - -namespace VK -{ - -const CommandChain BaseBuffer::loader{ - {&BaseBuffer::load_buffer, &BaseBuffer::unload_buffer}, - {&BaseBuffer::load_memory, &BaseBuffer::unload_memory} -}; - -void -BaseBuffer::load_buffer(void *obj) -{ - auto self = static_cast(obj); - - VkBufferCreateInfo buffer_info = {}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.pNext = nullptr; - buffer_info.flags = 0; - buffer_info.size = self->device_size; - buffer_info.usage = self->buffer_usage; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - buffer_info.queueFamilyIndexCount = 0; - buffer_info.pQueueFamilyIndices = nullptr; - - if(vkCreateBuffer( - self->device->device, &buffer_info, nullptr, &self->buffer) - != VK_SUCCESS) - throw CommandError{"Failed to create vertex buffer."}; -} - -void -BaseBuffer::unload_buffer(void *obj) -{ - auto self = static_cast(obj); - - if(self->buffer != VK_NULL_HANDLE) - vkDestroyBuffer(self->device->device, self->buffer, nullptr); -} - -void -BaseBuffer::load_memory(void *obj) -{ - auto self = static_cast(obj); - - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements( - self->device->device, self->buffer, &memory_requirements); - - VkPhysicalDeviceMemoryProperties memory_properties; - vkGetPhysicalDeviceMemoryProperties( - self->device->physical_device, &memory_properties); - - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = nullptr; - alloc_info.allocationSize = memory_requirements.size; - if(!self->device->select_memory_type( - &alloc_info.memoryTypeIndex, &memory_requirements, - self->memory_properties)) - throw CommandError{"Could not allocate memory for Vulkan vertex buffer."}; - - if(vkAllocateMemory(self->device->device, &alloc_info, nullptr, - &self->device_memory) != VK_SUCCESS) - throw CommandError{"Could not allocate memory for Vulkan vertex buffer."}; - - vkBindBufferMemory( - self->device->device, self->buffer, self->device_memory, 0); -} - -void -BaseBuffer::unload_memory(void *obj) -{ - auto self = static_cast(obj); - - if(self->device_memory != VK_NULL_HANDLE) - vkFreeMemory(self->device->device, self->device_memory, nullptr); -} - -} diff --git a/src/vk/base_buffer.hpp b/src/vk/base_buffer.hpp deleted file mode 100644 index 0f3e513..0000000 --- a/src/vk/base_buffer.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_BASE_BUFFER_H -#define CANDY_GEAR_VK_BASE_BUFFER_H 1 - -#include "../command.hpp" -#include "core.hpp" -#include "device.hpp" - -namespace VK -{ - -class BaseBuffer -{ - public: - virtual ~BaseBuffer(){}; - - VkBuffer buffer; - VkDeviceMemory device_memory; - VkDeviceSize device_size; - VkBufferUsageFlags buffer_usage; - VkMemoryPropertyFlags memory_properties; - - protected: - static const CommandChain loader; - - Device *device; - - static void - load_buffer(void *obj); - static void - unload_buffer(void *obj); - - static void - load_memory(void *obj); - static void - unload_memory(void *obj); -}; - -} - -#endif /* CANDY_GEAR_VK_BASE_BUFFER_H */ diff --git a/src/vk/character.cpp b/src/vk/character.cpp deleted file mode 100644 index e5eb87f..0000000 --- a/src/vk/character.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "character.hpp" - -#include "../command.hpp" -#include "../core.hpp" -#include "font.hpp" -#include "image.hpp" -#include "source_buffer.hpp" - -namespace -{ - -struct CharacterBuilder -{ - VK::Character *character; - FT_Face face; - uint32_t character_code; - - CharacterBuilder( - VK::Character *character, FT_Face face, uint32_t character_code); -}; - -CharacterBuilder::CharacterBuilder( - VK::Character *character, FT_Face face, uint32_t character_code): - character{character}, - face{face}, - character_code{character_code} -{ -} - -// TODO: creating one image with one device memory for each character is -// ineficient -void -load_image(void *obj) -{ - auto self = static_cast(obj); - - FT_Error error; - std::vector source_image_raw; - const int num_channels = 4; // all images are converted to RGBA - auto glyph_index{FT_Get_Char_Index(self->face, self->character_code)}; - - error = FT_Load_Glyph(self->face, glyph_index, FT_LOAD_DEFAULT); - if(error) throw CommandError{"failed to load glyph"}; - - error = FT_Render_Glyph(self->face->glyph, FT_RENDER_MODE_NORMAL); - if(error) throw CommandError{"failed to render glyph"}; - - self->character->bearing_x = self->face->glyph->bitmap_left; - self->character->bearing_y = self->face->glyph->bitmap_top; - self->character->advance = (self->face->glyph->advance.x >> 6); - self->character->width = self->face->glyph->bitmap.width; - self->character->height = self->face->glyph->bitmap.rows; - self->character->mip_levels = 1; - - // Character is a white-space. - if(self->character->width <= 0) - { - self->character->image = VK_NULL_HANDLE; - self->character->device_memory = VK_NULL_HANDLE; - - return; - } - - auto image_size{static_cast( - self->face->glyph->bitmap.width * - self->face->glyph->bitmap.rows * num_channels)}; - - { // Create the data for the image buffer - source_image_raw.resize(image_size, 0); - - for(auto y{0}; y < self->face->glyph->bitmap.width; y++) - { - for(auto x{0}; x < self->face->glyph->bitmap.rows; x++) - { - auto image_coord = y * self->face->glyph->bitmap.rows * num_channels + - x * num_channels; - auto glyph_coord = y * self->face->glyph->bitmap.rows + x; - // Red - source_image_raw[image_coord] = 255; - // Green - source_image_raw[image_coord + 1] = 255; - // Blue - source_image_raw[image_coord + 2] = 255; - // Alpha - source_image_raw[image_coord + 3] = - self->face->glyph->bitmap.buffer[glyph_coord]; - } - } - } - - VK::SourceBuffer source_image_buffer{ - cg_core.vk_device_with_swapchain, source_image_raw.data(), - image_size}; - - { // Create Vulkan image. - try - { - VkExtent3D vk_extent3d; - vk_extent3d.width = self->face->glyph->bitmap.width; - vk_extent3d.height = self->face->glyph->bitmap.rows; - vk_extent3d.depth = 1; - - VK::Image::create( - cg_core.vk_device_with_swapchain, - &self->character->image, - &self->character->device_memory, - VK_FORMAT_R8G8B8A8_UNORM, - vk_extent3d, - self->character->mip_levels, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - } - catch(VK::Image::Error error) - { - throw CommandError{error.what()}; - } - } - - { // Copy image from buffer into image. - auto queue_family{cg_core.vk_device_with_swapchain-> - get_queue_family_with_presentation()}; - auto queue{queue_family->get_queue()}; - VK::CommandPool command_pool{queue_family, 1}; - VkCommandBuffer vk_command_buffer{command_pool.command_buffers[0]}; - - queue.submit_one_time_command(vk_command_buffer, [&](){ - VK::Image::move_image_state( - vk_command_buffer, self->character->image, VK_FORMAT_R8G8B8A8_UNORM, - 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkBufferImageCopy image_copy; - image_copy.bufferOffset = 0; - image_copy.bufferRowLength = 0; - image_copy.bufferImageHeight = 0; - image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_copy.imageSubresource.mipLevel = 0; - image_copy.imageSubresource.baseArrayLayer = 0; - image_copy.imageSubresource.layerCount = 1; - image_copy.imageOffset = {0, 0, 0}; - image_copy.imageExtent = { - self->character->width, self->character->height, 1}; - - vkCmdCopyBufferToImage( - vk_command_buffer, source_image_buffer.buffer, self->character->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); - - VK::Image::move_image_state( - vk_command_buffer, self->character->image, VK_FORMAT_R8G8B8A8_UNORM, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - }); - } -} - -void -unload_image(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyImage( - cg_core.vk_device_with_swapchain->device, self->character->image, nullptr); - vkFreeMemory( - cg_core.vk_device_with_swapchain->device, self->character->device_memory, - nullptr); -} - -const CommandChain loader{ - {&load_image, &unload_image} -}; - -} - -namespace VK -{ - -Character::Character(FT_Face face, uint32_t character_code) -{ - CharacterBuilder character_builder(this, face, character_code); - loader.execute(&character_builder); -} - -Character::~Character() -{ - CharacterBuilder character_builder(this, nullptr, 0); - loader.revert(&character_builder); -} - -std::vector -Character::str_to_unicode(const char* str) -{ - std::vector unicode_text; - int text_width{0}; - int text_height{0}; - - { // Reserve memory - int size{0}; - for(auto i{0}; str[i] != '\0'; i++) - if((str[i] & 0b11000000) != 0b10000000) size++; - unicode_text.reserve(size); - } - - for(auto i{0}; str[i] != '\0'; i++) - { - int num_bytes; - uint32_t codepoint{0}; - - if(str[i] >= 0 && str[i] < 127) - { // Normal ASCI character, 1-byte. - num_bytes = 1; - codepoint = str[i]; - } - else if((str[i] & 0xE0) == 0xC0) - { // 2-byte character. - num_bytes = 2; - codepoint += ((str[i] & 0b00011111) << 6); - } - else if((str[i] & 0xF0) == 0xE0) - { // 3-byte character. - num_bytes = 3; - codepoint += ((str[i] & 0b00001111) << 12); - } - else if((str[i] & 0xF8) == 0xF0) - { // 4-byte character. - num_bytes = 4; - codepoint += ((str[i] & 0b00000111) << 18); - } - else - { // FIXME: Add support to 5-byte and 6-byte characters. - } - - switch (num_bytes) - { - case 4: - i++; - codepoint += ((str[i] & 0b00111111) << 12); - case 3: - i++; - codepoint += ((str[i] & 0b00111111) << 6); - case 2: - i++; - codepoint += (str[i] & 0b00111111); - case 1: - default: - break; - } - - unicode_text.push_back(codepoint); - } - - return unicode_text; -} - -} diff --git a/src/vk/character.hpp b/src/vk/character.hpp deleted file mode 100644 index 82ada49..0000000 --- a/src/vk/character.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_CHARACTER_H -#define CANDY_GEAR_VK_CHARACTER_H 1 - -#include -#include FT_FREETYPE_H - -#include "core.hpp" - -#include - -namespace VK -{ - -struct Character -{ - VkImage image; - VkDeviceMemory device_memory; - int32_t bearing_y, bearing_x; - uint32_t width, height, advance, mip_levels; - - Character(FT_Face face, uint32_t character_code); - ~Character(); - - Character(Character const&) = delete; - Character& operator=(Character const&) = delete; - - static std::vector - str_to_unicode(const char* str); -}; - -} - -#endif /* CANDY_GEAR_VK_CHARACTER_H */ diff --git a/src/vk/command_pool.cpp b/src/vk/command_pool.cpp deleted file mode 100644 index 3af62c1..0000000 --- a/src/vk/command_pool.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "command_pool.hpp" - -namespace VK -{ - -const CommandChain CommandPool::loader{ - {&CommandPool::load_command_pool, &CommandPool::unload_command_pool}, - {&CommandPool::load_command_buffers, nullptr} -}; - -CommandPool::CommandPool(QueueFamily *queue_family, uint32_t buffers_quantity): - queue_family{queue_family} -{ - this->command_buffers.resize(buffers_quantity); - - CommandPool::loader.execute(this); -} - -CommandPool::~CommandPool() -{ - CommandPool::loader.revert(this); -} - -void -CommandPool::load_command_pool(void *obj) -{ - auto *self = static_cast(obj); - - VkCommandPoolCreateInfo command_pool_create_info; - - command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - command_pool_create_info.pNext = nullptr; - command_pool_create_info.flags = - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - command_pool_create_info.queueFamilyIndex = self->queue_family->family_index; - - if(vkCreateCommandPool( - self->queue_family->device->device, &command_pool_create_info, - nullptr, &self->command_pool) != VK_SUCCESS) - throw CommandError{"Vulkan command pool could not be created."}; -} - -void -CommandPool::unload_command_pool(void *obj) -{ - auto *self = static_cast(obj); - - vkDestroyCommandPool( - self->queue_family->device->device, self->command_pool, nullptr); -} - -void -CommandPool::load_command_buffers(void *obj) -{ - auto *self = static_cast(obj); - - VkCommandBufferAllocateInfo command_buffer_info; - command_buffer_info.sType = - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_info.pNext = nullptr; - command_buffer_info.commandPool = self->command_pool; - command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - command_buffer_info.commandBufferCount = self->command_buffers.size(); - - if(vkAllocateCommandBuffers( - self->queue_family->device->device, - &command_buffer_info, self->command_buffers.data()) != VK_SUCCESS) - throw CommandError{"Vulkan command buffers could not be allocated."}; -} - -} diff --git a/src/vk/command_pool.hpp b/src/vk/command_pool.hpp deleted file mode 100644 index 68ab7a6..0000000 --- a/src/vk/command_pool.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_COMMAND_POOL_H -#define CANDY_GEAR_VK_COMMAND_POOL_H 1 - -#include - -#include "../command.hpp" -#include "core.hpp" -#include "device.hpp" - -namespace VK -{ - -class CommandPool -{ - CommandPool(const CommandPool &t) = delete; - CommandPool& operator=(const CommandPool &t) = delete; - CommandPool(const CommandPool &&t) = delete; - CommandPool& operator=(const CommandPool &&t) = delete; - -public: - std::vector command_buffers; - - CommandPool(QueueFamily *queue_family, uint32_t buffers_quantity); - ~CommandPool(); - -private: - static const CommandChain loader; - - QueueFamily *queue_family; - VkCommandPool command_pool; - - static void - load_command_pool(void *obj); - static void - unload_command_pool(void *obj); - - static void - load_command_buffers(void *obj); -}; - -} - -#endif /* CANDY_GEAR_VK_COMMAND_POOL_H */ diff --git a/src/vk/core.hpp b/src/vk/core.hpp deleted file mode 100644 index 736b8bb..0000000 --- a/src/vk/core.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_CORE_H -#define CANDY_GEAR_VK_CORE_H 1 - -// GLM uses some definitions to control their behavior, so you should not -// include it directly. Instead, use this header. -#define GLM_ENABLE_EXPERIMENTAL -#define GLM_FORCE_RADIANS -#define GLM_FORCE_DEPTH_ZERO_TO_ONE - -#include -#include -#include -#include -#include - -#include - -#endif /* CANDY_GEAR_VK_CORE_H */ diff --git a/src/vk/descriptor_set_layout.cpp b/src/vk/descriptor_set_layout.cpp deleted file mode 100644 index 8a2f4ef..0000000 --- a/src/vk/descriptor_set_layout.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "descriptor_set_layout.hpp" - -#include - -#include "../core.hpp" - -namespace -{ - -void -load_world(void *obj) -{ - auto self = static_cast(obj); - - std::array set_layouts{}; - set_layouts[0].binding = 0; - set_layouts[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - set_layouts[0].descriptorCount = 1; - set_layouts[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - set_layouts[0].pImmutableSamplers = nullptr; - - set_layouts[1].binding = 1; - set_layouts[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - set_layouts[1].descriptorCount = 1; - set_layouts[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - set_layouts[1].pImmutableSamplers = nullptr; - - VkDescriptorSetLayoutCreateInfo layout_info{}; - layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.pNext = nullptr; - layout_info.flags = 0; - layout_info.bindingCount = set_layouts.size(); - layout_info.pBindings = set_layouts.data(); - - if(vkCreateDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, - &self->world) != VK_SUCCESS) - throw CommandError{ - "Failed to create Vulkan descriptor set layout for world view."}; -} - -void -unload_world(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, self->world, nullptr); -} - -void -load_view(void *obj) -{ - auto self = static_cast(obj); - - std::array layout_bindings{}; - - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layout_bindings[0].pImmutableSamplers = nullptr; - - VkDescriptorSetLayoutCreateInfo layout_info{}; - layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.pNext = nullptr; - layout_info.flags = 0; - layout_info.bindingCount = static_cast(layout_bindings.size()); - layout_info.pBindings = layout_bindings.data(); - - if(vkCreateDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, - &self->view) != VK_SUCCESS) - throw CommandError{ - "Failed to create Vulkan descriptor set layout for view."}; -} - -void -unload_view(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, self->view, nullptr); -} - -void -load_texture(void *obj) -{ - auto self = static_cast(obj); - - std::array layout_bindings{}; - - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - layout_bindings[0].pImmutableSamplers = nullptr; - - VkDescriptorSetLayoutCreateInfo layout_info{}; - layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.pNext = nullptr; - layout_info.flags = 0; - layout_info.bindingCount = static_cast(layout_bindings.size()); - layout_info.pBindings = layout_bindings.data(); - - if(vkCreateDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, - &self->texture) != VK_SUCCESS) - throw CommandError{ - "Failed to create Vulkan descriptor set layout for textures."}; -} - -void -unload_texture(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, self->texture, nullptr); -} - -void -load_model(void *obj) -{ - auto self = static_cast(obj); - - std::array layout_bindings; - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layout_bindings[0].pImmutableSamplers = nullptr; - - VkDescriptorSetLayoutCreateInfo layout_info{}; - layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.pNext = nullptr; - layout_info.flags = 0; - layout_info.bindingCount = static_cast(layout_bindings.size()); - layout_info.pBindings = layout_bindings.data(); - - if(vkCreateDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, - &self->model) != VK_SUCCESS) - throw CommandError{ - "Failed to create Vulkan descriptor set layout for model instance."}; -} - -void -unload_model(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, self->model, nullptr); -} - -const CommandChain loader{ - {&load_world, &unload_world}, - {&load_view, &unload_view}, - {&load_texture, &unload_texture}, - {&load_model, &unload_model}, -}; - -} - -namespace VK -{ - -DescriptorSetLayout::DescriptorSetLayout() -{ - loader.execute(this); -} - -DescriptorSetLayout::~DescriptorSetLayout() -{ - loader.revert(this); -} - -} diff --git a/src/vk/descriptor_set_layout.hpp b/src/vk/descriptor_set_layout.hpp deleted file mode 100644 index 242d2fa..0000000 --- a/src/vk/descriptor_set_layout.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_DESCRIPTOR_SET_LAYOUT_H -#define CANDY_GEAR_VK_DESCRIPTOR_SET_LAYOUT_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct DescriptorSetLayout -{ - VkDescriptorSetLayout world; - VkDescriptorSetLayout view; - VkDescriptorSetLayout texture; - VkDescriptorSetLayout model; - - DescriptorSetLayout(); - ~DescriptorSetLayout(); -}; - -} - -#endif /* CANDY_GEAR_VK_DESCRIPTOR_SET_LAYOUT_H */ diff --git a/src/vk/destination_buffer.cpp b/src/vk/destination_buffer.cpp deleted file mode 100644 index 5c55fd2..0000000 --- a/src/vk/destination_buffer.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "destination_buffer.hpp" - -#include "command_pool.hpp" - -namespace VK -{ - -DestinationBuffer::DestinationBuffer( - QueueFamily *queue_family, SourceBuffer *source_buffer, - VkBufferUsageFlags buffer_usage) -{ - this->device = queue_family->device; - this->device_size = source_buffer->device_size; - this->buffer_usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | buffer_usage; - this->memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - this->queue_family = queue_family; - this->source_buffer = source_buffer; - - BaseBuffer::loader.execute(dynamic_cast(this)); - - this->copy_data(); -} - -DestinationBuffer::DestinationBuffer( - DestinationBuffer &&that) -{ - this->buffer = that.buffer; - this->device_memory = that.device_memory; - this->device_size = that.device_size; - this->buffer_usage = that.buffer_usage; - this->memory_properties = that.memory_properties; - - that.buffer = VK_NULL_HANDLE; - that.device_memory = VK_NULL_HANDLE; -} - -DestinationBuffer& -DestinationBuffer::operator=(DestinationBuffer &&that) -{ - this->buffer = that.buffer; - this->device_memory = that.device_memory; - this->device_size = that.device_size; - this->buffer_usage = that.buffer_usage; - this->memory_properties = that.memory_properties; - - that.buffer = VK_NULL_HANDLE; - that.device_memory = VK_NULL_HANDLE; - - return *this; -} - -DestinationBuffer::~DestinationBuffer() -{ - BaseBuffer::loader.revert(dynamic_cast(this)); -} - -void -DestinationBuffer::copy_data() -{ - CommandPool command_pool(this->queue_family, 1); - Queue transfer_queue{this->queue_family->get_queue()}; - this->device_size = source_buffer->device_size; - - this->vk_command_buffer = command_pool.command_buffers[0]; - - VkCommandBufferBeginInfo begin_info = {}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - VkBufferCopy copy_region = {}; - copy_region.srcOffset = 0; - copy_region.dstOffset = 0; - copy_region.size = this->device_size; - - vkBeginCommandBuffer(this->vk_command_buffer, &begin_info); - - vkCmdCopyBuffer( - this->vk_command_buffer, this->source_buffer->buffer, this->buffer, 1, - ©_region); - - vkEndCommandBuffer(this->vk_command_buffer); - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &this->vk_command_buffer; - - vkQueueSubmit(transfer_queue.queue, 1, &submit_info, VK_NULL_HANDLE); - - vkQueueWaitIdle(transfer_queue.queue); -} - -} diff --git a/src/vk/destination_buffer.hpp b/src/vk/destination_buffer.hpp deleted file mode 100644 index 9b42af3..0000000 --- a/src/vk/destination_buffer.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_DESTINATION_BUFFER_H -#define CANDY_GEAR_VK_DESTINATION_BUFFER_H 1 - -#include "base_buffer.hpp" -#include "core.hpp" -#include "source_buffer.hpp" -#include "queue_family.hpp" - -namespace VK -{ - -struct DestinationBuffer: public BaseBuffer -{ - DestinationBuffer(const DestinationBuffer &t) = delete; - DestinationBuffer& - operator=(const DestinationBuffer &t) = delete; - - QueueFamily *queue_family; - SourceBuffer *source_buffer; - VkCommandBuffer vk_command_buffer; - - DestinationBuffer( - QueueFamily *queue_family, SourceBuffer *source_buffer, - VkBufferUsageFlags buffer_usage); - - DestinationBuffer(DestinationBuffer &&that); - DestinationBuffer& - operator=(DestinationBuffer &&that); - - ~DestinationBuffer(); - - void - copy_data(); -}; - -} - -#endif /* CANDY_GEAR_VK_DESTINATION_BUFFER_H */ diff --git a/src/vk/device.cpp b/src/vk/device.cpp deleted file mode 100644 index 78baa53..0000000 --- a/src/vk/device.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2022-2024 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "device.hpp" - -#include -#include -#include -#ifdef DEBUG -#include -#endif - -#include "../core.hpp" - -namespace -{ -VkShaderModule -create_shader_module(VkDevice vk_device, const char *filename) -{ - std::ifstream file(filename, std::ios::ate | std::ios::binary); - - if (!file.is_open()) - { - throw std::runtime_error("Failed to open shader module file."); - } - - size_t file_size = (size_t) file.tellg(); - std::vector code(file_size); - - file.seekg(0); - file.read(code.data(), file_size); - - file.close(); - - VkShaderModuleCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - create_info.codeSize = code.size(); - create_info.pCode = reinterpret_cast(code.data()); - - VkShaderModule shader_module; - if (vkCreateShaderModule(vk_device, &create_info, nullptr, - &shader_module) != VK_SUCCESS) - { - throw std::runtime_error("Failed to create shader module."); - } - - return shader_module; -} -} - -namespace VK -{ - -Device::Device(VkPhysicalDevice vk_physical_device, bool with_swapchain) -{ - this->physical_device = vk_physical_device; - - std::vector queue_family_properties; - - // Get queue families. - { - vkGetPhysicalDeviceQueueFamilyProperties( - vk_physical_device, &this->queue_families_count, nullptr); - queue_family_properties.resize(this->queue_families_count); - vkGetPhysicalDeviceQueueFamilyProperties( - vk_physical_device, &this->queue_families_count, - queue_family_properties.data()); - } - - // Get information from physical device. - { - VkPhysicalDeviceProperties physical_properties = {}; - vkGetPhysicalDeviceProperties(vk_physical_device, &physical_properties); - VkPhysicalDeviceFeatures supported_features = {}; - vkGetPhysicalDeviceFeatures(vk_physical_device, &supported_features); - -#ifdef DEBUG - std::stringstream message{}; - message << "Name: " << physical_properties.deviceName << std::endl; - message << "API version: " << physical_properties.apiVersion << - std::endl; - message << "Driver version: " << physical_properties.driverVersion << - std::endl; - message << "Vendor ID: " << physical_properties.vendorID << std::endl; - message << "Device ID: " << physical_properties.deviceID << std::endl; - message << "Device type: " << physical_properties.deviceType << - std::endl; - cg_core.log.message(Log::Level::Trace, message.str()); -#endif - - std::vector device_queue_create_infos; - std::vector> queue_priorities( - queue_family_properties.size()); - device_queue_create_infos.resize(queue_family_properties.size()); - for(auto i{0}; i < queue_family_properties.size(); i++) - { - // Give different priorities to queues. - int queue_count = queue_family_properties[i].queueCount; - queue_priorities[i].resize(queue_count); - float priority_unity = 1.0f/queue_count; - for(auto ii{0}; ii < queue_count; ii++) - queue_priorities[i][ii] = priority_unity * (queue_count - ii); - - device_queue_create_infos[i].sType = - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - device_queue_create_infos[i].pNext = nullptr; - device_queue_create_infos[i].flags = 0; - device_queue_create_infos[i].queueFamilyIndex = i; - device_queue_create_infos[i].queueCount = queue_priorities[i].size(); - device_queue_create_infos[i].pQueuePriorities = - queue_priorities[i].data(); - } - - VkPhysicalDeviceFeatures required_features = {}; - required_features.multiDrawIndirect = supported_features.multiDrawIndirect; - required_features.fillModeNonSolid = VK_TRUE; - required_features.geometryShader = VK_TRUE; - required_features.tessellationShader = VK_TRUE; - required_features.samplerAnisotropy = VK_TRUE; - - std::vector device_extensions; - if(with_swapchain) - device_extensions.emplace_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - - VkDeviceCreateInfo device_create_info = {}; - device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.pNext = nullptr; - device_create_info.flags = 0; - device_create_info.queueCreateInfoCount = device_queue_create_infos.size(); - device_create_info.pQueueCreateInfos = device_queue_create_infos.data(); - device_create_info.enabledLayerCount = 0; - device_create_info.ppEnabledLayerNames = nullptr; - device_create_info.enabledExtensionCount = device_extensions.size(); - if(device_extensions.size() == 0) - device_create_info.ppEnabledExtensionNames = nullptr; - else - device_create_info.ppEnabledExtensionNames = device_extensions.data(); - - device_create_info.pEnabledFeatures = &required_features; - - if(vkCreateDevice(this->physical_device, &device_create_info, nullptr, - &this->device) != VK_SUCCESS) - throw std::runtime_error("Failed to create Vulkan physical device."); - } - - // Load Shaders - { - std::string data_dir{""}; -#ifdef _WIN64 - HKEY hKey; - LPCSTR lpSubKey = "SOFTWARE\\CandyGear"; - LPCSTR lpValueName = "InstallLocation"; - DWORD dwType = REG_SZ; - DWORD dwSize = 0; - LPBYTE lpData = NULL; - - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hKey) == - ERROR_SUCCESS) - { - if(RegQueryValueEx(hKey, lpValueName, NULL, &dwType, NULL, &dwSize) == - ERROR_SUCCESS) - { - lpData = new BYTE[dwSize]; - if(RegQueryValueEx( - hKey, lpValueName, NULL, &dwType, lpData, &dwSize) == - ERROR_SUCCESS) - { - data_dir = reinterpret_cast(lpData); - } - delete[] lpData; - } - RegCloseKey(hKey); - } - - if(data_dir == "") - throw std::runtime_error("Failed to read CandyGear registry."); - - std::string vert_sprite_3d_shader_module{data_dir}; - vert_sprite_3d_shader_module.append("\\glsl\\shader_sprite_3d.vert.spv"); - this->vert_sprite_3d_shader_module = create_shader_module( - this->device, vert_sprite_3d_shader_module.c_str()); - - std::string frag_sprite_3d_shader_module{data_dir}; - frag_sprite_3d_shader_module.append("\\glsl\\shader_sprite_3d.frag.spv"); - this->frag_sprite_3d_shader_module = create_shader_module( - this->device, frag_sprite_3d_shader_module.c_str()); - - std::string vert3d_shader_module{data_dir}; - vert3d_shader_module.append("\\glsl\\shader_3d.vert.spv"); - this->vert3d_shader_module = create_shader_module( - this->device, vert3d_shader_module.c_str()); - - std::string vert3d_skeletal_shader_module{data_dir}; - vert3d_skeletal_shader_module.append( - "\\glsl\\shader_3d_skeletal.vert.spv"); - this->vert3d_skeletal_shader_module = create_shader_module( - this->device, vert3d_skeletal_shader_module.c_str()); - - std::string frag3d_shader_module{data_dir}; - frag3d_shader_module.append("\\glsl\\shader_3d.frag.spv"); - this->frag3d_shader_module = create_shader_module( - this->device, frag3d_shader_module.c_str()); - - std::string vert2d_solid_shader_module{data_dir}; - vert2d_solid_shader_module.append("\\glsl\\shader_2d_solid.vert.spv"); - this->vert2d_solid_shader_module = create_shader_module( - this->device, vert2d_solid_shader_module.c_str()); - - std::string frag2d_solid_shader_module{data_dir}; - frag2d_solid_shader_module.append("\\glsl\\shader_2d_solid.frag.spv"); - this->frag2d_solid_shader_module = create_shader_module( - this->device, frag2d_solid_shader_module.c_str()); - - std::string vert2d_wired_shader_module{data_dir}; - vert2d_wired_shader_module.append("\\glsl\\shader_2d_wired.vert.spv"); - this->vert2d_wired_shader_module = create_shader_module( - this->device, vert2d_wired_shader_module.c_str()); - - std::string frag2d_wired_shader_module{data_dir}; - frag2d_wired_shader_module.append("\\glsl\\shader_2d_wired.frag.spv"); - this->frag2d_wired_shader_module = create_shader_module( - this->device, frag2d_wired_shader_module.c_str()); -#else - data_dir = "/usr/local/share/candy_gear"; - - std::string vert_sprite_3d_shader_module{data_dir}; - vert_sprite_3d_shader_module.append("/glsl/shader_sprite_3d.vert.spv"); - this->vert_sprite_3d_shader_module = create_shader_module( - this->device, vert_sprite_3d_shader_module.c_str()); - - std::string frag_sprite_3d_shader_module{data_dir}; - frag_sprite_3d_shader_module.append("/glsl/shader_sprite_3d.frag.spv"); - this->frag_sprite_3d_shader_module = create_shader_module( - this->device, frag_sprite_3d_shader_module.c_str()); - - std::string vert3d_shader_module{data_dir}; - vert3d_shader_module.append("/glsl/shader_3d.vert.spv"); - this->vert3d_shader_module = create_shader_module( - this->device, vert3d_shader_module.c_str()); - - std::string vert3d_skeletal_shader_module{data_dir}; - vert3d_skeletal_shader_module.append("/glsl/shader_3d_skeletal.vert.spv"); - this->vert3d_skeletal_shader_module = create_shader_module( - this->device, vert3d_skeletal_shader_module.c_str()); - - std::string frag3d_shader_module{data_dir}; - frag3d_shader_module.append("/glsl/shader_3d.frag.spv"); - this->frag3d_shader_module = create_shader_module( - this->device, frag3d_shader_module.c_str()); - - std::string vert2d_solid_shader_module{data_dir}; - vert2d_solid_shader_module.append("/glsl/shader_2d_solid.vert.spv"); - this->vert2d_solid_shader_module = create_shader_module( - this->device, vert2d_solid_shader_module.c_str()); - - std::string frag2d_solid_shader_module{data_dir}; - frag2d_solid_shader_module.append("/glsl/shader_2d_solid.frag.spv"); - this->frag2d_solid_shader_module = create_shader_module( - this->device, frag2d_solid_shader_module.c_str()); - - std::string vert2d_wired_shader_module{data_dir}; - vert2d_wired_shader_module.append("/glsl/shader_2d_wired.vert.spv"); - this->vert2d_wired_shader_module = create_shader_module( - this->device, vert2d_wired_shader_module.c_str()); - - std::string frag2d_wired_shader_module{data_dir}; - frag2d_wired_shader_module.append("/glsl/shader_2d_wired.frag.spv"); - this->frag2d_wired_shader_module = create_shader_module( - this->device, frag2d_wired_shader_module.c_str()); -#endif - } - - this->queue_families = static_cast( - std::malloc(this->queue_families_count * sizeof(QueueFamily))); - for(auto i{0}; i < this->queue_families_count; i++) - { - new(&this->queue_families[i])QueueFamily( - this, i, queue_family_properties[i]); - - // Select families with graphics support. - auto &family_properties = this->queue_families[i].family_properties; - if(family_properties.queueCount > 0 && - family_properties.queueFlags & VK_QUEUE_GRAPHICS_BIT) - this->queue_families_with_graphics.push_back( - &this->queue_families[i]); - - // Select families with presentation support. - VkBool32 present_supported; - vkGetPhysicalDeviceSurfaceSupportKHR( - vk_physical_device, i, cg_core.window_surface, &present_supported); - if(present_supported) - this->queue_families_with_presentation.push_back( - &this->queue_families[i]); - } -} - -Device::~Device() -{ - for(auto i{0}; i < this->queue_families_count; i++) - this->queue_families[i].~QueueFamily(); - std::free(this->queue_families); - - // Destroy shaders - vkDestroyShaderModule( - this->device, this->vert_sprite_3d_shader_module, nullptr); - vkDestroyShaderModule( - this->device, this->frag_sprite_3d_shader_module, nullptr); - vkDestroyShaderModule(this->device, this->vert3d_shader_module, nullptr); - vkDestroyShaderModule( - this->device, this->vert3d_skeletal_shader_module, nullptr); - vkDestroyShaderModule(this->device, this->frag3d_shader_module, nullptr); - vkDestroyShaderModule( - this->device, this->vert2d_solid_shader_module, nullptr); - vkDestroyShaderModule( - this->device, this->frag2d_solid_shader_module, nullptr); - vkDestroyShaderModule( - this->device, this->vert2d_wired_shader_module, nullptr); - vkDestroyShaderModule( - this->device, this->frag2d_wired_shader_module, nullptr); - - vkDeviceWaitIdle(this->device); - vkDestroyDevice(this->device, nullptr); -} - -bool -Device::select_memory_type( - uint32_t *memory_type_index, VkMemoryRequirements *vk_memory_requirements, - VkMemoryPropertyFlags vk_property_flags) -{ - VkPhysicalDeviceMemoryProperties vk_memory_properties; - vkGetPhysicalDeviceMemoryProperties( - this->physical_device, &vk_memory_properties); - - for (auto i{0}; i < vk_memory_properties.memoryTypeCount; i++) - { - if(vk_memory_requirements->memoryTypeBits & (1 << i)) - { - const VkMemoryType& type = vk_memory_properties.memoryTypes[i]; - - if ((type.propertyFlags & vk_property_flags) == vk_property_flags) - { - *memory_type_index = i; - return true; - } - } - } - - return false; -} - -QueueFamily* -Device::get_queue_family_with_graphics() const -{ - /* - Returns a random queue family, so not all commands in the engine use the - same queue. - TODO: There must be a better way of doing this. - */ - std::uniform_int_distribution random_distribution{ - 0, this->queue_families_with_graphics.size() -1}; - auto random = random_distribution(random_number_generator); - return this->queue_families_with_graphics[0]; -} - -QueueFamily* -Device::get_queue_family_with_presentation() const -{ - /* - Returns a random queue family, so not all commands in the engine use the - same queue. - TODO: There must be a better way of doing this. - */ - std::uniform_int_distribution random_distribution{ - 0, this->queue_families_with_presentation.size() -1}; - auto random = random_distribution(random_number_generator); - return this->queue_families_with_presentation[0]; -} - -} diff --git a/src/vk/device.hpp b/src/vk/device.hpp deleted file mode 100644 index e52a143..0000000 --- a/src/vk/device.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_DEVICE_H -#define CANDY_GEAR_VK_DEVICE_H 1 - -#include -#include - -#include "core.hpp" -#include "queue_family.hpp" - -namespace VK -{ - -struct Device -{ - uint32_t queue_families_count; - QueueFamily *queue_families; - std::vector queue_families_with_graphics; - std::vector queue_families_with_presentation; - -public: - VkDevice device; - VkPhysicalDevice physical_device; - - VkShaderModule vert_sprite_3d_shader_module; - VkShaderModule frag_sprite_3d_shader_module; - VkShaderModule vert3d_shader_module; - VkShaderModule vert3d_skeletal_shader_module; - VkShaderModule frag3d_shader_module; - VkShaderModule vert2d_solid_shader_module; - VkShaderModule frag2d_solid_shader_module; - VkShaderModule vert2d_wired_shader_module; - VkShaderModule frag2d_wired_shader_module; - - bool with_swapchain; - - Device(VkPhysicalDevice vk_physical_device, bool with_swapchain); - ~Device(); - - bool - select_memory_type( - uint32_t *memoryTypeIndex, VkMemoryRequirements *vk_memory_requirements, - VkMemoryPropertyFlags vk_property_flags); - - QueueFamily* - get_queue_family_with_graphics() const; - - QueueFamily* - get_queue_family_with_presentation() const; -}; - -} - -#endif /* CANDY_GEAR_VK_DEVICE_H */ diff --git a/src/vk/font.cpp b/src/vk/font.cpp deleted file mode 100644 index cb01a51..0000000 --- a/src/vk/font.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "font.hpp" - -#include "../core.hpp" - -namespace VK -{ - -Font::Font(const char* font_path, int font_size) -{ - FT_Error error; - error = FT_New_Face(cg_core.font_library, font_path, 0, &this->face); - if(error == FT_Err_Unknown_File_Format) throw std::invalid_argument( - "The font file could be opened and read, but it appears that its font " - "format is unsupported."); - else if(error) throw std::invalid_argument( - "The font file could not be opened or read, or it is broken."); - - error = FT_Set_Pixel_Sizes(this->face, 0, font_size); - if(error) throw std::invalid_argument("Failed to load font size."); -} - -Font::~Font() -{ - FT_Done_Face(this->face); -} - -std::shared_ptr -Font::character(uint32_t character_code) -{ - if(!this->characters.contains(character_code)) - this->characters.emplace( - character_code, std::make_shared(this->face, character_code)); - - return this->characters.at(character_code); -} - -} diff --git a/src/vk/font.hpp b/src/vk/font.hpp deleted file mode 100644 index b654183..0000000 --- a/src/vk/font.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_FONT_H -#define CANDY_GEAR_VK_FONT_H 1 - -#include -#include - -#include "character.hpp" - -namespace VK -{ - -struct Font -{ - FT_Face face; - std::unordered_map> characters; - - Font(const char* font_path, int font_size); - ~Font(); - - std::shared_ptr - character(uint32_t character_code); -}; - -} - -#endif /* CANDY_GEAR_VK_FONT_H */ diff --git a/src/vk/framebuffer.cpp b/src/vk/framebuffer.cpp deleted file mode 100644 index 4104554..0000000 --- a/src/vk/framebuffer.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "framebuffer.hpp" - -#include "../core.hpp" -#include "image.hpp" - -namespace -{ -void -load_depth_image(void *obj) -{ - auto self = static_cast(obj); - - VkExtent3D extent3d{}; - extent3d.width = cg_core.display_width; - extent3d.height = cg_core.display_height; - extent3d.depth = 1; - - try - { - VK::Image::create( - cg_core.vk_device_with_swapchain, - &self->depth_image, - &self->depth_image_memory, - VK_FORMAT_D32_SFLOAT, - extent3d, - 1, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT - ); - } - catch(VK::Image::Error error) - { - std::string error_message{"Failed to create depth image → "}; - error_message += error.what(); - throw CommandError{error_message}; - } -} - -void -unload_depth_image(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyImage( - cg_core.vk_device_with_swapchain->device, self->depth_image, - nullptr); - vkFreeMemory( - cg_core.vk_device_with_swapchain->device, - self->depth_image_memory, nullptr); -} - -void -load_depth_image_view(void *obj) -{ - auto self = static_cast(obj); - - try - { - VK::Image::create_view( - cg_core.vk_device_with_swapchain, &self->depth_image_view, - self->depth_image, - VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT); - } - catch(VK::Image::Error error) - { - std::string error_message{"Failed to create depth image view → "}; - error_message += error.what(); - throw CommandError{error_message}; - } -} - -void -unload_depth_image_view(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyImageView( - cg_core.vk_device_with_swapchain->device, self->depth_image_view, nullptr); -} - -void -load_3d(void *obj) -{ - auto self = static_cast(obj); - - self->pipeline_3d.resize(cg_core.vk_swapchain->images_count); - for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - { - std::array attachments = { - cg_core.vk_swapchain->image_views[i], - self->depth_image_view - }; - - VkFramebufferCreateInfo framebuffer_info{}; - framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebuffer_info.renderPass = cg_core.vk_render_pass->pipeline_3d; - framebuffer_info.attachmentCount = attachments.size(); - framebuffer_info.pAttachments = attachments.data(); - framebuffer_info.width = cg_core.display_width; - framebuffer_info.height = cg_core.display_height; - - framebuffer_info.layers = 1; - - if(vkCreateFramebuffer( - cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, - &self->pipeline_3d[i]) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan Framebuffer."}; - } -} - -void -unload_3d(void *obj) -{ - auto self = static_cast(obj); - - for(auto framebuffer: self->pipeline_3d) - vkDestroyFramebuffer( - cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); -} - -void -load_2d(void *obj) -{ - auto self = static_cast(obj); - - self->pipeline_2d.resize(cg_core.vk_swapchain->images_count); - for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - { - std::array attachments = { - cg_core.vk_swapchain->image_views[i] - }; - - VkFramebufferCreateInfo framebuffer_info{}; - framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebuffer_info.renderPass = cg_core.vk_render_pass->pipeline_2d; - framebuffer_info.attachmentCount = attachments.size(); - framebuffer_info.pAttachments = attachments.data(); - framebuffer_info.width = cg_core.display_width; - framebuffer_info.height = cg_core.display_height; - framebuffer_info.layers = 1; - - if(vkCreateFramebuffer( - cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, - &self->pipeline_2d[i]) - != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan Framebuffer."}; - } -} - -void -unload_2d(void *obj) -{ - auto self = static_cast(obj); - - for(auto framebuffer: self->pipeline_2d) - vkDestroyFramebuffer( - cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); -} - -const CommandChain loader{ - {&load_depth_image, &unload_depth_image}, - {&load_depth_image_view, &unload_depth_image_view}, - {&load_3d, &unload_3d}, - {&load_2d, &unload_2d} -}; - -} - -namespace VK -{ - -Framebuffer::Framebuffer() -{ - loader.execute(this); -} - -Framebuffer::~Framebuffer() -{ - loader.revert(this); -} - -} diff --git a/src/vk/framebuffer.hpp b/src/vk/framebuffer.hpp deleted file mode 100644 index 2867fa1..0000000 --- a/src/vk/framebuffer.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_FRAMEBUFFER_H -#define CANDY_GEAR_VK_FRAMEBUFFER_H 1 - -#include - -#include "core.hpp" - -namespace VK -{ - -struct Framebuffer -{ - // Depth image. - VkImage depth_image; - VkDeviceMemory depth_image_memory; - VkImageView depth_image_view; - - std::vector pipeline_3d; - std::vector pipeline_2d; - - Framebuffer(); - ~Framebuffer(); -}; - -} - -#endif /* CANDY_GEAR_VK_FRAMEBUFFER_H */ diff --git a/src/vk/graphics_pipeline_2d_solid.cpp b/src/vk/graphics_pipeline_2d_solid.cpp deleted file mode 100644 index f914594..0000000 --- a/src/vk/graphics_pipeline_2d_solid.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_2d_solid.hpp" - -#include - -#include "../core.hpp" -#include "sprite.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; - vert_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.pNext = nullptr; - vert_shader_stage_info.flags = 0; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = - cg_core.vk_device_with_swapchain->vert2d_solid_shader_module; - vert_shader_stage_info.pName = "main"; - vert_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; - frag_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.pNext = nullptr; - frag_shader_stage_info.flags = 0; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = - cg_core.vk_device_with_swapchain->frag2d_solid_shader_module; - frag_shader_stage_info.pName = "main"; - frag_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo shader_stages[] = { - vert_shader_stage_info, - frag_shader_stage_info - }; - - VkVertexInputBindingDescription vertex_input_binding{}; - vertex_input_binding.binding = 0; - vertex_input_binding.stride = sizeof(glm::vec2); - vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::array vertex_attribute{}; - // Texture coordinate. - vertex_attribute[0].location = 0; - vertex_attribute[0].binding = 0; - vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; - vertex_attribute[0].offset = 0; - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.pNext = nullptr; - vertex_input_info.flags = 0; - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; - vertex_input_info.vertexAttributeDescriptionCount = - static_cast(vertex_attribute.size()); - vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.pNext = nullptr; - input_assembly.flags = 0; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = cg_core.display_width; - viewport.height = cg_core.display_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = {cg_core.display_width, cg_core.display_height}; - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.pNext = nullptr; - viewport_state.flags = 0; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.pNext = nullptr; - rasterizer.flags = 0; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - rasterizer.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.blendEnable = VK_TRUE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment.dstColorBlendFactor = - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.pNext = nullptr; - color_blending.flags = 0; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - std::array dynamic_states{ - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH, - VK_DYNAMIC_STATE_BLEND_CONSTANTS - }; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_info.dynamicStateCount = dynamic_states.size(); - dynamic_state_info.pDynamicStates = dynamic_states.data(); - - VkGraphicsPipelineCreateInfo pipeline_info{}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = nullptr; - pipeline_info.flags = 0; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = nullptr; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = nullptr; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = - cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline; - pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_2d; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if(vkCreateGraphicsPipelines( - cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, - &pipeline_info, nullptr, &self->graphic_pipeline) - != VK_SUCCESS) - throw CommandError{"Failed to create graphics pipeline."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipeline( - cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline2DSolid::GraphicsPipeline2DSolid() -{ - loader.execute(this); -} - -GraphicsPipeline2DSolid::~GraphicsPipeline2DSolid() -{ - loader.revert(this); -} - -void -GraphicsPipeline2DSolid::draw( - std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const size_t next_frame, - const uint32_t image_index) -{ - // TODO set viewport just once per view, not once per pipeline. - { // Set viewport - VkViewport vk_viewport{}; - vk_viewport.x = view->region.x; - vk_viewport.y = view->region.y; - vk_viewport.width = view->region.z; - vk_viewport.height = view->region.w; - vk_viewport.minDepth = 0.0f; - vk_viewport.maxDepth = 1.0f; - vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); - - VkRect2D vk_scissor{}; - vk_scissor.offset.x = static_cast(view->region.x); - vk_scissor.offset.y = static_cast(view->region.y); - vk_scissor.extent.width = static_cast(view->region.z); - vk_scissor.extent.height = static_cast(view->region.w); - vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); - } - - vkCmdBindPipeline( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - this->graphic_pipeline); - - // FIXME: I know sorting is expensive, but I need to figure out better what - // to do here. - std::sort(view->sprites_to_draw[current_frame].begin(), - view->sprites_to_draw[current_frame].end()); - - // Draw sprites - for(auto& sprite_to_draw: view->sprites_to_draw[current_frame]) - { - std::array vk_descriptor_sets{ - view->descriptor_sets_2d[image_index], - sprite_to_draw.sprite->texture->descriptor_sets[image_index]}; - VkDeviceSize offsets[]{0}; - - vkCmdBindDescriptorSets( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline, 0, - vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); - vkCmdBindVertexBuffers( - draw_command_buffer, 0, 1, &sprite_to_draw.sprite->vertex_buffer->buffer, - offsets); - - UDOVector4D position{sprite_to_draw.position}; - vkCmdPushConstants( - draw_command_buffer, - cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline, - VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UDOVector4D), &position); - vkCmdDraw(draw_command_buffer, Sprite::vertex_count, 1, 0, 0); - } - - // Prepare for the next frame. - view->sprites_to_draw[next_frame].clear(); -} - -} diff --git a/src/vk/graphics_pipeline_2d_solid.hpp b/src/vk/graphics_pipeline_2d_solid.hpp deleted file mode 100644 index eac825f..0000000 --- a/src/vk/graphics_pipeline_2d_solid.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H 1 - -#include - -#include "core.hpp" -#include "command_pool.hpp" -#include "view_2d.hpp" - -namespace VK -{ - -struct GraphicsPipeline2DSolid -{ - VkPipeline graphic_pipeline; - - GraphicsPipeline2DSolid(); - ~GraphicsPipeline2DSolid(); - - void - draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const size_t next_frame, - const uint32_t image_index); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H */ diff --git a/src/vk/graphics_pipeline_2d_solid_layout.cpp b/src/vk/graphics_pipeline_2d_solid_layout.cpp deleted file mode 100644 index 11d080b..0000000 --- a/src/vk/graphics_pipeline_2d_solid_layout.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_2d_solid_layout.hpp" - -#include - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - std::array set_layouts{ - cg_core.vk_descriptor_set_layout->view, - cg_core.vk_descriptor_set_layout->texture - }; - - std::array push_constants; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - push_constants[0].offset = 0; - push_constants[0].size = sizeof(VK::UDOVector4D); - - VkPipelineLayoutCreateInfo pipeline_layout_info{}; - pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = set_layouts.size(); - pipeline_layout_info.pSetLayouts = set_layouts.data(); - pipeline_layout_info.pushConstantRangeCount = push_constants.size(); - pipeline_layout_info.pPushConstantRanges = push_constants.data(); - - if(vkCreatePipelineLayout( - cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, - nullptr, &self->pipeline) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan pipeline layout."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipelineLayout( - cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline2DSolidLayout::GraphicsPipeline2DSolidLayout() -{ - loader.execute(this); -} - -GraphicsPipeline2DSolidLayout::~GraphicsPipeline2DSolidLayout() -{ - loader.revert(this); -} - -} diff --git a/src/vk/graphics_pipeline_2d_solid_layout.hpp b/src/vk/graphics_pipeline_2d_solid_layout.hpp deleted file mode 100644 index 0bb9de8..0000000 --- a/src/vk/graphics_pipeline_2d_solid_layout.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct GraphicsPipeline2DSolidLayout -{ - VkPipelineLayout pipeline; - - GraphicsPipeline2DSolidLayout(); - ~GraphicsPipeline2DSolidLayout(); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/vk/graphics_pipeline_2d_wired.cpp b/src/vk/graphics_pipeline_2d_wired.cpp deleted file mode 100644 index ef43cd1..0000000 --- a/src/vk/graphics_pipeline_2d_wired.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_2d_wired.hpp" - -#include - -#include "../core.hpp" -#include "rectangle.hpp" -#include "sprite.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_indexes(void *obj) -{ - auto self = static_cast(obj); - - self->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); - - std::array indexes{0, 1, 2, 3}; - void *indexes_data{indexes.data()}; - size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; - VK::SourceBuffer source_index_buffer{ - self->queue_family->device, indexes_data, indexes_size}; - self->index_buffer = new VK::DestinationBuffer{ - self->queue_family, &source_index_buffer, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; -} - -void -unload_indexes(void *obj) -{ - auto self = static_cast(obj); - - delete self->index_buffer; -} - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; - vert_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.pNext = nullptr; - vert_shader_stage_info.flags = 0; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = - cg_core.vk_device_with_swapchain->vert2d_wired_shader_module; - vert_shader_stage_info.pName = "main"; - vert_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; - frag_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.pNext = nullptr; - frag_shader_stage_info.flags = 0; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = - cg_core.vk_device_with_swapchain->frag2d_wired_shader_module; - frag_shader_stage_info.pName = "main"; - frag_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo shader_stages[] = { - vert_shader_stage_info, - frag_shader_stage_info - }; - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.pNext = nullptr; - vertex_input_info.flags = 0; - vertex_input_info.vertexBindingDescriptionCount = 0; - vertex_input_info.pVertexBindingDescriptions = nullptr; - vertex_input_info.vertexAttributeDescriptionCount = 0; - vertex_input_info.pVertexAttributeDescriptions = nullptr; - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.pNext = nullptr; - input_assembly.flags = 0; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = cg_core.display_width; - viewport.height = cg_core.display_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = {cg_core.display_width, cg_core.display_height}; - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.pNext = nullptr; - viewport_state.flags = 0; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.pNext = nullptr; - rasterizer.flags = 0; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_LINE; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - rasterizer.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.blendEnable = VK_FALSE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.pNext = nullptr; - color_blending.flags = 0; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH - }; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_info.dynamicStateCount = 2; - dynamic_state_info.pDynamicStates = dynamic_states; - - VkGraphicsPipelineCreateInfo pipeline_info{}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = nullptr; - pipeline_info.flags = 0; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = nullptr; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = nullptr; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = - cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline; - pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_2d; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if(vkCreateGraphicsPipelines( - cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, - &pipeline_info, nullptr, &self->graphic_pipeline) != VK_SUCCESS) - throw CommandError{"Failed to create graphics pipeline."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipeline( - cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); -} - -const CommandChain loader{ - {&load_indexes, &unload_indexes}, - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline2DWired::GraphicsPipeline2DWired() -{ - loader.execute(this); -} - -GraphicsPipeline2DWired::~GraphicsPipeline2DWired() -{ - loader.revert(this); -} - -void -GraphicsPipeline2DWired::draw( - std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const size_t next_frame, - const uint32_t image_index) -{ - // Set viewport - { - VkViewport vk_viewport{}; - vk_viewport.x = view->region.x; - vk_viewport.y = view->region.y; - vk_viewport.width = view->region.z; - vk_viewport.height = view->region.w; - vk_viewport.minDepth = 0.0f; - vk_viewport.maxDepth = 1.0f; - vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); - - VkRect2D vk_scissor{}; - vk_scissor.offset.x = static_cast(view->region.x); - vk_scissor.offset.y = static_cast(view->region.y); - vk_scissor.extent.width = static_cast(view->region.z); - vk_scissor.extent.height = static_cast(view->region.w); - vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); - } - - // Draw rectangles - { - std::array vk_descriptor_sets{ - view->descriptor_sets_2d[image_index]}; - VkDeviceSize offsets[]{0}; - - vkCmdBindDescriptorSets( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline, 0, - vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); - vkCmdBindPipeline( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - this->graphic_pipeline); - vkCmdBindIndexBuffer( - draw_command_buffer, this->index_buffer->buffer, 0, - VK_INDEX_TYPE_UINT32); - - for(auto i{0}; i < view->rectangles_to_draw[current_frame].size(); i++) - { - auto &rect{view->rectangles_to_draw[current_frame][i]}; - - UDOVector4D position{rect.position}; - UDOVector3D color{rect.color}; - vkCmdPushConstants( - draw_command_buffer, - cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline, - VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UDOVector4D), &position); - vkCmdPushConstants( - draw_command_buffer, - cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline, - VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(UDOVector4D), sizeof(UDOVector3D), - &color); - vkCmdDrawIndexed( - draw_command_buffer, Rectangle::VertexCount, 1, 0, 0, 0); - } - } - - // Prepare for the next frame. - view->rectangles_to_draw[next_frame].clear(); -} - -} diff --git a/src/vk/graphics_pipeline_2d_wired.hpp b/src/vk/graphics_pipeline_2d_wired.hpp deleted file mode 100644 index 932ed61..0000000 --- a/src/vk/graphics_pipeline_2d_wired.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_H 1 - -#include - -#include "core.hpp" -#include "view_2d.hpp" - -namespace VK -{ - -struct GraphicsPipeline2DWired -{ - QueueFamily *queue_family; - - VkPipeline graphic_pipeline; - - DestinationBuffer *index_buffer; - - GraphicsPipeline2DWired(); - ~GraphicsPipeline2DWired(); - - void - draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const size_t next_frame, - const uint32_t image_index); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_H */ diff --git a/src/vk/graphics_pipeline_2d_wired_layout.cpp b/src/vk/graphics_pipeline_2d_wired_layout.cpp deleted file mode 100644 index 10e2b50..0000000 --- a/src/vk/graphics_pipeline_2d_wired_layout.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_2d_wired_layout.hpp" - -#include - -#include "../core.hpp" -#include "graphics_pipeline_2d_solid_layout.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - std::array set_layouts{ - cg_core.vk_descriptor_set_layout->view - }; - - std::array push_constants; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - push_constants[0].offset = 0; - push_constants[0].size = sizeof(VK::UDOVector4D); - - push_constants[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - push_constants[1].offset = sizeof(VK::UDOVector4D); - push_constants[1].size = sizeof(VK::UDOVector3D); - - VkPipelineLayoutCreateInfo pipeline_layout_info{}; - pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = set_layouts.size(); - pipeline_layout_info.pSetLayouts = set_layouts.data(); - pipeline_layout_info.pushConstantRangeCount = push_constants.size(); - pipeline_layout_info.pPushConstantRanges = push_constants.data(); - - if(vkCreatePipelineLayout( - cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, - nullptr, &self->pipeline) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan pipeline layout."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipelineLayout( - cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline2DWiredLayout::GraphicsPipeline2DWiredLayout() -{ - loader.execute(this); -} - -GraphicsPipeline2DWiredLayout::~GraphicsPipeline2DWiredLayout() -{ - loader.revert(this); -} - -} diff --git a/src/vk/graphics_pipeline_2d_wired_layout.hpp b/src/vk/graphics_pipeline_2d_wired_layout.hpp deleted file mode 100644 index 004f009..0000000 --- a/src/vk/graphics_pipeline_2d_wired_layout.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct GraphicsPipeline2DWiredLayout -{ - VkPipelineLayout pipeline; - - GraphicsPipeline2DWiredLayout(); - ~GraphicsPipeline2DWiredLayout(); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/vk/graphics_pipeline_3d.cpp b/src/vk/graphics_pipeline_3d.cpp deleted file mode 100644 index 2a1fec1..0000000 --- a/src/vk/graphics_pipeline_3d.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright 2022-2024 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_3d.hpp" - -#include -#include - -#include "../core.hpp" -#include "core.hpp" -#include "static_mesh_vertex.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; - vert_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.pNext = nullptr; - vert_shader_stage_info.flags = 0; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = - cg_core.vk_device_with_swapchain->vert3d_shader_module; - vert_shader_stage_info.pName = "main"; - vert_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; - frag_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.pNext = nullptr; - frag_shader_stage_info.flags = 0; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = - cg_core.vk_device_with_swapchain->frag3d_shader_module; - frag_shader_stage_info.pName = "main"; - frag_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo shader_stages[] = { - vert_shader_stage_info, - frag_shader_stage_info - }; - - VkVertexInputBindingDescription vertex_input_binding{}; - vertex_input_binding.binding = 0; - vertex_input_binding.stride = sizeof(VK::StaticMeshVertex); - vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::array vertex_attribute{}; - // Position. - vertex_attribute[0].location = 0; - vertex_attribute[0].binding = 0; - vertex_attribute[0].format = VK_FORMAT_R32G32B32_SFLOAT; - vertex_attribute[0].offset = offsetof(VK::StaticMeshVertex, position); - // Normal. - vertex_attribute[1].location = 1; - vertex_attribute[1].binding = 0; - vertex_attribute[1].format = VK_FORMAT_R32G32B32_SFLOAT; - vertex_attribute[1].offset = offsetof(VK::StaticMeshVertex, normal); - // Texture coordinate. - vertex_attribute[2].location = 2; - vertex_attribute[2].binding = 0; - vertex_attribute[2].format = VK_FORMAT_R32G32_SFLOAT; - vertex_attribute[2].offset = offsetof(VK::StaticMeshVertex, texture_coord); - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.pNext = nullptr; - vertex_input_info.flags = 0; - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; - vertex_input_info.vertexAttributeDescriptionCount = - static_cast(vertex_attribute.size()); - vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.pNext = nullptr; - input_assembly.flags = 0; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = cg_core.display_width; - viewport.height = cg_core.display_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = {cg_core.display_width, cg_core.display_height}; - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.pNext = nullptr; - viewport_state.flags = 0; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.pNext = nullptr; - rasterizer.flags = 0; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - rasterizer.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; - depth_stencil.sType = - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = VK_TRUE; - depth_stencil.depthWriteEnable = VK_TRUE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.minDepthBounds = 0.0f; - depth_stencil.maxDepthBounds = 1.0f; - depth_stencil.stencilTestEnable = VK_FALSE; - depth_stencil.front = {}; - depth_stencil.back = {}; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.blendEnable = VK_FALSE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.pNext = nullptr; - color_blending.flags = 0; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH - }; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_info.dynamicStateCount = 2; - dynamic_state_info.pDynamicStates = dynamic_states; - - VkGraphicsPipelineCreateInfo pipeline_info{}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = nullptr; - pipeline_info.flags = 0; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = nullptr; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = &depth_stencil; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; - pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_3d; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if(vkCreateGraphicsPipelines( - cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, - &pipeline_info, nullptr, &self->graphic_pipeline) - != VK_SUCCESS) - throw CommandError{"Failed to create graphics pipeline."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipeline( - cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline3D::GraphicsPipeline3D() -{ - loader.execute(this); -} - -GraphicsPipeline3D::~GraphicsPipeline3D() -{ - loader.revert(this); -} - -void -GraphicsPipeline3D::draw( - std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const uint32_t image_index) -{ - vkCmdBindPipeline( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - this->graphic_pipeline); - - // Draw models - for(auto& [static_mesh, instances]: - cg_core.vk_renderer->static_models_to_draw[current_frame]) - { - VkBuffer vertex_buffers[]{static_mesh->vertex_buffer->buffer}; - VkDeviceSize offsets[]{0}; - - vkCmdBindVertexBuffers( - draw_command_buffer, 0, 1, vertex_buffers, offsets); - vkCmdBindIndexBuffer( - draw_command_buffer, static_mesh->index_buffer->buffer, 0, - VK_INDEX_TYPE_UINT32); - - for(auto &instance: instances) - { // Object matrix. - glm::mat4 translation_matrix{1.0f}; - translation_matrix = glm::translate( - translation_matrix, *instance->position); - glm::mat4 rotation_matrix{glm::toMat4(*instance->orientation)}; - - std::array vk_descriptor_sets{ - cg_core.vk_light->descriptor_sets_world[image_index], - view->descriptor_sets_3d[image_index], - instance->descriptor_sets[image_index], - instance->texture->descriptor_sets[image_index]}; - - vkCmdBindDescriptorSets( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, - vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); - - vkCmdDrawIndexed( - draw_command_buffer, static_mesh->index_count, 1, 0, 0, 0); - - VK::UDOStaticModel udo_static_model{}; - udo_static_model.base_matrix = translation_matrix * rotation_matrix; - instance->uniform_buffers[image_index].copy_data(&udo_static_model); - } - } -} - -} diff --git a/src/vk/graphics_pipeline_3d.hpp b/src/vk/graphics_pipeline_3d.hpp deleted file mode 100644 index bfe034d..0000000 --- a/src/vk/graphics_pipeline_3d.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_H 1 - -#include - -#include "core.hpp" -#include "command_pool.hpp" -#include "view_3d.hpp" - -namespace VK -{ - -struct GraphicsPipeline3D -{ - VkPipeline graphic_pipeline; - - GraphicsPipeline3D(); - ~GraphicsPipeline3D(); - - void - draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const uint32_t image_index); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_H */ diff --git a/src/vk/graphics_pipeline_3d_layout.cpp b/src/vk/graphics_pipeline_3d_layout.cpp deleted file mode 100644 index c316518..0000000 --- a/src/vk/graphics_pipeline_3d_layout.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_3d_layout.hpp" - -#include - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - std::array set_layouts{ - cg_core.vk_descriptor_set_layout->world, - cg_core.vk_descriptor_set_layout->view, - cg_core.vk_descriptor_set_layout->model, - cg_core.vk_descriptor_set_layout->texture}; - - VkPipelineLayoutCreateInfo pipeline_layout_info{}; - pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = set_layouts.size(); - pipeline_layout_info.pSetLayouts = set_layouts.data(); - pipeline_layout_info.pushConstantRangeCount = 0; - pipeline_layout_info.pPushConstantRanges = nullptr; - - if(vkCreatePipelineLayout( - cg_core.vk_device_with_swapchain->device, - &pipeline_layout_info, nullptr, &self->pipeline) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan pipeline layout."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipelineLayout( - cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline3DLayout::GraphicsPipeline3DLayout() -{ - loader.execute(this); -} - -GraphicsPipeline3DLayout::~GraphicsPipeline3DLayout() -{ - loader.revert(this); -} - -} diff --git a/src/vk/graphics_pipeline_3d_layout.hpp b/src/vk/graphics_pipeline_3d_layout.hpp deleted file mode 100644 index 4b2b9b9..0000000 --- a/src/vk/graphics_pipeline_3d_layout.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_LAYOUT_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_LAYOUT_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct GraphicsPipeline3DLayout -{ - VkPipelineLayout pipeline; - - GraphicsPipeline3DLayout(); - ~GraphicsPipeline3DLayout(); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_LAYOUT_H */ diff --git a/src/vk/graphics_pipeline_3d_skeletal.cpp b/src/vk/graphics_pipeline_3d_skeletal.cpp deleted file mode 100644 index 6bd1713..0000000 --- a/src/vk/graphics_pipeline_3d_skeletal.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2022-2024 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_3d.hpp" - -#include -#include - -#include "../core.hpp" -#include "core.hpp" -#include "skeletal_mesh_vertex.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; - vert_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.pNext = nullptr; - vert_shader_stage_info.flags = 0; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = - cg_core.vk_device_with_swapchain->vert3d_skeletal_shader_module; - vert_shader_stage_info.pName = "main"; - vert_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; - frag_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.pNext = nullptr; - frag_shader_stage_info.flags = 0; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = - cg_core.vk_device_with_swapchain->frag3d_shader_module; - frag_shader_stage_info.pName = "main"; - frag_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo shader_stages[] = { - vert_shader_stage_info, - frag_shader_stage_info - }; - - VkVertexInputBindingDescription vertex_input_binding{}; - vertex_input_binding.binding = 0; - vertex_input_binding.stride = sizeof(VK::SkeletalMeshVertex); - vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::array vertex_attribute{}; - // Position. - vertex_attribute[0].location = 0; - vertex_attribute[0].binding = 0; - vertex_attribute[0].format = VK_FORMAT_R32G32B32_SFLOAT; - vertex_attribute[0].offset = offsetof(VK::SkeletalMeshVertex, position); - // Normal. - vertex_attribute[1].location = 1; - vertex_attribute[1].binding = 0; - vertex_attribute[1].format = VK_FORMAT_R32G32B32_SFLOAT; - vertex_attribute[1].offset = offsetof(VK::SkeletalMeshVertex, normal); - // Texture coordinate. - vertex_attribute[2].location = 2; - vertex_attribute[2].binding = 0; - vertex_attribute[2].format = VK_FORMAT_R32G32_SFLOAT; - vertex_attribute[2].offset = offsetof(VK::SkeletalMeshVertex, texture_coord); - // Bones ids. - vertex_attribute[3].location = 3; - vertex_attribute[3].binding = 0; - vertex_attribute[3].format = VK_FORMAT_R32G32B32A32_SINT; - vertex_attribute[3].offset = offsetof(VK::SkeletalMeshVertex, bone_ids); - // Bones weights. - vertex_attribute[4].location = 4; - vertex_attribute[4].binding = 0; - vertex_attribute[4].format = VK_FORMAT_R32G32B32A32_SFLOAT; - vertex_attribute[4].offset = offsetof(VK::SkeletalMeshVertex, bone_weights); - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.pNext = nullptr; - vertex_input_info.flags = 0; - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; - vertex_input_info.vertexAttributeDescriptionCount = - static_cast(vertex_attribute.size()); - vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.pNext = nullptr; - input_assembly.flags = 0; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = cg_core.display_width; - viewport.height = cg_core.display_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = {cg_core.display_width, cg_core.display_height}; - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.pNext = nullptr; - viewport_state.flags = 0; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.pNext = nullptr; - rasterizer.flags = 0; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - rasterizer.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; - depth_stencil.sType = - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = VK_TRUE; - depth_stencil.depthWriteEnable = VK_TRUE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.minDepthBounds = 0.0f; - depth_stencil.maxDepthBounds = 1.0f; - depth_stencil.stencilTestEnable = VK_FALSE; - depth_stencil.front = {}; - depth_stencil.back = {}; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.blendEnable = VK_FALSE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.pNext = nullptr; - color_blending.flags = 0; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH - }; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_info.dynamicStateCount = 2; - dynamic_state_info.pDynamicStates = dynamic_states; - - VkGraphicsPipelineCreateInfo pipeline_info{}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = nullptr; - pipeline_info.flags = 0; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = nullptr; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = &depth_stencil; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; - pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_3d; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if(vkCreateGraphicsPipelines( - cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, - &pipeline_info, nullptr, &self->graphic_pipeline) - != VK_SUCCESS) - throw CommandError{"Failed to create graphics pipeline."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipeline( - cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline3DSkeletal::GraphicsPipeline3DSkeletal() -{ - loader.execute(this); -} - -GraphicsPipeline3DSkeletal::~GraphicsPipeline3DSkeletal() -{ - loader.revert(this); -} - -void -GraphicsPipeline3DSkeletal::draw( - std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const uint32_t image_index) -{ - vkCmdBindPipeline( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - this->graphic_pipeline); - - // Draw models - for(auto& [skeletal_mesh, instances]: - cg_core.vk_renderer->skeletal_models_to_draw[current_frame]) - { - VkBuffer vertex_buffers[]{skeletal_mesh->vertex_buffer->buffer}; - VkDeviceSize offsets[]{0}; - - vkCmdBindVertexBuffers( - draw_command_buffer, 0, 1, vertex_buffers, offsets); - vkCmdBindIndexBuffer( - draw_command_buffer, skeletal_mesh->index_buffer->buffer, 0, - VK_INDEX_TYPE_UINT32); - - for(auto &instance: instances) - { // Object matrix. - glm::mat4 translation_matrix{1.0f}; - translation_matrix = glm::translate( - translation_matrix, *instance->position); - glm::mat4 rotation_matrix{glm::toMat4(*instance->orientation)}; - - std::array vk_descriptor_sets{ - cg_core.vk_light->descriptor_sets_world[image_index], - view->descriptor_sets_3d[image_index], - instance->descriptor_sets[image_index], - instance->texture->descriptor_sets[image_index]}; - - vkCmdBindDescriptorSets( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, - vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); - - vkCmdDrawIndexed( - draw_command_buffer, skeletal_mesh->index_count, 1, 0, 0, 0); - - VK::UDOSkeletalModel udo_skeletal_model{}; - instance->tick(cg_core.delta_time); - udo_skeletal_model.base_matrix = translation_matrix * rotation_matrix; - std::copy(instance->bone_transforms.begin(), - instance->bone_transforms.end(), - udo_skeletal_model.bone_matrices); - instance->uniform_buffers[image_index].copy_data(&udo_skeletal_model); - } - } - -} - -} diff --git a/src/vk/graphics_pipeline_3d_skeletal.hpp b/src/vk/graphics_pipeline_3d_skeletal.hpp deleted file mode 100644 index 027b42e..0000000 --- a/src/vk/graphics_pipeline_3d_skeletal.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_SKELETAL_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_3D_SKELETAL_H 1 - -#include - -#include "core.hpp" -#include "command_pool.hpp" -#include "view_3d.hpp" - -namespace VK -{ - -struct GraphicsPipeline3DSkeletal -{ - VkPipeline graphic_pipeline; - - GraphicsPipeline3DSkeletal(); - ~GraphicsPipeline3DSkeletal(); - - void - draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const uint32_t image_index); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_SKELETAL_3D_H */ diff --git a/src/vk/graphics_pipeline_sprite_3d.cpp b/src/vk/graphics_pipeline_sprite_3d.cpp deleted file mode 100644 index 0a4d520..0000000 --- a/src/vk/graphics_pipeline_sprite_3d.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "graphics_pipeline_sprite_3d.hpp" - -#include - -#include "../core.hpp" -#include "core.hpp" -#include "sprite.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -struct Sprite3DOrder -{ - std::shared_ptr sprite_3d; - float distance; -}; - -bool -operator<(const Sprite3DOrder &a, const Sprite3DOrder &b) -{ - return a.distance < b.distance; -} - -bool -operator>(const Sprite3DOrder &a, const Sprite3DOrder &b) -{ - return a.distance > b.distance; -} - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; - vert_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.pNext = nullptr; - vert_shader_stage_info.flags = 0; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = - cg_core.vk_device_with_swapchain->vert_sprite_3d_shader_module; - vert_shader_stage_info.pName = "main"; - vert_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; - frag_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.pNext = nullptr; - frag_shader_stage_info.flags = 0; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = - cg_core.vk_device_with_swapchain->frag_sprite_3d_shader_module; - frag_shader_stage_info.pName = "main"; - frag_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo shader_stages[] = { - vert_shader_stage_info, - frag_shader_stage_info - }; - - VkVertexInputBindingDescription vertex_input_binding{}; - vertex_input_binding.binding = 0; - vertex_input_binding.stride = sizeof(glm::vec2); - vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::array vertex_attribute{}; - // Texture coordinate. - vertex_attribute[0].location = 0; - vertex_attribute[0].binding = 0; - vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; - vertex_attribute[0].offset = 0; - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.pNext = nullptr; - vertex_input_info.flags = 0; - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; - vertex_input_info.vertexAttributeDescriptionCount = - static_cast(vertex_attribute.size()); - vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.pNext = nullptr; - input_assembly.flags = 0; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = cg_core.display_width; - viewport.height = cg_core.display_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = {cg_core.display_width, cg_core.display_height}; - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.pNext = nullptr; - viewport_state.flags = 0; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.pNext = nullptr; - rasterizer.flags = 0; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - rasterizer.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; - depth_stencil.sType = - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = VK_TRUE; - depth_stencil.depthWriteEnable = VK_TRUE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.minDepthBounds = 0.0f; - depth_stencil.maxDepthBounds = 1.0f; - depth_stencil.stencilTestEnable = VK_FALSE; - depth_stencil.front = {}; - depth_stencil.back = {}; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.blendEnable = VK_TRUE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment.dstColorBlendFactor = - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.pNext = nullptr; - color_blending.flags = 0; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - std::array dynamic_states{ - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH, - VK_DYNAMIC_STATE_BLEND_CONSTANTS - }; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_info.dynamicStateCount = dynamic_states.size(); - dynamic_state_info.pDynamicStates = dynamic_states.data(); - - VkGraphicsPipelineCreateInfo pipeline_info{}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = nullptr; - pipeline_info.flags = 0; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = nullptr; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = &depth_stencil; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; - pipeline_info.renderPass = cg_core.vk_render_pass->pipeline_3d; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if(vkCreateGraphicsPipelines( - cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, - &pipeline_info, nullptr, &self->graphic_pipeline) - != VK_SUCCESS) - throw CommandError{"Failed to create graphics pipeline sprite 3d."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipeline( - cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); -} - -const CommandChain loader{ - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipelineSprite3D::GraphicsPipelineSprite3D() -{ - loader.execute(this); -} - -GraphicsPipelineSprite3D::~GraphicsPipelineSprite3D() -{ - loader.revert(this); -} - -void -GraphicsPipelineSprite3D::draw( - std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const uint32_t image_index) -{ - vkCmdBindPipeline( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - this->graphic_pipeline); - - std::vector sprite_3d_order; - { // Sort sprites 3D - sprite_3d_order.reserve( - cg_core.vk_renderer->sprites_3d_to_draw[current_frame].size()); - - for(std::shared_ptr sprite: - cg_core.vk_renderer->sprites_3d_to_draw[current_frame]) - sprite_3d_order.emplace_back( - sprite, glm::distance(*view->camera_position, *sprite->position)); - - std::sort(sprite_3d_order.rbegin(), sprite_3d_order.rend()); - } - - // Draw sprites - for(auto& sprite: sprite_3d_order) - { - std::array vk_descriptor_sets{ - cg_core.vk_light->descriptor_sets_world[image_index], - view->descriptor_sets_3d[image_index], - sprite.sprite_3d->descriptor_sets[image_index], - sprite.sprite_3d->sprite->texture->descriptor_sets[image_index]}; - VkDeviceSize offsets[]{0}; - - vkCmdBindVertexBuffers( - draw_command_buffer, 0, 1, - &sprite.sprite_3d->sprite->vertex_buffer->buffer, offsets); - vkCmdBindDescriptorSets( - draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, - vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); - - UDOSprite3D ubo_sprite_3d{}; - ubo_sprite_3d.position = *sprite.sprite_3d->position; - ubo_sprite_3d.size = sprite.sprite_3d->size; - sprite.sprite_3d->uniform_buffers[image_index].copy_data(&ubo_sprite_3d); - - vkCmdDraw(draw_command_buffer, Sprite::vertex_count, 1, 0, 0); - } -} - -} diff --git a/src/vk/graphics_pipeline_sprite_3d.hpp b/src/vk/graphics_pipeline_sprite_3d.hpp deleted file mode 100644 index eb7aa34..0000000 --- a/src/vk/graphics_pipeline_sprite_3d.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_SPRITE_3D_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_SPRITE_3D_H 1 - -#include - -#include "core.hpp" -#include "command_pool.hpp" -#include "sprite_3d.hpp" -#include "view_3d.hpp" - -namespace VK -{ - -struct GraphicsPipelineSprite3D -{ - VkPipeline graphic_pipeline; - - GraphicsPipelineSprite3D(); - ~GraphicsPipelineSprite3D(); - - void - draw(std::shared_ptr view, const VkCommandBuffer draw_command_buffer, - const size_t current_frame, const uint32_t image_index); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_SPRITE_3D_H */ diff --git a/src/vk/image.cpp b/src/vk/image.cpp deleted file mode 100644 index 7d751c8..0000000 --- a/src/vk/image.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "image.hpp" - -#include "../core.hpp" - -namespace VK::Image -{ - -Error::Error(const std::string &m): - error(m) -{ -} - -Error::Error(const char &m): - Error{std::string{m}} -{ -} - -const char* -Error::what() const noexcept -{ - return this->error.c_str(); -} - -void -create( - VK::Device *device, - VkImage *image, - VkDeviceMemory *image_memory, - VkFormat format, - const VkExtent3D &extent3d, - uint32_t mip_levels, - VkImageTiling image_tiling, - VkImageUsageFlags usage) -{ - VkImageCreateInfo image_info{}; - image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_info.pNext = nullptr; - image_info.flags = 0; - image_info.imageType = VK_IMAGE_TYPE_2D; - image_info.format = format; - image_info.extent = extent3d; - image_info.mipLevels = mip_levels; - image_info.arrayLayers = 1; - image_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_info.tiling = image_tiling; - image_info.usage = usage; - image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - image_info.queueFamilyIndexCount = 0; - image_info.pQueueFamilyIndices = nullptr; - image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - if(vkCreateImage( - device->device, &image_info, nullptr, image) != VK_SUCCESS) - throw Error{"Failed to create Vulkan image."}; - - VkMemoryRequirements memory_requirements; - vkGetImageMemoryRequirements(device->device, *image, &memory_requirements); - - VkMemoryAllocateInfo memory_alloc_info{}; - memory_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_alloc_info.allocationSize = memory_requirements.size; - device->select_memory_type(&memory_alloc_info.memoryTypeIndex, - &memory_requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - if(vkAllocateMemory( - device->device, &memory_alloc_info, nullptr, image_memory) - != VK_SUCCESS) - { - vkDestroyImage(device->device, *image, nullptr); - throw Error{"Failed to allocate memory for Vulkan image."}; - } - - vkBindImageMemory(device->device, *image, *image_memory, 0); -} - -void move_image_state( - VkCommandBuffer vk_command_buffer, VkImage vk_image, VkFormat format, - VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask, - VkImageLayout old_layout, VkImageLayout new_layout, - VkPipelineStageFlags source_stage, VkPipelineStageFlags destination_stage) -{ - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.pNext = nullptr; - barrier.srcAccessMask = src_access_mask; - barrier.dstAccessMask = dst_access_mask; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = vk_image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - vkCmdPipelineBarrier( - vk_command_buffer, source_stage, destination_stage, 0, 0, nullptr, - 0, nullptr, 1, &barrier); -} - -void create_view( - VK::Device *device, - VkImageView *image_view, - const VkImage &image, - VkFormat format, - VkImageAspectFlags image_aspect_flags) -{ - VkImageViewCreateInfo image_view_info{}; - image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - image_view_info.pNext = nullptr; - image_view_info.flags = 0; - image_view_info.image = image; - image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - image_view_info.format = format; - image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_info.subresourceRange.aspectMask = image_aspect_flags; - image_view_info.subresourceRange.baseMipLevel = 0; - image_view_info.subresourceRange.levelCount = 1; - image_view_info.subresourceRange.baseArrayLayer = 0; - image_view_info.subresourceRange.layerCount = 1; - - if(vkCreateImageView(device->device, &image_view_info, - nullptr, image_view) != VK_SUCCESS) - throw Error{"Failed to create texture view."}; - -} - -} diff --git a/src/vk/image.hpp b/src/vk/image.hpp deleted file mode 100644 index 4849038..0000000 --- a/src/vk/image.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef BLUE_KITTY_VK_IMAGE_H -#define BLUE_KITTY_VK_IMAGE_H 1 - -#include -#include - -#include "core.hpp" -#include "device.hpp" - -namespace VK::Image -{ - -struct Error: public std::exception -{ - Error(const std::string &m); - Error(const char &m); - - const char* - what() const noexcept; - -private: - std::string error; -}; - -void -create( - VK::Device *device, - VkImage *image, - VkDeviceMemory *image_memory, - VkFormat format, - const VkExtent3D &extent3d, - uint32_t mip_levels, - VkImageTiling image_tiling, - VkImageUsageFlags usage); - -void -move_image_state( - VkCommandBuffer vk_command_buffer, - VkImage vk_image, - VkFormat format, - VkAccessFlags src_access_mask, - VkAccessFlags dst_access_mask, - VkImageLayout old_layout, - VkImageLayout new_layout, - VkPipelineStageFlags source_stage, - VkPipelineStageFlags destination_stage); - -void -create_view( - VK::Device *device, - VkImageView *image_view, - const VkImage &image, - VkFormat format, - VkImageAspectFlags image_aspect_flags); -} - -#endif /* CANDY_GEAR_VK_IMAGE_H */ diff --git a/src/vk/light.cpp b/src/vk/light.cpp deleted file mode 100644 index 5ed07ee..0000000 --- a/src/vk/light.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "light.hpp" - -#include - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_world_vert_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->ub_world_vert.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->ub_world_vert.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOWorld3D_Vert)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_world_vert_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - self->ub_world_vert.clear(); -} - -void -load_world_frag_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->ub_world_frag.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->ub_world_frag.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOWorld3D_Frag)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_world_frag_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - self->ub_world_frag.clear(); -} - -void -load_descriptor_pool(void *obj) -{ - auto self = static_cast(obj); - - uint32_t uniform_buffers_count = - self->ub_world_vert.size() + self->ub_world_vert.size(); - - VkDescriptorPoolSize descriptor_pool_size{}; - descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_pool_size.descriptorCount = uniform_buffers_count; - - VkDescriptorPoolCreateInfo pool_info{}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.pNext = nullptr; - pool_info.flags = 0; - pool_info.maxSets = uniform_buffers_count; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &descriptor_pool_size; - - if(vkCreateDescriptorPool( - cg_core.vk_device_with_swapchain->device, &pool_info, nullptr, - &self->descriptor_pool) != VK_SUCCESS) - throw CommandError{"Failed to create a Vulkan descriptor pool."}; -} - -void -unload_descriptor_pool(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorPool( - cg_core.vk_device_with_swapchain->device, self->descriptor_pool, - nullptr); -} - -void -load_descriptor_sets_world(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->world); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets_world.resize(layouts.size()); - if(vkAllocateDescriptorSets( - cg_core.vk_device_with_swapchain->device, &alloc_info, - self->descriptor_sets_world.data()) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan world descriptor set."}; -} - -void -load_resources_to_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - { - VkDescriptorBufferInfo world_vert_info{}; - world_vert_info.buffer = self->ub_world_vert[i].buffer; - world_vert_info.offset = 0; - world_vert_info.range = sizeof(VK::UDOWorld3D_Vert); - - VkDescriptorBufferInfo world_frag_info{}; - world_frag_info.buffer = self->ub_world_frag[i].buffer; - world_frag_info.offset = 0; - world_frag_info.range = sizeof(VK::UDOWorld3D_Frag); - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets_world[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[0].pBufferInfo = &world_vert_info; - write_descriptors[0].pImageInfo = nullptr; - write_descriptors[0].pTexelBufferView = nullptr; - - write_descriptors[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[1].dstSet = self->descriptor_sets_world[i]; - write_descriptors[1].dstBinding = 1; - write_descriptors[1].dstArrayElement = 0; - write_descriptors[1].descriptorCount = 1; - write_descriptors[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[1].pBufferInfo = &world_frag_info; - write_descriptors[1].pImageInfo = nullptr; - write_descriptors[1].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - } -} - -const CommandChain loader{ - {&load_world_vert_uniform_buffer, &unload_world_vert_uniform_buffer}, - {&load_world_frag_uniform_buffer, &unload_world_frag_uniform_buffer}, - {&load_descriptor_pool, &unload_descriptor_pool}, - // By destroying the pool the sets are also destroyed. - {&load_descriptor_sets_world, nullptr}, - {&load_resources_to_descriptor_sets, nullptr} -}; - -} - -namespace VK -{ - -Light::Light() -{ - loader.execute(this); -} - -Light::~Light() -{ - loader.revert(this); -} - -} diff --git a/src/vk/light.hpp b/src/vk/light.hpp deleted file mode 100644 index 80e44c7..0000000 --- a/src/vk/light.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_LIGHT_H -#define CANDY_GEAR_VK_LIGHT_H 1 - -#include "core.hpp" -#include "uniform_buffer.hpp" - -namespace VK -{ - -struct Light -{ - // FIXME: if this vector get resized, it will cause a segmentation fault! - std::vector ub_world_vert; - std::vector ub_world_frag; - - VkDescriptorPool descriptor_pool; - std::vector descriptor_sets_world; - - Light(); - ~Light(); -}; - -} - -#endif /* CANDY_GEAR_VK_LIGHT_H */ diff --git a/src/vk/qoi.cpp b/src/vk/qoi.cpp deleted file mode 100644 index bc0caab..0000000 --- a/src/vk/qoi.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "qoi.hpp" - -#include -#include - -#include "../binary_reader.hpp" - -namespace -{ - -const char MAGIC[]{"qoif"}; -const int HEADER_SIZE{14}; -const uint8_t PADDING[8]{0,0,0,0,0,0,0,1}; -const unsigned int PIXELS_MAX{400000000}; - -const int OP_INDEX{0b00000000}; -const int OP_DIFF {0b01000000}; -const int OP_LUMA {0b10000000}; -const int OP_RUN {0b11000000}; -const int OP_RGB {0b11111110}; -const int OP_RGBA {0b11111111}; - -const int MASK_2_BITS{0b11000000}; - -struct RGBA -{ - uint8_t red, green, blue, alpha; - - RGBA(); - RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); -}; - -RGBA::RGBA(): - red{0}, - green{0}, - blue{0}, - alpha{0} -{ -} - -RGBA::RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha): - red{red}, - green{green}, - blue{blue}, - alpha{alpha} -{ -} - -struct Pixel -{ - union - { - RGBA colors; - uint32_t value; - }; - - Pixel(); - Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); -}; - -Pixel::Pixel(): - colors{} -{ -} - -Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha): - colors(red, green, blue, alpha) -{ -} - -inline int -color_hash(const RGBA &colors) -{ - return colors.red*3 + colors.green*5 + colors.blue*7 + colors.alpha*11; -} - -} - -namespace VK::QOI -{ - -Image::Image(const char *file_path, uint8_t channels): - channels{channels} -{ - if(this->channels != 0 && this->channels != 3 && this->channels != 4) - { - throw std::invalid_argument{"invalid number of channels"}; - } - - BinaryReader input{file_path}; - if(input.size() < HEADER_SIZE + (int)sizeof(PADDING)) - { - throw std::runtime_error{"invalid QOI file"}; - } - - input.read_chars(this->header.magic, 4); - this->header.width = input.read_ui32(); - this->header.height = input.read_ui32(); - this->header.channels = input.read_ui8(); - this->header.colorspace = input.read_ui8(); - - if(this->header.width == 0 || this->header.height == 0 || - this->header.channels < 3 || this->header.channels > 4 || - this->header.colorspace > 1 || - this->header.height >= PIXELS_MAX / this->header.width) - { - throw std::runtime_error{"QOI file have an invalid header"}; - } - - if(this->channels == 0) this->channels = this->header.channels; - - uint32_t num_pixels{this->header.width * this->header.height}; - this->pixels_len = num_pixels * this->channels; - this->pixels = new uint8_t[this->pixels_len]; - - std::array index; - Pixel pixel(0, 0, 0, 255); - int chunks_len = input.size() - (int)sizeof(PADDING); - - /* - This algorithm is based on the original implementation that is in GitHub: - https://github.com/phoboslab/qoi - - For information about the QOI image format, see: https://qoiformat.org/ - */ - int pixel_p{0}; - int run{0}; - for(uint32_t decoded_pixel{0}; decoded_pixel < num_pixels; decoded_pixel++) - { - if(run > 0) - { - run--; - } - else if(input.pointer() < chunks_len) - { - int b1 = input.read_ui8(); - - if (b1 == OP_RGB) - { - pixel.colors.red = input.read_ui8(); - pixel.colors.green = input.read_ui8(); - pixel.colors.blue = input.read_ui8(); - } - else if (b1 == OP_RGBA) - { - pixel.colors.red = input.read_ui8(); - pixel.colors.green = input.read_ui8(); - pixel.colors.blue = input.read_ui8(); - pixel.colors.alpha = input.read_ui8(); - } - else if ((b1 & MASK_2_BITS) == OP_INDEX) - { - pixel = index[b1]; - } - else if ((b1 & MASK_2_BITS) == OP_DIFF) - { - pixel.colors.red += ((b1 >> 4) & 0x03) - 2; - pixel.colors.green += ((b1 >> 2) & 0x03) - 2; - pixel.colors.blue += (b1 & 0x03) - 2; - } - else if ((b1 & MASK_2_BITS) == OP_LUMA) - { - int b2 = input.read_ui8(); - int vg = (b1 & 0x3f) - 32; - pixel.colors.red += vg - 8 + ((b2 >> 4) & 0x0f); - pixel.colors.green += vg; - pixel.colors.blue += vg - 8 + (b2 & 0x0f); - } - else if ((b1 & MASK_2_BITS) == OP_RUN) - { - run = (b1 & 0x3f); - } - - index[color_hash(pixel.colors) % 64] = pixel; - } - - this->pixels[pixel_p++] = pixel.colors.red; - this->pixels[pixel_p++] = pixel.colors.green; - this->pixels[pixel_p++] = pixel.colors.blue; - if(this->channels == 4) this->pixels[pixel_p++] = pixel.colors.alpha; - } -} - -Image::~Image() -{ - delete[] this->pixels; -} - -} diff --git a/src/vk/qoi.hpp b/src/vk/qoi.hpp deleted file mode 100644 index 8a8688f..0000000 --- a/src/vk/qoi.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -namespace VK::QOI -{ - struct Header - { - char magic[4]; - uint32_t width; - uint32_t height; - uint8_t channels; - uint8_t colorspace; - }; - - struct Image - { - Header header; - uint32_t pixels_len; - uint8_t channels; - uint8_t *pixels; - - Image(const char *file_path, uint8_t channels); - ~Image(); - }; - -} diff --git a/src/vk/queue.cpp b/src/vk/queue.cpp deleted file mode 100644 index deb59ba..0000000 --- a/src/vk/queue.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "queue.hpp" - -#include "queue_family.hpp" - -namespace VK -{ - -Queue::Queue( - VK::QueueFamily *queue_family, VkQueue queue, int queue_index): - queue_family{queue_family}, - queue{queue}, - queue_index{queue_index} -{ - this->queue_family->queue_states[this->queue_index].busy = true; -} - -Queue::Queue(Queue &&that): - queue{that.queue}, - queue_family{that.queue_family}, - queue_index{that.queue_index} -{ - that.queue_family = nullptr; -} - -Queue& Queue::operator=(Queue &&that) -{ - this->queue = that.queue; - this->queue_family = that.queue_family; - this->queue_index = that.queue_index; - - that.queue_family = nullptr; - - return *this; -} - -Queue::~Queue() -{ - if(this->queue_family) - { - std::unique_lock lock{this->queue_family->queue_mutex}; - this->queue_family->queue_states[this->queue_index].busy = false; - } -} - -} diff --git a/src/vk/queue.hpp b/src/vk/queue.hpp deleted file mode 100644 index 955daa5..0000000 --- a/src/vk/queue.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_QUEUE_H -#define CANDY_GEAR_VK_QUEUE_H 1 - -#include "core.hpp" - -namespace VK -{ -class QueueFamily; - -struct Queue -{ - friend class VK::QueueFamily; - - Queue(const Queue &t) = delete; - Queue& operator=(const Queue &t) = delete; - - VkQueue queue; - - template - void submit_one_time_command( - const VkCommandBuffer vk_command_buffer, T commands); - - Queue(Queue &&that); - Queue& operator=(Queue &&that); - - ~Queue(); - -private: - VK::QueueFamily *queue_family; - int queue_index; - - Queue(VK::QueueFamily *queue_family, VkQueue queue, int queue_index); -}; - -template void -Queue::submit_one_time_command( - const VkCommandBuffer vk_command_buffer, T commands) -{ - VkCommandBufferBeginInfo buffer_begin_info{}; - buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - vkBeginCommandBuffer(vk_command_buffer, &buffer_begin_info); - - commands(); - - vkEndCommandBuffer(vk_command_buffer); - - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = nullptr; - submit_info.pWaitDstStageMask = nullptr; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &vk_command_buffer; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; - - vkQueueSubmit(this->queue, 1, &submit_info, VK_NULL_HANDLE); - vkQueueWaitIdle(this->queue); -} - -} - -#endif /* CANDY_GEAR_VK_QUEUE_H */ diff --git a/src/vk/queue_family.cpp b/src/vk/queue_family.cpp deleted file mode 100644 index d917c13..0000000 --- a/src/vk/queue_family.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "queue_family.hpp" - -#ifdef DEBUG -#include -#endif - -#include "../core.hpp" - -namespace VK -{ - -QueueFamily::QueueFamily( - VK::Device *device, uint32_t family_index, - const VkQueueFamilyProperties &queue_family_properties): - queue_mutex{} -{ - -#ifdef DEBUG - std::stringstream message{}; - message << "Queue quantity: " << queue_family_properties.queueCount << - std::endl; - message << "Graphics: " << - (queue_family_properties.queueFlags & VK_QUEUE_GRAPHICS_BIT ? - "true" : "false") << std::endl; - message << "Compute: " << - (queue_family_properties.queueFlags & VK_QUEUE_COMPUTE_BIT ? - "true" : "false") << std::endl; - message << "Transfer: " << - (queue_family_properties.queueFlags & VK_QUEUE_TRANSFER_BIT ? - "true" : "false") << std::endl; - message << "Sparse Binding: " << - (queue_family_properties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT ? - "true" : "false") << std::endl; - cg_core.log.message(Log::Level::Trace, message.str()); -#endif - - this->device = device; - this->family_index = family_index; - this->family_properties = queue_family_properties; - - // Create queues - { - auto queue_count = this->family_properties.queueCount; - this->queue_states.resize(queue_count); - - for(auto i{0}; i < queue_count; i++) - { - vkGetDeviceQueue(device->device, this->family_index, i, - &this->queue_states[i].queue); - if(this->queue_states[i].queue == VK_NULL_HANDLE) - throw std::runtime_error("Failed to get Vulkan queue."); - } - } -} - -Queue -QueueFamily::get_queue() -{ - std::unique_lock lock{this->queue_mutex}; - - for(auto i{0}; i < this->queue_states.size(); i++) - if(!this->queue_states[i].busy) - return Queue(this, this->queue_states[i].queue, i); - - throw std::length_error("No free queues found."); -} - -} diff --git a/src/vk/queue_family.hpp b/src/vk/queue_family.hpp deleted file mode 100644 index 83efc00..0000000 --- a/src/vk/queue_family.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_QUEUE_FAMILY_H -#define CANDY_GEAR_VK_QUEUE_FAMILY_H 1 - -#include -#include - -#include "core.hpp" -#include "queue.hpp" - -namespace VK -{ -class Device; - -struct QueueState -{ - VkQueue queue; - bool busy; -}; - -class QueueFamily -{ - friend class Queue; - - std::mutex queue_mutex; - std::vector queue_states; - -public: - VK::Device *device; - - uint32_t family_index; - VkQueueFamilyProperties family_properties; - - QueueFamily(VK::Device *device, uint32_t family_index, - const VkQueueFamilyProperties &queue_family_properties); - - Queue - get_queue(); -}; - -} - -#endif /* CANDY_GEAR_VK_QUEUE_FAMILY_H */ diff --git a/src/vk/rectangle.cpp b/src/vk/rectangle.cpp deleted file mode 100644 index dc18c45..0000000 --- a/src/vk/rectangle.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "rectangle.hpp" - -namespace VK -{ - -const int Rectangle::VertexCount{4}; - -Rectangle::Rectangle(glm::vec4 position, glm::vec3 color): - position{position}, - color{color} -{ -} - -} diff --git a/src/vk/rectangle.hpp b/src/vk/rectangle.hpp deleted file mode 100644 index faee927..0000000 --- a/src/vk/rectangle.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_RECTANGLE_H -#define CANDY_GEAR_VK_RECTANGLE_H 1 - -#include - -#include "core.hpp" -#include "destination_buffer.hpp" -#include "queue_family.hpp" -#include "uniform_buffer.hpp" - -namespace VK -{ - -struct Rectangle -{ - static const int VertexCount; - - glm::vec4 position; - glm::vec3 color; - - Rectangle(glm::vec4 position, glm::vec3 color); -}; - -} - -#endif /* CANDY_GEAR_VK_RECTANGLE_H */ diff --git a/src/vk/render_pass.cpp b/src/vk/render_pass.cpp deleted file mode 100644 index 799cde4..0000000 --- a/src/vk/render_pass.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "render_pass.hpp" - -#include - -#include "../core.hpp" - -namespace -{ - -void -load_3d(void *obj) -{ - auto self = static_cast(obj); - - std::array attachments{}; - // Color attachment. - attachments[0].flags = 0; - attachments[0].format = cg_core.vk_swapchain->image_format; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - // Depth attachment. - attachments[1].flags = 0; - attachments[1].format = VK_FORMAT_D32_SFLOAT; - attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments[1].finalLayout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkAttachmentReference color_attachment_ref{}; - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference depth_attachment_ref{}; - depth_attachment_ref.attachment = 1; - depth_attachment_ref.layout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.flags = 0; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = nullptr; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment_ref; - subpass.pResolveAttachments = nullptr; - subpass.pDepthStencilAttachment = &depth_attachment_ref; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = nullptr; - - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkRenderPassCreateInfo render_pass_info{}; - render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - render_pass_info.pNext = nullptr; - render_pass_info.flags = 0; - render_pass_info.attachmentCount = attachments.size(); - render_pass_info.pAttachments = attachments.data(); - render_pass_info.subpassCount = 1; - render_pass_info.pSubpasses = &subpass; - render_pass_info.dependencyCount = 1; - render_pass_info.pDependencies = &dependency; - - if(vkCreateRenderPass( - cg_core.vk_device_with_swapchain->device, &render_pass_info, nullptr, - &self->pipeline_3d) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan Render Pass 3D."}; -} - -void -unload_3d(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyRenderPass( - cg_core.vk_device_with_swapchain->device, self->pipeline_3d, nullptr); -} - -void -load_2d(void *obj) -{ - auto self = static_cast(obj); - - std::array attachments{}; - // Color attachment. - attachments[0].flags = 0; - attachments[0].format = cg_core.vk_swapchain->image_format; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference color_attachment_ref{}; - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass{}; - subpass.flags = 0; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = nullptr; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment_ref; - subpass.pResolveAttachments = nullptr; - subpass.pDepthStencilAttachment = nullptr; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = nullptr; - - VkSubpassDependency dependency{}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkRenderPassCreateInfo render_pass_info{}; - render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - render_pass_info.pNext = nullptr; - render_pass_info.flags = 0; - render_pass_info.attachmentCount = attachments.size(); - render_pass_info.pAttachments = attachments.data(); - render_pass_info.subpassCount = 1; - render_pass_info.pSubpasses = &subpass; - render_pass_info.dependencyCount = 1; - render_pass_info.pDependencies = &dependency; - - if(vkCreateRenderPass( - cg_core.vk_device_with_swapchain->device, &render_pass_info, - nullptr, &self->pipeline_2d) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan Render Pass 2D."}; -} - -void -unload_2d(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyRenderPass( - cg_core.vk_device_with_swapchain->device, self->pipeline_2d, nullptr); -} - -const CommandChain loader{ - {&load_3d, &unload_3d}, - {&load_2d, &unload_2d} -}; - -} - -namespace VK -{ - -RenderPass::RenderPass() -{ - loader.execute(this); -} - -RenderPass::~RenderPass() -{ - loader.revert(this); -} - -} diff --git a/src/vk/render_pass.hpp b/src/vk/render_pass.hpp deleted file mode 100644 index 2f96062..0000000 --- a/src/vk/render_pass.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_RENDER_PASS_H -#define CANDY_GEAR_VK_RENDER_PASS_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct RenderPass -{ - VkRenderPass pipeline_2d; - VkRenderPass pipeline_3d; - - RenderPass(); - ~RenderPass(); -}; - -} - -#endif /* CANDY_GEAR_VK_RENDER_PASS_H */ diff --git a/src/vk/renderer.cpp b/src/vk/renderer.cpp deleted file mode 100644 index 0f7f804..0000000 --- a/src/vk/renderer.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "renderer.hpp" - -#include - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_descriptor_pool(void *obj) -{ - auto self = static_cast(obj); - - uint32_t uniform_buffer_count = 0; - for(auto &view : self->views_3d) - uniform_buffer_count += (view->ub_3d.size() + view->ub_2d.size()); - for(auto &view : self->views_2d) - uniform_buffer_count += (view->ub_2d.size()); - - VkDescriptorPoolSize descriptor_pool_size{}; - descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_pool_size.descriptorCount = uniform_buffer_count; - - VkDescriptorPoolCreateInfo pool_info{}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.pNext = nullptr; - pool_info.flags = 0; - pool_info.maxSets = uniform_buffer_count; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &descriptor_pool_size; - - if(vkCreateDescriptorPool( - cg_core.vk_device_with_swapchain->device, &pool_info, nullptr, - &self->descriptor_pool) != VK_SUCCESS) - throw CommandError{"Failed to create a Vulkan descriptor pool."}; - - for(auto &view : self->views_3d) - view->load_descriptor_sets(self->descriptor_pool); - for(auto &view : self->views_2d) - view->load_descriptor_sets(self->descriptor_pool); -} - -void -unload_descriptor_pool(void *obj) -{ - auto self = static_cast(obj); - - for(auto &view : self->views_3d) view->unload_descriptor_sets(); - for(auto &view : self->views_2d) view->unload_descriptor_sets(); - - vkDestroyDescriptorPool( - cg_core.vk_device_with_swapchain->device, self->descriptor_pool, - nullptr); -} - -void -load_queue_family(void *obj) -{ - auto self = static_cast(obj); - - self->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_presentation(); -} - -void -load_command_pool(void *obj) -{ - auto self = static_cast(obj); - - VkCommandPoolCreateInfo create_info{}; - create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - create_info.pNext = nullptr; - create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - create_info.queueFamilyIndex = self->queue_family->family_index; - - vkCreateCommandPool( - self->queue_family->device->device, &create_info, nullptr, - &self->command_pool); -} - -void -unload_command_pool(void *obj) -{ - auto self = static_cast(obj); - - vkWaitForFences(cg_core.vk_device_with_swapchain->device, - VK::Swapchain::max_frames_in_flight, - cg_core.vk_swapchain->in_flight_fences.data(), VK_TRUE, - std::numeric_limits::max()); - vkDestroyCommandPool( - self->queue_family->device->device, self->command_pool, nullptr); -} - -void -load_draw_command_buffer(void *obj) -{ - auto self = static_cast(obj); - - // FIXME: 3 is a magical number, triple buffering. - self->draw_command_buffers.resize(3); - - VkCommandBufferAllocateInfo allocate_info{}; - allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocate_info.pNext = nullptr; - allocate_info.commandPool = self->command_pool; - allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocate_info.commandBufferCount = self->draw_command_buffers.size(); - - if(vkAllocateCommandBuffers( - self->queue_family->device->device, &allocate_info, - self->draw_command_buffers.data()) != VK_SUCCESS) - throw CommandError{"Vulkan draw command buffers could not be allocated."}; -} - -const CommandChain loader{ - {&load_descriptor_pool, &unload_descriptor_pool}, - {&load_queue_family, nullptr}, - {&load_command_pool, &unload_command_pool}, - {&load_draw_command_buffer, nullptr} -}; - -} - -namespace VK -{ - -Renderer::Renderer(std::vector> views_2d, - std::vector> views_3d): - skeletal_models_to_draw{cg_core.vk_swapchain->images_count}, - static_models_to_draw{cg_core.vk_swapchain->images_count}, - sprites_3d_to_draw{cg_core.vk_swapchain->images_count}, - views_2d{views_2d}, - views_3d{views_3d} -{ - loader.execute(this); -} - -Renderer::Renderer(std::initializer_list> views_2d, - std::initializer_list> views_3d): - Renderer(std::vector(views_2d), std::vector(views_3d)) -{ -} - -Renderer::~Renderer() -{ - loader.revert(this); -} - -void -Renderer::draw() -{ - auto fence_status = vkGetFenceStatus( - cg_core.vk_device_with_swapchain->device, - cg_core.vk_swapchain->in_flight_fences[ - cg_core.vk_swapchain->current_frame]); - - if(fence_status == VK_SUCCESS) - { - auto next_frame = cg_core.vk_swapchain->current_frame + 1; - if(next_frame == Swapchain::max_frames_in_flight) next_frame = 0; - - vkResetFences(cg_core.vk_device_with_swapchain->device, 1, - &cg_core.vk_swapchain->in_flight_fences[ - cg_core.vk_swapchain->current_frame]); - - uint32_t image_index; - vkAcquireNextImageKHR( - cg_core.vk_device_with_swapchain->device, - cg_core.vk_swapchain->swapchain, std::numeric_limits::max(), - cg_core.vk_swapchain->image_available_semaphores[ - cg_core.vk_swapchain->current_frame], VK_NULL_HANDLE, &image_index); - - VkCommandBuffer draw_command_buffer = - this->draw_command_buffers[cg_core.vk_swapchain->current_frame]; - vkResetCommandBuffer(draw_command_buffer, 0); - - // Begin command buffer. - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.flags = 0; - begin_info.pInheritanceInfo = nullptr; - if (vkBeginCommandBuffer(draw_command_buffer, &begin_info) != VK_SUCCESS) - throw std::runtime_error{"Failed to beggin draw command buffer."}; - } - - // 3D drawing. - { - // Dark gray blue. - std::array clear_values{}; - clear_values[0].color = {0.12f, 0.12f, 0.18f, 1.0f}; - clear_values[1].depthStencil = {1.0f, 0}; - - { // Update world uniform buffer - UDOWorld3D_Vert ubo_world_3d_vert{}; - ubo_world_3d_vert.ambient_light_color = - glm::vec4{0.25, 0.25, 0.25, 1.0}; - cg_core.vk_light->ub_world_vert[image_index].copy_data( - &ubo_world_3d_vert); - - UDOWorld3D_Frag ubo_world_3d_frag{}; - ubo_world_3d_frag.directional_light_direction = - glm::vec3{-0.57735, 0.57735, -0.57735}; - ubo_world_3d_frag.directional_light_color = - glm::vec4{0.8, 0.8, 0.8, 1.0}; - cg_core.vk_light->ub_world_frag[image_index].copy_data( - &ubo_world_3d_frag); - } - - VkRenderPassBeginInfo render_pass_begin{}; - render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin.pNext = nullptr; - render_pass_begin.renderPass = cg_core.vk_render_pass->pipeline_3d; - render_pass_begin.framebuffer = - cg_core.vk_framebuffer->pipeline_3d[image_index]; - render_pass_begin.renderArea.offset = {0, 0}; - render_pass_begin.renderArea.extent = { - static_cast(cg_core.display_width), - static_cast(cg_core.display_height)}; - render_pass_begin.clearValueCount = clear_values.size(); - render_pass_begin.pClearValues = clear_values.data(); - - vkCmdBeginRenderPass( - draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); - } - - for(auto &view: this->views_3d) - { - { // Set viewport - VkViewport vk_viewport{}; - vk_viewport.x = view->region.x; - vk_viewport.y = view->region.y; - vk_viewport.width = view->region.z; - vk_viewport.height = view->region.w; - vk_viewport.minDepth = 0.0f; - vk_viewport.maxDepth = 1.0f; - vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); - - VkRect2D vk_scissor{}; - vk_scissor.offset.x = static_cast(view->region.x); - vk_scissor.offset.y = static_cast(view->region.y); - vk_scissor.extent.width = static_cast(view->region.z); - vk_scissor.extent.height = static_cast(view->region.w); - vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); - } - - cg_core.vk_graphics_pipeline_3d->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - image_index); - - cg_core.vk_graphics_pipeline_sprite_3d->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - image_index); - - cg_core.vk_graphics_pipeline_3d_skeletal->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - image_index); - - { // Update view uniform buffers - VK::UDOView3D ubo_view_3d{}; - - // View matrix. - glm::mat4 translation_matrix{1.0f}; - translation_matrix = glm::translate( - translation_matrix, *view->camera_position); - glm::mat4 rotation_matrix{glm::toMat4(*view->camera_orientation)}; - ubo_view_3d.view = glm::inverse(translation_matrix * rotation_matrix); - - // Projection matrix. - ubo_view_3d.proj = glm::perspective( - glm::radians(view->field_of_view), - view->region.z / view->region.w, - 0.1f, 100.0f); - - view->ub_3d[image_index].copy_data(&ubo_view_3d); - } - } - - vkCmdEndRenderPass(draw_command_buffer); - - { // 2D render pass - VkRenderPassBeginInfo render_pass_begin{}; - render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin.pNext = nullptr; - render_pass_begin.renderPass = cg_core.vk_render_pass->pipeline_2d; - render_pass_begin.framebuffer = - cg_core.vk_framebuffer->pipeline_2d[image_index]; - render_pass_begin.renderArea.offset = {0, 0}; - render_pass_begin.renderArea.extent = { - static_cast(cg_core.display_width), - static_cast(cg_core.display_height)}; - render_pass_begin.clearValueCount = 0; - render_pass_begin.pClearValues = nullptr; - - vkCmdBeginRenderPass( - draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); - - } - - { // 2D solid drawing - for(auto &view: this->views_2d) - cg_core.vk_graphics_pipeline_2d_solid->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - next_frame, image_index); - - for(auto &view: this->views_3d) - cg_core.vk_graphics_pipeline_2d_solid->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - next_frame, image_index); - } - - { // 2D wired drawing - for(auto &view: this->views_2d) - cg_core.vk_graphics_pipeline_2d_wired->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - next_frame, image_index); - - for(auto &view: this->views_3d) - cg_core.vk_graphics_pipeline_2d_wired->draw( - view, draw_command_buffer, cg_core.vk_swapchain->current_frame, - next_frame, image_index); - } - - vkCmdEndRenderPass(draw_command_buffer); - - // End command buffer. - if(vkEndCommandBuffer(draw_command_buffer) != VK_SUCCESS) - throw std::runtime_error{"Failed to end draw command buffer."}; - - // Submit drawing command. - { - auto queue{this->queue_family->get_queue()}; - - VkSemaphore wait_semaphores[]{ - cg_core.vk_swapchain->image_available_semaphores[ - cg_core.vk_swapchain->current_frame]}; - VkPipelineStageFlags wait_stages[] = - {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - VkSemaphore signal_semaphores[]{ - cg_core.vk_swapchain->render_finished_semaphores[ - cg_core.vk_swapchain->current_frame]}; - - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = wait_semaphores; - submit_info.pWaitDstStageMask = wait_stages; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &draw_command_buffer; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = signal_semaphores; - - if(vkQueueSubmit( - queue.queue, 1, &submit_info, cg_core.vk_swapchain->in_flight_fences[ - cg_core.vk_swapchain->current_frame]) != VK_SUCCESS) - throw std::runtime_error{"Failed to submit draw command buffer."}; - - VkSwapchainKHR swap_chains[]{cg_core.vk_swapchain->swapchain}; - - VkPresentInfoKHR present_info{}; - present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present_info.pNext = nullptr; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = signal_semaphores; - present_info.swapchainCount = 1; - present_info.pSwapchains = swap_chains; - present_info.pImageIndices = &image_index; - present_info.pResults = nullptr; - - vkQueuePresentKHR(queue.queue, &present_info); - } - - // Prepare for the next frame. - { - this->skeletal_models_to_draw[next_frame].clear(); - this->static_models_to_draw[next_frame].clear(); - this->sprites_3d_to_draw[next_frame].clear(); - cg_core.vk_swapchain->current_frame = next_frame; - } - } - else - { - // Clear images for the current frame because we are skipping this frame. - this->skeletal_models_to_draw[cg_core.vk_swapchain->current_frame].clear(); - this->static_models_to_draw[cg_core.vk_swapchain->current_frame].clear(); - this->sprites_3d_to_draw[cg_core.vk_swapchain->current_frame].clear(); - for(auto &view: this->views_2d) - view->sprites_to_draw[cg_core.vk_swapchain->current_frame].clear(); - for(auto &view: this->views_3d) - view->sprites_to_draw[cg_core.vk_swapchain->current_frame].clear(); - } -} - -} diff --git a/src/vk/renderer.hpp b/src/vk/renderer.hpp deleted file mode 100644 index 96d25ba..0000000 --- a/src/vk/renderer.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_RENDERER_H -#define CANDY_GEAR_VK_RENDERER_H 1 - -#include -#include -#include - -#include "core.hpp" -#include "skeletal_mesh.hpp" -#include "skeletal_model.hpp" -#include "sprite_3d.hpp" -#include "static_mesh.hpp" -#include "static_model.hpp" -#include "queue_family.hpp" -#include "view_2d.hpp" -#include "view_3d.hpp" - -namespace VK -{ - -struct Renderer -{ - std::vector< - std::unordered_map< - std::shared_ptr, - std::vector>>> - skeletal_models_to_draw; - - std::vector< - std::unordered_map< - std::shared_ptr, - std::vector>>> - static_models_to_draw; - - std::vector>> sprites_3d_to_draw; - - VkDescriptorPool descriptor_pool; - std::vector> views_2d; - std::vector> views_3d; - QueueFamily *queue_family; - VkCommandPool command_pool; - std::vector draw_command_buffers; - - Renderer(std::vector> views_2d, - std::vector> views_3d); - Renderer(std::initializer_list> views_2d, - std::initializer_list> views_3d); - ~Renderer(); - - void - draw(); -}; - -} - -#endif /* CANDY_GEAR_VK_RENDERER_H */ diff --git a/src/vk/skeletal_mesh.cpp b/src/vk/skeletal_mesh.cpp deleted file mode 100644 index b65d27d..0000000 --- a/src/vk/skeletal_mesh.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "skeletal_mesh.hpp" - -#include "../binary_reader.hpp" -#include "../command.hpp" -#include "../core.hpp" -#include "skeletal_mesh_vertex.hpp" - -namespace -{ - -// Data that is only needed for the command chain but not for the SkeletalMesh -// goes here. -struct MeshBuilder -{ - std::string mesh_path; - VK::SkeletalMesh *mesh; - - MeshBuilder(VK::SkeletalMesh *m, std::string mp); - MeshBuilder(VK::SkeletalMesh *m, const char* mp); -}; - -MeshBuilder::MeshBuilder(VK::SkeletalMesh *m, std::string mp): - mesh{m}, - mesh_path{mp} -{ -} - -MeshBuilder::MeshBuilder(VK::SkeletalMesh *m, const char *mp): - MeshBuilder{m, std::string(mp)} -{ -} - -void -load_mesh(void *obj) -{ - auto self = static_cast(obj); - - BinaryReader input{self->mesh_path}; - - self->mesh->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); - - { // Load vertexes. - auto vertex_count{input.read_ui32()}; - std::vector vertexes{vertex_count}; - - for(auto i{0}; i < vertex_count; i++) - { - vertexes[i].position = input.read_vec3(); - vertexes[i].normal = input.read_vec3(); - vertexes[i].texture_coord = input.read_vec2(); - - for(auto ii{0}; ii < VK::SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES; - ii++) - vertexes[i].bone_ids[ii] = input.read_ui32(); - - for(auto ii{0}; ii < VK::SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES; - ii++) - vertexes[i].bone_weights[ii] = input.read_float(); - } - - void *vertexes_data{vertexes.data()}; - size_t vertexes_size = sizeof(vertexes[0]) * vertexes.size(); - self->mesh->source_vertex_buffer = new VK::SourceBuffer{ - self->mesh->queue_family->device, vertexes_data, vertexes_size}; - self->mesh->vertex_buffer = new VK::DestinationBuffer{ - self->mesh->queue_family, self->mesh->source_vertex_buffer, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; - } - - { // Load indexes. - self->mesh->index_count = input.read_ui32(); - std::vector indexes(self->mesh->index_count); - - for(auto i{0}; i < self->mesh->index_count; i++) - indexes[i] = input.read_ui32(); - - void *indexes_data{indexes.data()}; - size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; - VK::SourceBuffer source_index_buffer{ - self->mesh->queue_family->device, indexes_data, indexes_size}; - self->mesh->index_buffer = new VK::DestinationBuffer{ - self->mesh->queue_family, &source_index_buffer, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; - } - - { // Load bones - auto bone_count{input.read_ui32()}; - self->mesh->bones.reserve(bone_count); - for(int i{0}; i < bone_count; i++) - self->mesh->bones.emplace_back(input.read_mat4()); - } - - { // Load animations - auto num_animations{input.read_ui32()}; - self->mesh->animations.resize(num_animations); - for(uint32_t i{0}; i < num_animations; i++) - { - auto duration{input.read_double()}; - self->mesh->animations[i].final_time = (float)duration; - - auto ticks_per_second{input.read_double()}; - - auto num_bone_transforms{input.read_ui32()}; - std::vector *bone_transforms = - &(self->mesh->animations[i].bone_transforms); - bone_transforms->resize(num_bone_transforms); - for(uint32_t bone_transform_index{0}; - bone_transform_index < num_bone_transforms; bone_transform_index++) - { - auto bone_id{input.read_ui32()}; - - auto num_positions{input.read_ui32()}; - VK::Channel *positions = - &((*bone_transforms)[bone_transform_index].positions); - for(auto position_key_index{0}; position_key_index < num_positions; - position_key_index++) - { - auto vec3{input.read_vec3()}; - auto timestamp{input.read_double()}; - positions->key_frames.emplace_back( - vec3, static_cast(timestamp)); - } - - auto num_rotations{input.read_ui32()}; - VK::Channel *rotations = - &((*bone_transforms)[bone_transform_index].rotations); - for(auto rotation_key_index{0}; rotation_key_index < num_rotations; - rotation_key_index++) - { - auto quat{input.read_quat()}; - auto timestamp{input.read_double()}; - rotations->key_frames.emplace_back( - quat, static_cast(timestamp)); - } - - auto num_scales{input.read_ui32()}; - VK::Channel *scales = - &((*bone_transforms)[bone_transform_index].scales); - for(auto scaling_key_index{0}; scaling_key_index < num_scales; - scaling_key_index++) - { - auto vec3{input.read_vec3()}; - auto timestamp{input.read_double()}; - scales->key_frames.emplace_back(vec3, static_cast(timestamp)); - } - } - } - } -} - -void -unload_mesh(void *obj) -{ - auto self = static_cast(obj); - - delete self->mesh->index_buffer; - delete self->mesh->vertex_buffer; - delete self->mesh->source_vertex_buffer; -} - -static const CommandChain loader{ - {&load_mesh, &unload_mesh} -}; - -} - -namespace VK -{ - -SkeletalMesh::SkeletalMesh(std::string mesh_path) -{ - MeshBuilder mesh_builder(this, mesh_path); - loader.execute(&mesh_builder); -} - -SkeletalMesh::SkeletalMesh(const char* mesh_path): - SkeletalMesh{std::string(mesh_path)} -{ -} - -SkeletalMesh::~SkeletalMesh() -{ - MeshBuilder mesh_builder(this, ""); - loader.revert(&mesh_builder); -} - -} diff --git a/src/vk/skeletal_mesh.hpp b/src/vk/skeletal_mesh.hpp deleted file mode 100644 index 7fc8334..0000000 --- a/src/vk/skeletal_mesh.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SKELETAL_MESH_H -#define CANDY_GEAR_VK_SKELETAL_MESH_H 1 - -#include -#include - -#include "animation.hpp" -#include "core.hpp" -#include "destination_buffer.hpp" -#include "queue_family.hpp" -#include "uniform_buffer.hpp" -#include "texture.hpp" - -namespace VK -{ - -struct SkeletalMesh -{ - QueueFamily *queue_family; - - uint32_t index_count; - SourceBuffer *source_vertex_buffer; - DestinationBuffer *index_buffer; - DestinationBuffer *vertex_buffer; - - std::vector bones; - std::vector animations; - - SkeletalMesh(std::string mesh_path); - SkeletalMesh(const char* mesh_path); - ~SkeletalMesh(); -}; - -} - -#endif /* CANDY_GEAR_VK_SKELETAL_MESH_H */ diff --git a/src/vk/skeletal_mesh_vertex.hpp b/src/vk/skeletal_mesh_vertex.hpp deleted file mode 100644 index b5bba3d..0000000 --- a/src/vk/skeletal_mesh_vertex.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SKELETAL_MESH_VERTEX_H -#define CANDY_GEAR_VK_SKELETAL_MESH_VERTEX_H 1 - -#include "core.hpp" - -namespace VK -{ - -// This variable define the maximum ammount of bones that can influence a -// vertex. -const int SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES{4}; -const int SKELETAL_MESH_MAX_NUM_OF_BONES{50}; - -struct SkeletalMeshVertex -{ - glm::vec3 position; - glm::vec3 normal; - glm::vec2 texture_coord; - - uint32_t bone_ids[SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES]; - float bone_weights[SKELETAL_MESH_MAX_NUM_OF_INFLUENCING_BONES]; -}; - -} - -#endif /* CANDY_GEAR_VK_SKELETAL_MESH_VERTEX_H */ diff --git a/src/vk/skeletal_model.cpp b/src/vk/skeletal_model.cpp deleted file mode 100644 index d2739c4..0000000 --- a/src/vk/skeletal_model.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "skeletal_model.hpp" - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_uniform_buffers(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->uniform_buffers.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->uniform_buffers.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOSkeletalModel)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_uniform_buffers(void *obj) -{ - auto self = static_cast(obj); - - self->uniform_buffers.clear(); -} - -void -load_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - std::array descriptor_pool_sizes{}; - descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_pool_sizes[0].descriptorCount = - self->uniform_buffers.size(); - - VkDescriptorPoolCreateInfo pool_info{}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.pNext = nullptr; - pool_info.flags = 0; - pool_info.maxSets = self->uniform_buffers.size(); - pool_info.poolSizeCount = descriptor_pool_sizes.size(); - pool_info.pPoolSizes = descriptor_pool_sizes.data(); - - if(vkCreateDescriptorPool( - self->skeletal_mesh->queue_family->device->device, &pool_info, nullptr, - &self->descriptor_pool) != VK_SUCCESS) - throw CommandError{"Failed to create a Vulkan descriptor pool."}; -} - -void -unload_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorPool( - self->skeletal_mesh->queue_family->device->device, self->descriptor_pool, - nullptr); -} - -void -load_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->model); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets.resize(layouts.size()); - if(vkAllocateDescriptorSets( - self->skeletal_mesh->queue_family->device->device, &alloc_info, - self->descriptor_sets.data()) != VK_SUCCESS) - CommandError{"Failed to create Vulkan descriptor set."}; -} - -void -load_buffers_to_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < self->uniform_buffers.size(); i++) - { - VkDescriptorBufferInfo buffer_info{}; - buffer_info.buffer = self->uniform_buffers[i].buffer; - buffer_info.offset = 0; - buffer_info.range = sizeof(VK::UDOSkeletalModel); - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[0].pBufferInfo = &buffer_info; - write_descriptors[0].pImageInfo = nullptr; - write_descriptors[0].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - } -} - -static const CommandChain loader{ - {&load_uniform_buffers, &unload_uniform_buffers}, - {&load_descriptor_set_pool, &unload_descriptor_set_pool}, - {&load_descriptor_sets, nullptr}, - {&load_buffers_to_descriptor_sets, nullptr} -}; - -} - -namespace VK -{ - -SkeletalModel::SkeletalModel( - std::shared_ptr skeletal_mesh, - std::shared_ptr texture, std::shared_ptr position, - std::shared_ptr orientation): - skeletal_mesh{skeletal_mesh}, - texture{texture}, - position{position}, - orientation{orientation}, - animation_index{0}, - animation_time{0.0f}, - bone_transforms(SKELETAL_MESH_MAX_NUM_OF_BONES) -{ - loader.execute(this); - - for(int i{0}; i < skeletal_mesh->bones.size(); i++) - this->bone_transforms[i] = skeletal_mesh->bones[i].offset_matrix; -} - -SkeletalModel::~SkeletalModel() -{ - loader.revert(this); -} - -void -SkeletalModel::tick(float delta) -{ - VK::Animation *current_animation = - &this->skeletal_mesh->animations[this->animation_index]; - - { // update time - this->animation_time += delta; - if(this->animation_time > current_animation->final_time) - { - this->animation_time -= current_animation->final_time; - for(VK::BoneTransform &bone_transform: - current_animation->bone_transforms) - { - bone_transform.positions.current_index = 0; - bone_transform.rotations.current_index = 0; - bone_transform.scales.current_index = 0; - } - } - } - - for(int i{0}; i < current_animation->bone_transforms.size(); i++) - { - VK::BoneTransform *bone_transform = ¤t_animation->bone_transforms[i]; - - auto position{bone_transform->positions.interpolate( - this->animation_time, - [](glm::vec3 frame) - { - return glm::translate(glm::mat4(1.0f), frame); - }, - [](glm::vec3 previous_frame, glm::vec3 next_frame, float scale_factor) - { - glm::vec3 final_position{glm::mix( - previous_frame, next_frame, scale_factor)}; - return glm::translate(glm::mat4(1.0f), final_position); - })}; - - auto rotation{bone_transform->rotations.interpolate( - this->animation_time, - [](glm::quat frame) - { - return glm::toMat4(glm::normalize(frame)); - }, - [](glm::quat previous_frame, glm::quat next_frame, float scale_factor) - { - return glm::toMat4(glm::slerp( - previous_frame, next_frame, scale_factor)); - })}; - - auto scale{bone_transform->scales.interpolate( - this->animation_time, - [](glm::vec3 frame) - { - return glm::scale(glm::mat4(1.0f), frame); - }, - [](glm::vec3 previous_frame, glm::vec3 next_frame, float scale_factor) - { - glm::vec3 scale{glm::mix( - previous_frame, next_frame, scale_factor)}; - return glm::scale(glm::mat4(1.0f), scale); - })}; - - this->bone_transforms[i] = position * rotation * scale; - } -} - -} diff --git a/src/vk/skeletal_model.hpp b/src/vk/skeletal_model.hpp deleted file mode 100644 index db54ac9..0000000 --- a/src/vk/skeletal_model.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SKELETAL_MODEL_H -#define CANDY_GEAR_VK_SKELETAL_MODEL_H 1 - -#include -#include - -#include "core.hpp" -#include "skeletal_mesh.hpp" - -namespace VK -{ - -struct SkeletalModel -{ - std::shared_ptr skeletal_mesh; - std::shared_ptr texture; - std::vector uniform_buffers; - std::shared_ptr position; - std::shared_ptr orientation; - int animation_index; - float animation_time; - std::vector bone_transforms; - - VkDescriptorPool descriptor_pool; - std::vector descriptor_sets; - - SkeletalModel( - std::shared_ptr skeletal_mesh, - std::shared_ptr texture, std::shared_ptr position, - std::shared_ptr orientation); - ~SkeletalModel(); - - void - tick(float delta); -}; - -} - -#endif /* CANDY_GEAR_VK_SKELETAL_MODEL_H */ diff --git a/src/vk/source_buffer.cpp b/src/vk/source_buffer.cpp deleted file mode 100644 index f8f1aee..0000000 --- a/src/vk/source_buffer.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "source_buffer.hpp" - -#include - -namespace VK -{ - -SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size) -{ - this->device = device; - this->device_size = data_size; - this->buffer_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - this->memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - try - { - VK::BaseBuffer::loader.execute(static_cast(this)); - } - catch(const CommandError &command_error) - { - std::string error{"Could not initialize Vulkan source buffer → "}; - error += command_error.what(); - throw std::runtime_error{error}; - } - this->copy_data(data); -} - -SourceBuffer::SourceBuffer(SourceBuffer &&that) -{ - this->buffer = that.buffer; - this->device_memory = that.device_memory; - this->device_size = that.device_size; - this->buffer_usage = that.buffer_usage; - this->memory_properties = that.memory_properties; - - that.buffer = VK_NULL_HANDLE; - that.device_memory = VK_NULL_HANDLE; -} - -SourceBuffer& -SourceBuffer::operator=(SourceBuffer &&that) -{ - this->buffer = that.buffer; - this->device_memory = that.device_memory; - this->device_size = that.device_size; - this->buffer_usage = that.buffer_usage; - this->memory_properties = that.memory_properties; - - that.buffer = VK_NULL_HANDLE; - that.device_memory = VK_NULL_HANDLE; - - return *this; -} - -SourceBuffer::~SourceBuffer() -{ - VK::BaseBuffer::loader.revert(static_cast(this)); -} - -void -SourceBuffer::copy_data(void *src_data) -{ - void *dst_data; - vkMapMemory(this->device->device, this->device_memory, 0, this->device_size, - 0, &dst_data); - memcpy(dst_data, src_data, static_cast(this->device_size)); - vkUnmapMemory(this->device->device, this->device_memory); -} - -} diff --git a/src/vk/source_buffer.hpp b/src/vk/source_buffer.hpp deleted file mode 100644 index 440e561..0000000 --- a/src/vk/source_buffer.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SOURCE_BUFFER_H -#define CANDY_GEAR_VK_SOURCE_BUFFER_H 1 - -#include "base_buffer.hpp" - -namespace VK -{ - -struct SourceBuffer: public BaseBuffer -{ - SourceBuffer(const SourceBuffer &t) = delete; - SourceBuffer& - operator=(const SourceBuffer &t) = delete; - - SourceBuffer(Device *device, void *data, size_t data_size); - - SourceBuffer(SourceBuffer &&that); - SourceBuffer& - operator=(SourceBuffer &&that); - - ~SourceBuffer(); - - void - copy_data(void *src_data); -}; - -} - -#endif /* CANDY_GEAR_VK_SOURCE_BUFFER_H */ diff --git a/src/vk/sprite.cpp b/src/vk/sprite.cpp deleted file mode 100644 index 95e11a3..0000000 --- a/src/vk/sprite.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sprite.hpp" - -#include - -#include "../core.hpp" -#include "sprite.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -struct SpriteBuilder -{ - VK::Sprite *sprite; - glm::vec4 ▭ - - SpriteBuilder(VK::Sprite *sprite, glm::vec4 &rect); -}; - -SpriteBuilder::SpriteBuilder(VK::Sprite *sprite, glm::vec4 &rect): - sprite{sprite}, - rect{rect} -{ -} - -void -load_mesh(void *obj) -{ - auto self = static_cast(obj); - - self->sprite->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); - - glm::vec2 rect[VK::Sprite::vertex_count]{ - glm::vec2{self->rect.x, self->rect.y}, - glm::vec2{self->rect.x, self->rect.w}, - glm::vec2{self->rect.z, self->rect.y}, - glm::vec2{self->rect.z, self->rect.w} - }; - - void *vertexes_data{&rect}; - static const size_t vertexes_size = - sizeof(glm::vec2) * VK::Sprite::vertex_count; - self->sprite->source_buffer = new VK::SourceBuffer{ - self->sprite->queue_family->device, vertexes_data, vertexes_size}; - self->sprite->vertex_buffer = new VK::DestinationBuffer{ - self->sprite->queue_family, self->sprite->source_buffer, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; -} - -void -unload_mesh(void *obj) -{ - auto self = static_cast(obj); - - delete self->sprite->vertex_buffer; - delete self->sprite->source_buffer; -} - -static const CommandChain loader{ - {&load_mesh, &unload_mesh}, -}; - -} - -namespace VK -{ - -Sprite::Sprite(std::shared_ptr texture, glm::vec4 &rect): - texture{texture} -{ - SpriteBuilder sprite_builder(this, rect); - loader.execute(&sprite_builder); -} - -Sprite::~Sprite() -{ - glm::vec4 vector_4d{}; - SpriteBuilder sprite_builder(this, vector_4d); - loader.revert(&sprite_builder); -} - -} diff --git a/src/vk/sprite.hpp b/src/vk/sprite.hpp deleted file mode 100644 index 791144e..0000000 --- a/src/vk/sprite.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SPRITE_H -#define CANDY_GEAR_VK_SPRITE_H 1 - -#include -#include -#include - -#include "core.hpp" -#include "destination_buffer.hpp" -#include "queue_family.hpp" -#include "uniform_buffer.hpp" -#include "texture.hpp" - -namespace VK -{ - -struct Sprite -{ - static const uint32_t vertex_count{4}; - - QueueFamily *queue_family; - - SourceBuffer *source_buffer; - DestinationBuffer *vertex_buffer; - - std::shared_ptr texture; - - Sprite(std::shared_ptr texture, glm::vec4 &rect); - ~Sprite(); -}; - -} - -#endif /* CANDY_GEAR_VK_SPRITE_H */ diff --git a/src/vk/sprite_3d.cpp b/src/vk/sprite_3d.cpp deleted file mode 100644 index 66199f1..0000000 --- a/src/vk/sprite_3d.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sprite_3d.hpp" - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_uniform_buffers(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->uniform_buffers.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->uniform_buffers.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOSprite3D)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_uniform_buffers(void *obj) -{ - auto self = static_cast(obj); - - self->uniform_buffers.clear(); -} - -void -load_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - std::array descriptor_pool_sizes{}; - descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_pool_sizes[0].descriptorCount = - self->uniform_buffers.size(); - - VkDescriptorPoolCreateInfo pool_info{}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.pNext = nullptr; - pool_info.flags = 0; - pool_info.maxSets = self->uniform_buffers.size(); - pool_info.poolSizeCount = descriptor_pool_sizes.size(); - pool_info.pPoolSizes = descriptor_pool_sizes.data(); - - if(vkCreateDescriptorPool( - self->queue_family->device->device, &pool_info, nullptr, - &self->descriptor_pool) != VK_SUCCESS) - throw CommandError{"Failed to create a Vulkan descriptor pool."}; -} - -void -unload_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorPool( - self->queue_family->device->device, self->descriptor_pool, nullptr); -} -void -load_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->model); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets.resize(layouts.size()); - if(vkAllocateDescriptorSets( - self->queue_family->device->device, &alloc_info, - self->descriptor_sets.data()) != VK_SUCCESS) - CommandError{"Failed to create Vulkan descriptor set."}; -} - -void -load_buffers_to_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < self->uniform_buffers.size(); i++) - { - VkDescriptorBufferInfo buffer_info{}; - buffer_info.buffer = self->uniform_buffers[i].buffer; - buffer_info.offset = 0; - buffer_info.range = sizeof(VK::UDOSprite3D); - - VkDescriptorImageInfo image_info{}; - image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_info.imageView = self->sprite->texture->view; - image_info.sampler = self->sprite->texture->sampler; - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[0].pBufferInfo = &buffer_info; - write_descriptors[0].pImageInfo = nullptr; - write_descriptors[0].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - } -} - -static const CommandChain loader{ - {&load_uniform_buffers, &unload_uniform_buffers}, - {&load_descriptor_set_pool, &unload_descriptor_set_pool}, - {&load_descriptor_sets, nullptr}, - {&load_buffers_to_descriptor_sets, nullptr} -}; - -} - -namespace VK -{ - -Sprite3D::Sprite3D( - std::shared_ptr sprite, std::shared_ptr position, - glm::vec2 size): - sprite{sprite}, - position{position}, - size{size} -{ - this->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); - loader.execute(this); -} - -Sprite3D::~Sprite3D() -{ - loader.revert(this); -} - -} diff --git a/src/vk/sprite_3d.hpp b/src/vk/sprite_3d.hpp deleted file mode 100644 index 2059606..0000000 --- a/src/vk/sprite_3d.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SPRITE_3D_H -#define CANDY_GEAR_VK_SPRITE_3D_H 1 - -#include "core.hpp" -#include "sprite.hpp" - -namespace VK -{ - -struct Sprite3D -{ - std::shared_ptr sprite; - std::shared_ptr position; - glm::vec2 size; - - QueueFamily *queue_family; - - std::vector uniform_buffers; - VkDescriptorPool descriptor_pool; - std::vector descriptor_sets; - - Sprite3D( - std::shared_ptr sprite, std::shared_ptr position, - glm::vec2 size); - ~Sprite3D(); -}; - -} - -#endif /* CANDY_GEAR_VK_SPRITE_3D_H */ diff --git a/src/vk/sprite_to_draw.cpp b/src/vk/sprite_to_draw.cpp deleted file mode 100644 index 76ee847..0000000 --- a/src/vk/sprite_to_draw.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sprite_to_draw.hpp" - -namespace VK -{ - SpriteToDraw::SpriteToDraw( - std::shared_ptr sprite, const glm::vec4 &position, float z_index): - sprite{sprite}, - position{position}, - z_index{z_index} - { - } - - bool - operator<(const SpriteToDraw& a, const SpriteToDraw& b) - { - return a.z_index < b.z_index; - } - - bool - operator>(const SpriteToDraw& a, const SpriteToDraw& b) - { - return a.z_index > b.z_index; - } -} diff --git a/src/vk/sprite_to_draw.hpp b/src/vk/sprite_to_draw.hpp deleted file mode 100644 index 84effff..0000000 --- a/src/vk/sprite_to_draw.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SPRITES_TO_DRAW_H -#define CANDY_GEAR_VK_SPRITES_TO_DRAW_H 1 - -#include - -#include "core.hpp" -#include "sprite.hpp" - -namespace VK -{ - struct SpriteToDraw - { - std::shared_ptr sprite; - glm::vec4 position; - float z_index; - - SpriteToDraw(std::shared_ptr sprite, const glm::vec4 &position, - float z_index); - }; - - bool - operator<(const SpriteToDraw &a, const SpriteToDraw &b); - - bool - operator>(const SpriteToDraw &a, const SpriteToDraw &b); -} - -#endif /* CANDY_GEAR_VK_SPRITES_TO_DRAW_H */ diff --git a/src/vk/static_mesh.cpp b/src/vk/static_mesh.cpp deleted file mode 100644 index 29034df..0000000 --- a/src/vk/static_mesh.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "static_mesh.hpp" - -#include "../binary_reader.hpp" -#include "../command.hpp" -#include "../core.hpp" -#include "static_mesh_vertex.hpp" - -namespace -{ - -// Data that is only needed for the command chain but not for the StaticMesh -// goes here. -struct MeshBuilder -{ - std::string mesh_path; - VK::StaticMesh *mesh; - - MeshBuilder(VK::StaticMesh *m, std::string mp); - MeshBuilder(VK::StaticMesh *m, const char* mp); -}; - -MeshBuilder::MeshBuilder(VK::StaticMesh *m, std::string mp): - mesh{m}, - mesh_path{mp} -{ -} - -MeshBuilder::MeshBuilder(VK::StaticMesh *m, const char *mp): - MeshBuilder{m, std::string(mp)} -{ -} - -void -load_mesh(void *obj) -{ - auto self = static_cast(obj); - - BinaryReader input{self->mesh_path}; - - self->mesh->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); - - { // Load vertexes. - auto vertex_count{input.read_ui32()}; - std::vector vertexes{vertex_count}; - - for(auto i{0}; i < vertex_count; i++) - { - vertexes[i].position = input.read_vec3(); - vertexes[i].normal = input.read_vec3(); - vertexes[i].texture_coord = input.read_vec2(); - } - - void *vertexes_data{vertexes.data()}; - size_t vertexes_size = sizeof(vertexes[0]) * vertexes.size(); - self->mesh->source_vertex_buffer = new VK::SourceBuffer{ - self->mesh->queue_family->device, vertexes_data, vertexes_size}; - self->mesh->vertex_buffer = new VK::DestinationBuffer{ - self->mesh->queue_family, self->mesh->source_vertex_buffer, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; - } - - { // Load indexes - self->mesh->index_count = input.read_ui32(); - std::vector indexes(self->mesh->index_count); - - for(auto i{0}; i < self->mesh->index_count; i++) - indexes[i] = input.read_ui32(); - - void *indexes_data{indexes.data()}; - size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; - VK::SourceBuffer source_index_buffer{ - self->mesh->queue_family->device, indexes_data, indexes_size}; - self->mesh->index_buffer = new VK::DestinationBuffer{ - self->mesh->queue_family, &source_index_buffer, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; - } -} - -void -unload_mesh(void *obj) -{ - auto self = static_cast(obj); - - delete self->mesh->index_buffer; - delete self->mesh->vertex_buffer; - delete self->mesh->source_vertex_buffer; -} - -static const CommandChain loader{ - {&load_mesh, &unload_mesh} -}; - -} - -namespace VK -{ - -StaticMesh::StaticMesh(std::string mesh_path) -{ - MeshBuilder mesh_builder(this, mesh_path); - loader.execute(&mesh_builder); -} - -StaticMesh::StaticMesh(const char* mesh_path): - StaticMesh{std::string(mesh_path)} -{ -} - -StaticMesh::~StaticMesh() -{ - MeshBuilder mesh_builder(this, ""); - loader.revert(&mesh_builder); -} - -} diff --git a/src/vk/static_mesh.hpp b/src/vk/static_mesh.hpp deleted file mode 100644 index 0ab38b2..0000000 --- a/src/vk/static_mesh.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_STATIC_MESH_H -#define CANDY_GEAR_VK_STATIC_MESH_H 1 - -#include -#include - -#include "core.hpp" -#include "destination_buffer.hpp" -#include "queue_family.hpp" -#include "uniform_buffer.hpp" -#include "texture.hpp" - -namespace VK -{ - -struct StaticMesh -{ - QueueFamily *queue_family; - - uint32_t index_count; - SourceBuffer *source_vertex_buffer; - DestinationBuffer *index_buffer; - DestinationBuffer *vertex_buffer; - - StaticMesh(std::string mesh_path); - StaticMesh(const char* mesh_path); - ~StaticMesh(); -}; - -} - -#endif /* CANDY_GEAR_VK_STATIC_MESH_H */ diff --git a/src/vk/static_mesh_vertex.hpp b/src/vk/static_mesh_vertex.hpp deleted file mode 100644 index 7a91fe4..0000000 --- a/src/vk/static_mesh_vertex.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_STATIC_MESH_VERTEX_H -#define CANDY_GEAR_VK_STATIC_MESH_VERTEX_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct StaticMeshVertex -{ - glm::vec3 position; - glm::vec3 normal; - glm::vec2 texture_coord; -}; - -} - -#endif /* CANDY_GEAR_VK_STATIC_MESH_VERTEX_H */ diff --git a/src/vk/static_model.cpp b/src/vk/static_model.cpp deleted file mode 100644 index ef53155..0000000 --- a/src/vk/static_model.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2022-2024 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "static_model.hpp" - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_uniform_buffers(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->uniform_buffers.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->uniform_buffers.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOStaticModel)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_uniform_buffers(void *obj) -{ - auto self = static_cast(obj); - - self->uniform_buffers.clear(); -} - -void -load_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - std::array descriptor_pool_sizes{}; - descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_pool_sizes[0].descriptorCount = - self->uniform_buffers.size(); - - VkDescriptorPoolCreateInfo pool_info{}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.pNext = nullptr; - pool_info.flags = 0; - pool_info.maxSets = self->uniform_buffers.size(); - pool_info.poolSizeCount = descriptor_pool_sizes.size(); - pool_info.pPoolSizes = descriptor_pool_sizes.data(); - - if(vkCreateDescriptorPool( - self->static_mesh->queue_family->device->device, &pool_info, nullptr, - &self->descriptor_pool) != VK_SUCCESS) - throw CommandError{"Failed to create a Vulkan descriptor pool."}; -} - -void -unload_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorPool( - self->static_mesh->queue_family->device->device, self->descriptor_pool, - nullptr); -} - -void -load_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->model); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets.resize(layouts.size()); - if(vkAllocateDescriptorSets( - self->static_mesh->queue_family->device->device, &alloc_info, - self->descriptor_sets.data()) != VK_SUCCESS) - CommandError{"Failed to create Vulkan descriptor set."}; -} - -void -load_buffers_to_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < self->uniform_buffers.size(); i++) - { - VkDescriptorBufferInfo buffer_info{}; - buffer_info.buffer = self->uniform_buffers[i].buffer; - buffer_info.offset = 0; - buffer_info.range = sizeof(VK::UDOStaticModel); - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[0].pBufferInfo = &buffer_info; - write_descriptors[0].pImageInfo = nullptr; - write_descriptors[0].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - } -} - -static const CommandChain loader{ - {&load_uniform_buffers, &unload_uniform_buffers}, - {&load_descriptor_set_pool, &unload_descriptor_set_pool}, - {&load_descriptor_sets, nullptr}, - {&load_buffers_to_descriptor_sets, nullptr} -}; - -} - -namespace VK -{ - -StaticModel::StaticModel( - std::shared_ptr static_mesh, - std::shared_ptr texture, std::shared_ptr position, - std::shared_ptr orientation): - static_mesh{static_mesh}, - texture{texture}, - position{position}, - orientation{orientation} -{ - loader.execute(this); -} - -StaticModel::~StaticModel() -{ - loader.revert(this); -} - -} diff --git a/src/vk/static_model.hpp b/src/vk/static_model.hpp deleted file mode 100644 index 72f4fac..0000000 --- a/src/vk/static_model.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_STATIC_MODEL_H -#define CANDY_GEAR_VK_STATIC_MODEL_H 1 - -#include -#include - -#include "core.hpp" -#include "static_mesh.hpp" - -namespace VK -{ - -struct StaticModel -{ - std::shared_ptr static_mesh; - std::shared_ptr texture; - std::vector uniform_buffers; - std::shared_ptr position; - std::shared_ptr orientation; - - VkDescriptorPool descriptor_pool; - std::vector descriptor_sets; - - StaticModel( - std::shared_ptr static_mesh, - std::shared_ptr texture, std::shared_ptr position, - std::shared_ptr orientation); - ~StaticModel(); -}; - -} - -#endif /* CANDY_GEAR_VK_STATIC_MODEL_H */ diff --git a/src/vk/swapchain.cpp b/src/vk/swapchain.cpp deleted file mode 100644 index 2c67ebd..0000000 --- a/src/vk/swapchain.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "swapchain.hpp" - -#include "../core.hpp" - -#include - -namespace -{ - -void -load_swapchain(void *obj) -{ - auto self = static_cast(obj); - - // Surface formats. - uint32_t vk_surface_format_count; - std::vector vk_surface_formats; - vkGetPhysicalDeviceSurfaceFormatsKHR( - cg_core.vk_device_with_swapchain->physical_device, cg_core.window_surface, - &vk_surface_format_count, nullptr); - vk_surface_formats.resize(vk_surface_format_count); - vkGetPhysicalDeviceSurfaceFormatsKHR( - cg_core.vk_device_with_swapchain->physical_device, cg_core.window_surface, - &vk_surface_format_count, vk_surface_formats.data()); - - VkSwapchainCreateInfoKHR swapchain_create_info = {}; - swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_create_info.pNext = nullptr; - swapchain_create_info.flags = 0; - swapchain_create_info.surface = cg_core.window_surface; - swapchain_create_info.minImageCount = 3; // triple buffering. - - self->image_format = vk_surface_formats[0].format; - swapchain_create_info.imageFormat = self->image_format; - swapchain_create_info.imageColorSpace = vk_surface_formats[0].colorSpace; - - swapchain_create_info.imageExtent = { - cg_core.display_width, cg_core.display_height}; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchain_create_info.queueFamilyIndexCount = 0; - swapchain_create_info.pQueueFamilyIndices = nullptr; - swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; - swapchain_create_info.clipped = VK_FALSE; - swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; - - if(vkCreateSwapchainKHR( - cg_core.vk_device_with_swapchain->device, &swapchain_create_info, - nullptr, &self->swapchain) != VK_SUCCESS) - throw CommandError{"Vulkan failed to create swapchain."}; - - vkGetSwapchainImagesKHR( - cg_core.vk_device_with_swapchain->device, self->swapchain, - &self->images_count, nullptr); - self->images = new VkImage[self->images_count]; - vkGetSwapchainImagesKHR( - cg_core.vk_device_with_swapchain->device, self->swapchain, - &self->images_count, self->images); -} - -void -unload_swapchain(void *obj) -{ - auto self = static_cast(obj); - - delete[] self->images; - vkDestroySwapchainKHR( - cg_core.vk_device_with_swapchain->device, self->swapchain, nullptr); -} - -void -load_image_view(void *obj) -{ - auto self = static_cast(obj); - - self->image_views = new VkImageView[self->images_count]; - for(auto i{0}; i < self->images_count; i++) - { - VkImageViewCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - create_info.image = self->images[i]; - create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - create_info.format = self->image_format; - create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - create_info.subresourceRange.baseMipLevel = 0; - create_info.subresourceRange.levelCount = 1; - create_info.subresourceRange.baseArrayLayer = 0; - create_info.subresourceRange.layerCount = 1; - - if(vkCreateImageView( - cg_core.vk_device_with_swapchain->device, &create_info, nullptr, - &self->image_views[i])) - throw CommandError{"Could no create Image View for swapchain."}; - } -} - -void -unload_image_view(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < self->images_count; i++) - vkDestroyImageView( - cg_core.vk_device_with_swapchain->device, self->image_views[i], nullptr); -} - -void -load_frame_sync(void *obj) -{ - auto self = static_cast(obj); - - self->image_available_semaphores.resize(self->max_frames_in_flight); - self->render_finished_semaphores.resize(self->max_frames_in_flight); - self->in_flight_fences.resize(self->max_frames_in_flight); - - VkSemaphoreCreateInfo semaphore_info = {}; - semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphore_info.pNext = nullptr; - semaphore_info.flags = 0; - - VkFenceCreateInfo fence_info = {}; - fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fence_info.pNext = nullptr; - fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - // FIXME: if this loop fails, it will not destroy the semaphores. - for(auto i{0}; i < self->max_frames_in_flight; i++) - { - if(vkCreateSemaphore( - cg_core.vk_device_with_swapchain->device, &semaphore_info, - nullptr, &self->image_available_semaphores[i]) != VK_SUCCESS || - vkCreateSemaphore( - cg_core.vk_device_with_swapchain->device, &semaphore_info, - nullptr, &self->render_finished_semaphores[i]) != VK_SUCCESS || - vkCreateFence(cg_core.vk_device_with_swapchain->device, &fence_info, - nullptr, &self->in_flight_fences[i]) != VK_SUCCESS) - throw CommandError{"Failed to create semaphores."}; - } -} - -void -unload_frame_sync(void *obj) -{ - auto self = static_cast(obj); - - vkDeviceWaitIdle(cg_core.vk_device_with_swapchain->device); - - for(auto i{0}; i < self->max_frames_in_flight; i++) - { - vkDestroySemaphore(cg_core.vk_device_with_swapchain->device, - self->render_finished_semaphores[i], nullptr); - vkDestroySemaphore(cg_core.vk_device_with_swapchain->device, - self->image_available_semaphores[i], nullptr); - vkDestroyFence(cg_core.vk_device_with_swapchain->device, - self->in_flight_fences[i], nullptr); - } -} - -const CommandChain loader{ - {&load_swapchain, &unload_swapchain}, - {&load_image_view, &unload_image_view}, - {&load_frame_sync, &unload_frame_sync} -}; - -} - -namespace VK -{ - -Swapchain::Swapchain(): - current_frame{0} -{ - loader.execute(this); -} - -Swapchain::~Swapchain() -{ - loader.revert(this); -} - -} diff --git a/src/vk/swapchain.hpp b/src/vk/swapchain.hpp deleted file mode 100644 index a5ade81..0000000 --- a/src/vk/swapchain.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_SWAPCHAIN_H -#define CANDY_GEAR_VK_SWAPCHAIN_H 1 - -#include "core.hpp" -#include "../command.hpp" - -namespace VK -{ - -struct Swapchain -{ - VkSwapchainKHR swapchain; - VkFormat image_format; - - uint32_t images_count; - VkImage *images; - VkImageView *image_views; - - static const int max_frames_in_flight{2}; - size_t current_frame; - std::vector image_available_semaphores; - std::vector render_finished_semaphores; - std::vector in_flight_fences; - - Swapchain(); - ~Swapchain(); -}; - -} - -#endif /* CANDY_GEAR_VK_SWAPCHAIN_H */ diff --git a/src/vk/texture.cpp b/src/vk/texture.cpp deleted file mode 100644 index a4cac40..0000000 --- a/src/vk/texture.cpp +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright 2022-2024 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "texture.hpp" - -#include "../command.hpp" -#include "../core.hpp" -#include "image.hpp" -#include "qoi.hpp" -#include "source_buffer.hpp" - -namespace -{ - -inline void -create_vulkan_image( - VkImage *image, VkDeviceMemory *device_memory, int width, int height, - uint32_t mip_levels) -{ - VkExtent3D vk_extent3d{}; - vk_extent3d.width = width; - vk_extent3d.height = height; - vk_extent3d.depth = 1; - - VK::Image::create( - cg_core.vk_device_with_swapchain, - image, - device_memory, - VK_FORMAT_R8G8B8A8_UNORM, - vk_extent3d, - mip_levels, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); -} - -struct ImageBuilder -{ - VK::Texture *texture; -}; - -struct ImageTextureBuilder: public ImageBuilder -{ - std::string texture_path; - - ImageTextureBuilder(VK::Texture *t, std::string tp); - ImageTextureBuilder(VK::Texture *t, const char* tp); -}; - -ImageTextureBuilder::ImageTextureBuilder(VK::Texture *t, std::string tp): - texture_path{tp} -{ - this->texture = t; -} - -ImageTextureBuilder::ImageTextureBuilder(VK::Texture *t, const char* tp): - ImageTextureBuilder{t, std::string(tp)} -{ -} - -void -load_image(void *obj) -{ - auto self = static_cast(obj); - - const int num_channels = 4; // all images are converted to RGBA - VK::QOI::Image qoi_image(self->texture_path.c_str(), num_channels); - uint8_t *pixels; - - { // Load file image from file. - self->texture->width = qoi_image.header.width; - self->texture->height = qoi_image.header.height; - self->texture->mip_levels = 1; - - pixels = qoi_image.pixels; - } - - // Load file image into a vulkan buffer. - size_t image_size{static_cast( - qoi_image.header.width * qoi_image.header.height * num_channels)}; - VK::SourceBuffer source_image_buffer{ - cg_core.vk_device_with_swapchain, pixels, image_size}; - - { // Create vulkan image. - try - { - create_vulkan_image( - &self->texture->image, - &self->texture->device_memory, - self->texture->width, - self->texture->height, - self->texture->mip_levels); - } - catch(VK::Image::Error error) - { - throw CommandError{error.what()}; - } - } - - // Copy image from vulkan buffer into vulkan image. - { - auto queue_family = self->texture->queue_family; - auto queue{queue_family->get_queue()}; - VK::CommandPool command_pool{queue_family, 1}; - VkCommandBuffer vk_command_buffer{command_pool.command_buffers[0]}; - - queue.submit_one_time_command(vk_command_buffer, [&](){ - VK::Image::move_image_state( - vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, - 0, VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkBufferImageCopy image_copy{}; - image_copy.bufferOffset = 0; - image_copy.bufferRowLength = 0; - image_copy.bufferImageHeight = 0; - image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_copy.imageSubresource.mipLevel = 0; - image_copy.imageSubresource.baseArrayLayer = 0; - image_copy.imageSubresource.layerCount = 1; - image_copy.imageOffset = {0, 0, 0}; - image_copy.imageExtent = { - self->texture->width, self->texture->height, 1}; - - vkCmdCopyBufferToImage( - vk_command_buffer, source_image_buffer.buffer, self->texture->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); - - VK::Image::move_image_state( - vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - }); - } -} - -void -unload_image(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyImage( - cg_core.vk_device_with_swapchain->device, self->texture->image, nullptr); - vkFreeMemory( - cg_core.vk_device_with_swapchain->device, self->texture->device_memory, - nullptr); -} - -void -load_sampler(void *obj) -{ - auto self = static_cast(obj); - - VkSamplerCreateInfo sampler_info{}; - sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - sampler_info.pNext = nullptr; - sampler_info.flags = 0; - sampler_info.magFilter = VK_FILTER_LINEAR; - sampler_info.minFilter = VK_FILTER_LINEAR; - sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.mipLodBias = 0.0f; - sampler_info.anisotropyEnable = VK_TRUE; - sampler_info.maxAnisotropy = 16; - sampler_info.compareEnable = VK_FALSE; - sampler_info.compareOp = VK_COMPARE_OP_NEVER; - sampler_info.minLod = 0.0f; - sampler_info.maxLod = 0.0f; - sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - sampler_info.unnormalizedCoordinates = VK_FALSE; - - if(vkCreateSampler( - cg_core.vk_device_with_swapchain->device, &sampler_info, nullptr, - &self->texture->sampler) != VK_SUCCESS) - throw CommandError{"Failed to create texture sampler."}; -} - -void -unload_sampler(void *obj) -{ - auto self = static_cast(obj); - - vkDestroySampler( - cg_core.vk_device_with_swapchain->device, self->texture->sampler, nullptr); -} - -void -load_view(void *obj) -{ - auto self = static_cast(obj); - - try - { - VK::Image::create_view( - cg_core.vk_device_with_swapchain, &self->texture->view, - self->texture->image, - VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); - } - catch(VK::Image::Error error) - { - throw CommandError{error.what()}; - } -} - -void -unload_view(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyImageView( - cg_core.vk_device_with_swapchain->device, self->texture->view, nullptr); -} - -const CommandChain image_loader{ - {&load_image, &unload_image}, - {&load_sampler, &unload_sampler}, - {&load_view, &unload_view} -}; - -struct CharacterToDraw -{ - int pos_x; - std::shared_ptr character; - - CharacterToDraw(int x, std::shared_ptr character): - pos_x{x}, - character{character} - {}; -}; - -struct TextTextureBuilder: public ImageBuilder -{ - VK::Font *font; - const char* str; - uint32_t max_bearing_y; - std::vector chars_to_draw; - - TextTextureBuilder(VK::Texture *texture, VK::Font *font, const char* str): - font{font}, - str{str} - { - this->texture = texture; - } -}; - -void -load_text_proportions(void *obj) -{ - auto self = static_cast(obj); - - uint32_t texture_width{0}, texture_descender{0}; - auto unicode_text{VK::Character::str_to_unicode(self->str)}; - - auto first_image{self->font->character(unicode_text[0])}; - if(first_image->bearing_x < 0) texture_width = - first_image->bearing_x; - - self->max_bearing_y = 0; - self->chars_to_draw.reserve(unicode_text.size()); - - // FIXME: I need to test several different fonts to find all bugs in this - // code. - std::shared_ptr char_image{}; - { // Calculate image size - int max_height; - for(auto char_code : unicode_text) - { - char_image = self->font->character(char_code); - uint32_t descender{char_image->height - char_image->bearing_y}; - uint32_t pos_x{texture_width + char_image->bearing_x}; - - if(char_image->image != VK_NULL_HANDLE) - self->chars_to_draw.emplace_back(pos_x, char_image); - - if(char_image->bearing_y > self->max_bearing_y) - self->max_bearing_y = char_image->bearing_y; - if(descender > texture_descender) texture_descender = descender; - - texture_width += char_image->advance; - } - } - - { // Restore image width if last character have a negative bearing. - int bearing_x_pluss_width = char_image->bearing_x + char_image->width; - if(bearing_x_pluss_width > char_image->advance) - texture_width += bearing_x_pluss_width - char_image->advance; - } - - self->texture->width = texture_width; - self->texture->height = self->max_bearing_y + texture_descender; - self->texture->mip_levels = 1; -} - -void -load_text_image(void *obj) -{ - auto self = static_cast(obj); - - const int NumChannels = 4; - - size_t image_size{static_cast( - self->texture->width * self->texture->height * NumChannels)}; - std::vector pixels(image_size); - for(auto x{0}; x < self->texture->width; x++) - { - for(auto y{0}; y < self->texture->height; y++) - { - auto image_coord = y * self->font->face->glyph->bitmap.width + - x * NumChannels; - pixels[image_coord] = 0; // Red - pixels[image_coord + 1] = 0; // Green - pixels[image_coord + 2] = 0; // Blue - pixels[image_coord + 3] = 0; // Alpha - } - } - VK::SourceBuffer source_image_buffer{ - cg_core.vk_device_with_swapchain, pixels.data(), image_size}; - - { // Create vulkan image. - try - { - create_vulkan_image( - &self->texture->image, - &self->texture->device_memory, - self->texture->width, - self->texture->height, - self->texture->mip_levels); - } - catch(VK::Image::Error error) - { - throw CommandError{error.what()}; - } - } - - { // Render text - auto queue_family{ - cg_core.vk_device_with_swapchain->get_queue_family_with_presentation()}; - auto queue{queue_family->get_queue()}; - VK::CommandPool command_pool{queue_family, 1}; - VkCommandBuffer vk_command_buffer{command_pool.command_buffers[0]}; - - queue.submit_one_time_command(vk_command_buffer, [&](){ - VK::Image::move_image_state( - vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, - 0, VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkBufferImageCopy image_copy{}; - image_copy.bufferOffset = 0; - image_copy.bufferRowLength = 0; - image_copy.bufferImageHeight = 0; - image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_copy.imageSubresource.mipLevel = 0; - image_copy.imageSubresource.baseArrayLayer = 0; - image_copy.imageSubresource.layerCount = 1; - image_copy.imageOffset = {0, 0, 0}; - image_copy.imageExtent = {self->texture->width, self->texture->height, 1}; - - vkCmdCopyBufferToImage( - vk_command_buffer, source_image_buffer.buffer, self->texture->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); - - for(auto &to_draw: self->chars_to_draw) - { - VkImageSubresourceLayers - source_subresources{}, destination_subresources{}; - source_subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - source_subresources.mipLevel = 0; - source_subresources.baseArrayLayer = 0; - source_subresources.layerCount = 1; - - destination_subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - destination_subresources.mipLevel = 0; - destination_subresources.baseArrayLayer = 0; - destination_subresources.layerCount = 1; - - VkImageCopy image_copy{}; - image_copy.srcSubresource = source_subresources; - image_copy.srcOffset = {0, 0, 0}; - image_copy.dstSubresource = destination_subresources; - image_copy.dstOffset = { - to_draw.pos_x, - (int)(self->max_bearing_y - to_draw.character->bearing_y), - 0}; - image_copy.extent = { - to_draw.character->width, to_draw.character->height, 1}; - - vkCmdCopyImage( - vk_command_buffer, - to_draw.character->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - self->texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &image_copy); - } - - VK::Image::move_image_state( - vk_command_buffer, self->texture->image, VK_FORMAT_R8G8B8A8_UNORM, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - }); - } -} - -const CommandChain text_loader{ - {&load_text_proportions, nullptr}, - {&load_text_image, &unload_image}, - {&load_sampler, &unload_sampler}, - {&load_view, &unload_view} -}; - -void -load_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - std::array descriptor_pool_sizes{}; - descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptor_pool_sizes[0].descriptorCount = - cg_core.vk_swapchain->images_count; - - VkDescriptorPoolCreateInfo pool_info{}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.pNext = nullptr; - pool_info.flags = 0; - pool_info.maxSets = cg_core.vk_swapchain->images_count; - pool_info.poolSizeCount = descriptor_pool_sizes.size(); - pool_info.pPoolSizes = descriptor_pool_sizes.data(); - - if(vkCreateDescriptorPool( - self->queue_family->device->device, &pool_info, nullptr, - &self->descriptor_pool) != VK_SUCCESS) - throw CommandError{"Failed to create a Vulkan descriptor pool."}; -} - -void -unload_descriptor_set_pool(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorPool( - self->queue_family->device->device, self->descriptor_pool, nullptr); -} - -void -load_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->texture); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets.resize(layouts.size()); - if(vkAllocateDescriptorSets( - self->queue_family->device->device, &alloc_info, - self->descriptor_sets.data()) != VK_SUCCESS) - CommandError{"Failed to create Vulkan descriptor set."}; -} - -void -load_data_to_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - { - VkDescriptorImageInfo image_info{}; - image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_info.imageView = self->view; - image_info.sampler = self->sampler; - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write_descriptors[0].pBufferInfo = nullptr; - write_descriptors[0].pImageInfo = &image_info; - write_descriptors[0].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - } -} - -const CommandChain descriptor_loader{ - {&load_descriptor_set_pool, &unload_descriptor_set_pool}, - {&load_descriptor_sets, nullptr}, - {&load_data_to_descriptor_sets, nullptr} -}; - -} - -namespace VK -{ - -Texture::Texture(Font *font, const char* str) -{ - this->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_presentation(); - - TextTextureBuilder text_builder(this, font, str); - text_loader.execute(&text_builder); - descriptor_loader.execute(this); -} - -Texture::Texture(std::string texture_path) -{ - this->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_presentation(); - - ImageTextureBuilder texture_builder(this, texture_path); - image_loader.execute(&texture_builder); - descriptor_loader.execute(this); -} - -Texture::Texture(const char* texture_path): - Texture{std::string(texture_path)} -{ -} - -Texture::~Texture() -{ - ImageTextureBuilder texture_builder(this, ""); - image_loader.revert(&texture_builder); - descriptor_loader.revert(this); -} - -} diff --git a/src/vk/texture.hpp b/src/vk/texture.hpp deleted file mode 100644 index 22711eb..0000000 --- a/src/vk/texture.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_TEXTURE_H -#define CANDY_GEAR_VK_TEXTURE_H 1 - -#include - -#include "core.hpp" -#include "font.hpp" -#include "queue_family.hpp" - -namespace VK -{ - -struct Texture -{ - QueueFamily *queue_family; - - VkImage image; - VkSampler sampler; - VkImageView view; - VkDeviceMemory device_memory; - uint32_t width, height; - uint32_t mip_levels; - - VkDescriptorPool descriptor_pool; - std::vector descriptor_sets; - - Texture(Font *font, const char *str); - Texture(std::string texture_path); - Texture(const char* texture_path); - ~Texture(); -}; - -} - -#endif /* CANDY_GEAR_TEXTURE_H */ diff --git a/src/vk/uniform_buffer.cpp b/src/vk/uniform_buffer.cpp deleted file mode 100644 index dd61898..0000000 --- a/src/vk/uniform_buffer.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "uniform_buffer.hpp" - -#include -#include - -namespace VK -{ - -UniformBuffer::UniformBuffer(Device *device, VkDeviceSize data_size) -{ - this->device = device; - this->device_size = data_size; - this->buffer_usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - this->memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - try - { - BaseBuffer::loader.execute(static_cast(this)); - } - catch(const CommandError &command_error) - { - std::string error{"Could not initialize Vulkan uniform buffer → "}; - error += command_error.what(); - throw CommandError{error}; - } -} - -UniformBuffer::~UniformBuffer() -{ - BaseBuffer::loader.revert(static_cast(this)); -} - -UniformBuffer::UniformBuffer(UniformBuffer &&that) -{ - this->device = that.device; - this->buffer = that.buffer; - this->device_memory = that.device_memory; - this->device_size = that.device_size; - this->buffer_usage = that.buffer_usage; - this->memory_properties = that.memory_properties; - - that.buffer = VK_NULL_HANDLE; - that.device_memory = VK_NULL_HANDLE; -} - -UniformBuffer& -UniformBuffer::operator=(UniformBuffer &&that) -{ - this->device = that.device; - this->buffer = that.buffer; - this->device_memory = that.device_memory; - this->device_size = that.device_size; - this->buffer_usage = that.buffer_usage; - this->memory_properties = that.memory_properties; - - that.buffer = VK_NULL_HANDLE; - that.device_memory = VK_NULL_HANDLE; - - return *this; -} - -void -UniformBuffer::copy_data(void *ubo) -{ - void *data; - vkMapMemory(this->device->device, this->device_memory, 0, - this->device_size, 0, &data); - memcpy(data, ubo, this->device_size); - vkUnmapMemory(this->device->device, this->device_memory); -} - -} diff --git a/src/vk/uniform_buffer.hpp b/src/vk/uniform_buffer.hpp deleted file mode 100644 index e978894..0000000 --- a/src/vk/uniform_buffer.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_UNIFORM_BUFFER_H -#define CANDY_GEAR_VK_UNIFORM_BUFFER_H 1 - -#include - -#include "core.hpp" - -#include "base_buffer.hpp" - -namespace VK -{ - -// FIXME: this class need to delete or create custom copy constructors! -class UniformBuffer: public BaseBuffer -{ - UniformBuffer(const UniformBuffer &t) = delete; - UniformBuffer& - operator=(const UniformBuffer &t) = delete; - -public: - UniformBuffer(Device *device, VkDeviceSize data_size); - ~UniformBuffer(); - - UniformBuffer(UniformBuffer &&that); - UniformBuffer& - operator=(UniformBuffer &&that); - - void copy_data(void* ubo); -}; - -} - -#endif /* CANDY_GEAR_VK_UNIFORM_BUFFER_H */ diff --git a/src/vk/uniform_data_object.hpp b/src/vk/uniform_data_object.hpp deleted file mode 100644 index 5cc22cb..0000000 --- a/src/vk/uniform_data_object.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_UNIFORM_DATA_OBJECT_H -#define CANDY_GEAR_VK_UNIFORM_DATA_OBJECT_H 1 - -#include "core.hpp" -#include "skeletal_mesh_vertex.hpp" - -namespace VK -{ - -// UDO = "uniform data object" - -struct UDOView2D -{ - glm::mat4 proj; -}; - -struct UDOView3D -{ - glm::mat4 view; - glm::mat4 proj; -}; - -struct UDOWorld3D_Vert -{ - glm::vec4 ambient_light_color; -}; - -struct UDOWorld3D_Frag -{ - glm::vec3 directional_light_direction; - glm::vec4 directional_light_color; -}; - -struct UDOStaticModel -{ - glm::mat4 base_matrix; -}; - -struct UDOSkeletalModel -{ - glm::mat4 base_matrix; - glm::mat4 bone_matrices[SKELETAL_MESH_MAX_NUM_OF_BONES]; -}; - -struct UDOVector4D -{ - glm::vec4 vector; -}; - -struct UDOVector3D -{ - glm::vec3 vectors; -}; - -struct UDOSprite3D -{ - glm::vec3 position; - uint32_t padding; - glm::vec2 size; -}; - -} - -#endif /* CANDY_GEAR_VK_UNIFORM_DATA_OBJECT_H */ diff --git a/src/vk/view_2d.cpp b/src/vk/view_2d.cpp deleted file mode 100644 index c628a18..0000000 --- a/src/vk/view_2d.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "view_2d.hpp" - -#include - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_2d_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->ub_2d.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->ub_2d.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOView2D)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_2d_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - self->ub_2d.clear(); -} - -void -load_descriptor_sets_2d(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->view); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets_2d.resize(layouts.size()); - if(vkAllocateDescriptorSets( - cg_core.vk_device_with_swapchain->device, &alloc_info, - self->descriptor_sets_2d.data()) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan descriptor sets for view."}; -} - -void -load_resources_to_descriptor_sets_2d(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < self->ub_2d.size(); i++) - { - VkDescriptorBufferInfo view_2d_info{}; - view_2d_info.buffer = self->ub_2d[i].buffer; - view_2d_info.offset = 0; - view_2d_info.range = sizeof(VK::UDOView2D); - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets_2d[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[0].pBufferInfo = &view_2d_info; - write_descriptors[0].pImageInfo = nullptr; - write_descriptors[0].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - - VK::UDOView2D ubo_view_2d; - ubo_view_2d.proj = glm::ortho( - 0.0f, self->projection_width, - 0.0f, self->projection_height, - 0.0f, 100.0f); - self->ub_2d[i].copy_data(&ubo_view_2d); - } -} - -} - -namespace VK -{ - -const CommandChain View2D::loader{ - {&load_2d_uniform_buffer, &unload_2d_uniform_buffer} -}; - -const CommandChain View2D::descriptor_sets_loader{ - {&load_descriptor_sets_2d, nullptr}, - {&load_resources_to_descriptor_sets_2d, nullptr} -}; - -View2D::View2D( - glm::vec4 region, float projection_width, float projection_height): - projection_width{projection_width}, - projection_height{projection_height}, - region{region}, - descriptor_pool{VK_NULL_HANDLE}, - rectangles_to_draw{cg_core.vk_swapchain->images_count}, - sprites_to_draw{cg_core.vk_swapchain->images_count} -{ - loader.execute(this); -} - -View2D::~View2D() -{ - loader.revert(this); -} - -void -View2D::load_descriptor_sets(VkDescriptorPool descriptor_pool) -{ - if(this->descriptor_pool != VK_NULL_HANDLE) return; - - this->descriptor_pool = descriptor_pool; - descriptor_sets_loader.execute(this); -} - -void -View2D::unload_descriptor_sets() -{ - if(this->descriptor_pool == VK_NULL_HANDLE) return; - - this->descriptor_pool = VK_NULL_HANDLE; - descriptor_sets_loader.revert(this); -} - -} diff --git a/src/vk/view_2d.hpp b/src/vk/view_2d.hpp deleted file mode 100644 index ead21e2..0000000 --- a/src/vk/view_2d.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_VIEW_2D_H -#define CANDY_GEAR_VK_VIEW_2D_H 1 - -#include -#include -#include - -#include "core.hpp" -#include "sprite_to_draw.hpp" -#include "rectangle.hpp" - -namespace VK -{ - -struct View2D -{ - glm::vec4 region; - float projection_width, projection_height; - - // FIXME: if these vectors get resized, they can cause a segmentation fault! - std::vector ub_2d; - - VkDescriptorPool descriptor_pool; - std::vector descriptor_sets_2d; - - std::vector> rectangles_to_draw; - std::vector> sprites_to_draw; - - View2D(glm::vec4 region, float projection_width, float projection_height); - virtual ~View2D(); - - void - virtual load_descriptor_sets(VkDescriptorPool descriptor_pool); - - void - virtual unload_descriptor_sets(); - -protected: - static const CommandChain loader, descriptor_sets_loader; -}; - -} - -#endif /* CANDY_GEAR_VK_VIEW_2D_H */ diff --git a/src/vk/view_3d.cpp b/src/vk/view_3d.cpp deleted file mode 100644 index 273874c..0000000 --- a/src/vk/view_3d.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2022-2023 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "view_3d.hpp" - -#include - -#include "../core.hpp" -#include "uniform_data_object.hpp" - -namespace -{ - -void -load_3d_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - try - { - self->ub_3d.reserve(cg_core.vk_swapchain->images_count); - for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->ub_3d.emplace_back( - cg_core.vk_device_with_swapchain, sizeof(VK::UDOView3D)); - } - catch(const std::exception& e) - { - throw CommandError{e.what()}; - } -} - -void -unload_3d_uniform_buffer(void *obj) -{ - auto self = static_cast(obj); - - self->ub_3d.clear(); -} - -void -load_descriptor_sets_3d(void *obj) -{ - auto self = static_cast(obj); - - std::vector layouts( - cg_core.vk_swapchain->images_count, - cg_core.vk_descriptor_set_layout->view); - - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->descriptor_pool; - alloc_info.descriptorSetCount = layouts.size(); - alloc_info.pSetLayouts = layouts.data(); - - self->descriptor_sets_3d.resize(layouts.size()); - if(vkAllocateDescriptorSets( - cg_core.vk_device_with_swapchain->device, &alloc_info, - self->descriptor_sets_3d.data()) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan descriptor sets for view."}; -} - -void -load_resources_to_descriptor_sets_3d(void *obj) -{ - auto self = static_cast(obj); - - for(auto i{0}; i < self->ub_3d.size(); i++) - { - VkDescriptorBufferInfo view_3d_info{}; - view_3d_info.buffer = self->ub_3d[i].buffer; - view_3d_info.offset = 0; - view_3d_info.range = sizeof(VK::UDOView3D); - - std::array write_descriptors{}; - write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->descriptor_sets_3d[i]; - write_descriptors[0].dstBinding = 0; - write_descriptors[0].dstArrayElement = 0; - write_descriptors[0].descriptorCount = 1; - write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_descriptors[0].pBufferInfo = &view_3d_info; - write_descriptors[0].pImageInfo = nullptr; - write_descriptors[0].pTexelBufferView = nullptr; - - vkUpdateDescriptorSets( - cg_core.vk_device_with_swapchain->device, write_descriptors.size(), - write_descriptors.data(), 0, nullptr); - } -} - -const CommandChain loader{ - {&load_3d_uniform_buffer, &unload_3d_uniform_buffer} -}; - -const CommandChain descriptor_sets_loader{ - {&load_descriptor_sets_3d, nullptr}, - {&load_resources_to_descriptor_sets_3d, nullptr} -}; - -} - -namespace VK -{ - -View3D::View3D( - glm::vec4 region, float projection_width, float projection_height): - View2D{region, projection_width, projection_height}, - field_of_view{45.0f}, - camera_position{std::make_shared(0.0f, 0.0f, 0.0f)}, - camera_orientation{std::make_shared(0.0f, 0.0f, 0.0f, 0.0f)} -{ - ::loader.execute(this); -} - -View3D::~View3D() -{ - ::loader.revert(this); -} - -void -View3D::load_descriptor_sets(VkDescriptorPool descriptor_pool) -{ - if(this->descriptor_pool != VK_NULL_HANDLE) return; - - auto parent = dynamic_cast(this); - this->descriptor_pool = descriptor_pool; - View2D::descriptor_sets_loader.execute(parent); - ::descriptor_sets_loader.execute(this); -} - -void -View3D::unload_descriptor_sets() -{ - if(this->descriptor_pool == VK_NULL_HANDLE) return; - - auto parent = dynamic_cast(this); - this->descriptor_pool = VK_NULL_HANDLE; - ::descriptor_sets_loader.revert(this); - View2D::descriptor_sets_loader.revert(parent); -} - -} diff --git a/src/vk/view_3d.hpp b/src/vk/view_3d.hpp deleted file mode 100644 index c5a803b..0000000 --- a/src/vk/view_3d.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2022 Frederico de Oliveira Linhares - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CANDY_GEAR_VK_VIEW_3D_H -#define CANDY_GEAR_VK_VIEW_3D_H 1 - -#include "view_2d.hpp" - -namespace VK -{ - -struct View3D: public View2D -{ - float field_of_view; - // FIXME: if this vector get resized, it can cause a segmentation fault! - std::vector ub_3d; - - std::vector descriptor_sets_3d; - - std::shared_ptr camera_position; - std::shared_ptr camera_orientation; - - View3D(glm::vec4 region, float projection_width, float projection_height); - ~View3D(); - - void - load_descriptor_sets(VkDescriptorPool descriptor_pool); - - void - unload_descriptor_sets(); -}; - -} - -#endif /* CANDY_GEAR_VK_VIEW_3D_H */ -- cgit v1.2.3