summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--glsl/shader_2d.vert.glsl6
-rw-r--r--glsl/shader_3d.frag.glsl15
-rw-r--r--glsl/shader_3d.vert.glsl18
-rw-r--r--src/candy_gear.cpp58
-rw-r--r--src/core.cpp27
-rw-r--r--src/core.hpp12
-rw-r--r--src/main.cpp2
-rw-r--r--src/model.cpp4
-rw-r--r--src/sprite.cpp15
-rw-r--r--src/view.cpp94
-rw-r--r--src/view.hpp27
-rw-r--r--src/vk/graphics_pipeline_2d.cpp226
-rw-r--r--src/vk/graphics_pipeline_2d.hpp18
-rw-r--r--src/vk/graphics_pipeline_2d_layout.cpp29
-rw-r--r--src/vk/graphics_pipeline_2d_layout.hpp12
-rw-r--r--src/vk/graphics_pipeline_3d.cpp281
-rw-r--r--src/vk/graphics_pipeline_3d.hpp17
-rw-r--r--src/vk/graphics_pipeline_3d_layout.cpp69
-rw-r--r--src/vk/graphics_pipeline_3d_layout.hpp25
-rw-r--r--src/vk/renderer.cpp169
-rw-r--r--src/vk/renderer.hpp17
-rw-r--r--src/vk/swapchain.cpp58
-rw-r--r--src/vk/swapchain.hpp6
-rw-r--r--src/vk/uniform_buffer.hpp28
-rw-r--r--src/vk/view.cpp259
-rw-r--r--src/vk/view.hpp55
-rw-r--r--test/config/init.yaml3
-rw-r--r--test/src/main.rb12
28 files changed, 979 insertions, 583 deletions
diff --git a/glsl/shader_2d.vert.glsl b/glsl/shader_2d.vert.glsl
index b053fec..5c5a243 100644
--- a/glsl/shader_2d.vert.glsl
+++ b/glsl/shader_2d.vert.glsl
@@ -21,10 +21,10 @@ layout(location = 0) in vec2 in_texture_coord;
layout(location = 0) out vec2 out_texture_coord;
-layout(set = 0, binding = 0) uniform UBOProjection
+layout(set = 0, binding = 0) uniform UBOView2D
{
mat4 proj;
-} ubo_projection;
+} ubo_view;
layout(set = 1, binding = 0) uniform UBOSpritePositions
{
@@ -54,5 +54,5 @@ main()
coordinate = vec2(position.z, position.w);
break;
}
- gl_Position = ubo_projection.proj * vec4(coordinate, 0.0, 1.0);
+ gl_Position = ubo_view.proj * vec4(coordinate, 0.0, 1.0);
}
diff --git a/glsl/shader_3d.frag.glsl b/glsl/shader_3d.frag.glsl
index 5c4b857..302f7d4 100644
--- a/glsl/shader_3d.frag.glsl
+++ b/glsl/shader_3d.frag.glsl
@@ -28,24 +28,25 @@ layout(location = 0) in DataTransferObject in_dto;
layout(location = 0) out vec4 out_color;
-layout(set = 0, binding = 1) uniform UBODirectionalLight
+layout(set = 0, binding = 1) uniform UBOWorld
{
- vec3 direction;
- vec4 color;
-} ubo_directional_light;
+ vec3 directional_light_direction;
+ vec4 directional_light_color;
+} ubo_world;
-layout(set = 1, binding = 1) uniform sampler2D texture_sampler;
+layout(set = 2, binding = 1) uniform sampler2D texture_sampler;
void
main()
{
float diffuse_factor =
- max(dot(in_dto.normal, -ubo_directional_light.direction), 0.0);
+ max(dot(in_dto.normal, -ubo_world.directional_light_direction), 0.0);
vec4 diff_samp = texture(texture_sampler, in_dto.frag_texture_coord);
vec4 ambient = vec4(vec3(in_dto.frag_color), diff_samp.a);
vec4 diffuse =
- vec4(vec3(ubo_directional_light.color * diffuse_factor), diff_samp.a);
+ vec4(vec3(ubo_world.directional_light_color * diffuse_factor),
+ diff_samp.a);
diffuse *= diff_samp;
ambient *= diff_samp;
diff --git a/glsl/shader_3d.vert.glsl b/glsl/shader_3d.vert.glsl
index 387ad00..29beea9 100644
--- a/glsl/shader_3d.vert.glsl
+++ b/glsl/shader_3d.vert.glsl
@@ -29,14 +29,18 @@ layout(location = 0) out DataTransferObject
vec3 normal;
} out_dto;
-layout(set = 0, binding = 0) uniform UBOViewProjection
+layout(set = 0, binding = 0) uniform UBOWorld
+{
+ vec4 ambient_light_color;
+} ubo_world;
+
+layout(set = 1, binding = 0) uniform UBOView
{
mat4 view;
mat4 proj;
- vec4 ambient_color;
-} ubo_view_projection;
+} ubo_view;
-layout(set = 1, binding = 0) uniform UBOModelInstance
+layout(set = 2, binding = 0) uniform UBOModelInstance
{
mat4 instances[128];
} ubo_model_instance;
@@ -45,9 +49,9 @@ void
main()
{
gl_Position =
- ubo_view_projection.proj * ubo_view_projection.view *
- ubo_model_instance.instances[gl_InstanceIndex] * vec4(in_position, 1.0);
- out_dto.frag_color = ubo_view_projection.ambient_color;
+ ubo_view.proj * ubo_view.view *
+ ubo_model_instance.instances[gl_InstanceIndex] * vec4(in_position, 1.0);
+ out_dto.frag_color = ubo_world.ambient_light_color;
out_dto.frag_texture_coord = in_texture_coord;
out_dto.normal = mat3(ubo_model_instance.instances[gl_InstanceIndex]) *
in_normal;
diff --git a/src/candy_gear.cpp b/src/candy_gear.cpp
index 9460b51..8ba87cc 100644
--- a/src/candy_gear.cpp
+++ b/src/candy_gear.cpp
@@ -24,6 +24,7 @@
#include "rotation_3d.hpp"
#include "vector_3d.hpp"
+#include "view.hpp"
static mrb_value
parse_node(mrb_state *mrb, const YAML::Node &node)
@@ -60,37 +61,47 @@ parse_node(mrb_state *mrb, const YAML::Node &node)
}
static mrb_value
-cg_mCandyGear_set_camera_position(mrb_state *mrb, mrb_value self)
+cg_mCandyGear_load_yaml(mrb_state *mrb, mrb_value self)
{
- std::shared_ptr<glm::vec3> *camera_position;
+ const char *file_path;
- mrb_get_args(mrb, "d", &camera_position, &cg_vector_3d_type);
- cg_core.vk_graphics_pipeline_3d->camera_position = (*camera_position);
+ mrb_get_args(mrb, "z", &file_path);
- return self;
+ YAML::Node root = YAML::LoadFile(file_path);
+
+ return parse_node(mrb, root);
}
static mrb_value
-cg_mCandyGear_set_camera_rotation(mrb_state *mrb, mrb_value self)
+cg_mCandyGear_set_views(mrb_state *mrb, mrb_value self)
{
- std::shared_ptr<glm::vec3> *camera_rotation;
+ struct RClass *cg_m, *cg_cView;
+ mrb_value *array;
+ mrb_int array_len;
- mrb_get_args(mrb, "d", &camera_rotation, &cg_rotation_3d_type);
- cg_core.vk_graphics_pipeline_3d->camera_rotation = (*camera_rotation);
+ std::vector<std::shared_ptr<VK::View>> views;
- return self;
-}
-
-static mrb_value
-cg_mCandyGear_load_yaml(mrb_state *mrb, mrb_value self)
-{
- const char *file_path;
+ cg_m = mrb_module_get(mrb, "CandyGear");
+ cg_cView = mrb_class_get_under(mrb, cg_m, "View");
- mrb_get_args(mrb, "z", &file_path);
+ mrb_get_args(mrb, "a", &array, &array_len);
+ for(mrb_int i{0}; i < array_len; i++)
+ {
+ if(mrb_obj_is_kind_of(mrb, array[i], cg_cView))
+ {
+ auto v = (std::shared_ptr<VK::View>*)DATA_PTR(array[i]);
+ views.push_back(*v);
+ }
+ }
- YAML::Node root = YAML::LoadFile(file_path);
+ // A Renderer need at least one view to work.
+ if(views.size() > 0)
+ {
+ delete cg_core.vk_renderer;
+ cg_core.vk_renderer = new VK::Renderer({views});
+ }
- return parse_node(mrb, root);
+ return self;
}
static mrb_value
@@ -136,15 +147,10 @@ cg_candy_gear_init(mrb_state *mrb)
cg_m = mrb_module_get(mrb, "CandyGear");
mrb_define_class_method(
- mrb, cg_m, "camera_position=", cg_mCandyGear_set_camera_position,
- MRB_ARGS_REQ(1));
- mrb_define_class_method(
- mrb, cg_m, "camera_rotation=", cg_mCandyGear_set_camera_rotation,
- MRB_ARGS_REQ(1));
-
- mrb_define_class_method(
mrb, cg_m, "load_yaml", cg_mCandyGear_load_yaml, MRB_ARGS_REQ(1));
mrb_define_class_method(
+ mrb, cg_m, "views=", cg_mCandyGear_set_views, MRB_ARGS_REQ(1));
+ mrb_define_class_method(
mrb, cg_m, "log", cg_mCandyGear_log, MRB_ARGS_REQ(2));
mrb_define_class_method(
mrb, cg_m, "quit", cg_mCandyGear_quit, MRB_ARGS_NONE());
diff --git a/src/core.cpp b/src/core.cpp
index 46fb6eb..5827ef6 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -62,8 +62,6 @@ load_variables(void *obj)
cg_core.game_name = new char[game_name.size() + 1];
strcpy(cg_core.game_name, game_name.c_str());
- cg_core.game_width = root["game"]["width"].as<int>();
- cg_core.game_height = root["game"]["height"].as<int>();
cg_core.screen_width = root["screen"]["width"].as<int>();
cg_core.screen_height = root["screen"]["height"].as<int>();
@@ -491,12 +489,13 @@ unload_vk_graphics_pipeline_2d_layout(void *obj)
delete cg_core.vk_graphics_pipeline_2d_layout;
}
-static void
+void
load_vk_graphics_pipeline_3d(void *obj)
{
try
{
- cg_core.vk_graphics_pipeline_3d = new VK::GraphicsPipeline3D();
+ cg_core.vk_graphics_pipeline_3d =
+ std::make_unique<VK::GraphicsPipeline3D>();
}
catch(const CommandError &e)
{
@@ -504,18 +503,19 @@ load_vk_graphics_pipeline_3d(void *obj)
}
}
-static void
+void
unload_vk_graphics_pipeline_3d(void *obj)
{
- delete cg_core.vk_graphics_pipeline_3d;
+ cg_core.vk_graphics_pipeline_3d = nullptr;
}
-static void
+void
load_vk_graphics_pipeline_2d(void *obj)
{
try
{
- cg_core.vk_graphics_pipeline_2d = new VK::GraphicsPipeline2D();
+ cg_core.vk_graphics_pipeline_2d =
+ std::make_unique<VK::GraphicsPipeline2D>();
}
catch(const CommandError &e)
{
@@ -523,10 +523,10 @@ load_vk_graphics_pipeline_2d(void *obj)
}
}
-static void
+void
unload_vk_graphics_pipeline_2d(void *obj)
{
- delete cg_core.vk_graphics_pipeline_2d;
+ cg_core.vk_graphics_pipeline_2d = nullptr;
}
static void
@@ -534,7 +534,12 @@ load_vk_renderer(void *obj)
{
try
{
- cg_core.vk_renderer = new VK::Renderer();
+ glm::vec4 region(
+ 0.f, 0.f,
+ static_cast<float>(cg_core.screen_width),
+ static_cast<float>(cg_core.screen_height));
+ cg_core.vk_renderer = new VK::Renderer(
+ {std::make_shared<VK::View>(region)});
}
catch(const CommandError &e)
{
diff --git a/src/core.hpp b/src/core.hpp
index c7dbceb..c4e9a6c 100644
--- a/src/core.hpp
+++ b/src/core.hpp
@@ -75,14 +75,6 @@ struct cg_sCore
/**
* @{
- * This is the amount of pixel the games use to render a buffer. The image in
- * this buffer is then rendered to the screen.
- */
- uint32_t game_width, game_height;
- /// @}
-
- /**
- * @{
* This is the ammount of pixel that the games uses when rendering to the
* screen.
*/
@@ -110,8 +102,8 @@ struct cg_sCore
VK::GraphicsPipeline3DLayout *vk_graphics_pipeline_3d_layout;
VK::GraphicsPipeline2DLayout *vk_graphics_pipeline_2d_layout;
- VK::GraphicsPipeline3D *vk_graphics_pipeline_3d;
- VK::GraphicsPipeline2D *vk_graphics_pipeline_2d;
+ std::unique_ptr<VK::GraphicsPipeline3D> vk_graphics_pipeline_3d;
+ std::unique_ptr<VK::GraphicsPipeline2D> vk_graphics_pipeline_2d;
VK::Renderer *vk_renderer;
diff --git a/src/main.cpp b/src/main.cpp
index 590ea89..21e2c29 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -27,6 +27,7 @@
#include "texture.hpp"
#include "vector_3d.hpp"
#include "vector_4d.hpp"
+#include "view.hpp"
cg_sCore cg_core;
@@ -69,6 +70,7 @@ int main(int argc, char *argv[])
cg_texture_init(cg_core.mrb);
cg_vector_3d_init(cg_core.mrb);
cg_vector_4d_init(cg_core.mrb);
+ cg_view_init(cg_core.mrb);
main_obj = mrb_obj_iv_inspect(cg_core.mrb, cg_core.mrb->top_self);
sym_init = mrb_intern_cstr(cg_core.mrb, "init");
diff --git a/src/model.cpp b/src/model.cpp
index 45744f6..6a6e470 100644
--- a/src/model.cpp
+++ b/src/model.cpp
@@ -70,8 +70,8 @@ cg_cModel_draw(mrb_state *mrb, mrb_value self)
instance.position = **position;
instance.rotation = **rotation;
- auto &instances = cg_core.vk_graphics_pipeline_3d->models_to_draw[
- cg_core.vk_renderer->current_frame][*ptr];
+ auto &instances = cg_core.vk_renderer->models_to_draw[
+ cg_core.vk_swapchain->current_frame][*ptr];
instances.push_back(instance);
return self;
diff --git a/src/sprite.cpp b/src/sprite.cpp
index 7c1f109..96a702a 100644
--- a/src/sprite.cpp
+++ b/src/sprite.cpp
@@ -17,8 +17,9 @@
#include "sprite.hpp"
#include "texture.hpp"
-#include "vk/sprite.hpp"
#include "vector_4d.hpp"
+#include "view.hpp"
+#include "vk/sprite.hpp"
void
cg_free_sprite(mrb_state *mrb, void* obj)
@@ -55,13 +56,13 @@ cg_cSprite_initialize(mrb_state *mrb, mrb_value self)
static mrb_value
cg_cSprite_draw(mrb_state *mrb, mrb_value self)
{
- auto *ptr = (std::shared_ptr<VK::Sprite>*)DATA_PTR(self);
-
+ std::shared_ptr<VK::View> *view;
std::shared_ptr<glm::vec4> *position;
+ auto *ptr = (std::shared_ptr<VK::Sprite>*)DATA_PTR(self);
- mrb_get_args(mrb, "d", &position, &cg_vector_4d_type);
- auto &positions = cg_core.vk_graphics_pipeline_2d->sprites_to_draw[
- cg_core.vk_renderer->current_frame][*ptr];
+ mrb_get_args(mrb, "dd", &view, &cg_view_type, &position, &cg_vector_4d_type);
+ auto &positions = (*view)->sprites_to_draw[
+ cg_core.vk_swapchain->current_frame][*ptr];
positions.push_back(*position->get());
return self;
@@ -77,5 +78,5 @@ cg_sprite_init(mrb_state *mrb)
MRB_SET_INSTANCE_TT(cg_cSprite, MRB_TT_DATA);
mrb_define_method(
mrb, cg_cSprite, "initialize", cg_cSprite_initialize, MRB_ARGS_REQ(2));
- mrb_define_method(mrb, cg_cSprite, "draw", cg_cSprite_draw, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, cg_cSprite, "draw", cg_cSprite_draw, MRB_ARGS_REQ(2));
}
diff --git a/src/view.cpp b/src/view.cpp
new file mode 100644
index 0000000..745c4bc
--- /dev/null
+++ b/src/view.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "view.hpp"
+
+#include "rotation_3d.hpp"
+#include "vector_3d.hpp"
+#include "vector_4d.hpp"
+#include "vk/view.hpp"
+
+void
+cg_free_view(mrb_state *mrb, void* obj)
+{
+ auto ptr = static_cast<std::shared_ptr<VK::View>*>(obj);
+
+ ptr->~shared_ptr();
+ mrb_free(mrb, ptr);
+}
+
+const struct mrb_data_type cg_view_type = { "CG_View", cg_free_view };
+
+static mrb_value
+cg_cView_initialize(mrb_state *mrb, mrb_value self)
+{
+ std::shared_ptr<glm::vec4> *region;
+ std::shared_ptr<VK::View> *ptr;
+
+ mrb_get_args(mrb, "d", &region, &cg_vector_4d_type);
+ ptr = (std::shared_ptr<VK::View>*)DATA_PTR(self);
+ if(ptr) mrb_free(mrb, ptr);
+ ptr = (std::shared_ptr<VK::View>*)mrb_malloc(
+ mrb, sizeof(std::shared_ptr<VK::View>));
+
+ new(ptr)std::shared_ptr<VK::View>(
+ std::make_shared<VK::View>(*region->get()));
+
+ mrb_data_init(self, ptr, &cg_view_type);
+ return self;
+}
+
+static mrb_value
+cg_cView_set_camera_position(mrb_state *mrb, mrb_value self)
+{
+ std::shared_ptr<glm::vec3> *camera_position;
+ auto ptr = (std::shared_ptr<VK::View>*)DATA_PTR(self);
+
+ mrb_get_args(mrb, "d", &camera_position, &cg_vector_3d_type);
+ (*ptr)->camera_position = (*camera_position);
+
+ return self;
+}
+
+static mrb_value
+cg_cView_set_camera_rotation(mrb_state *mrb, mrb_value self)
+{
+ std::shared_ptr<glm::vec3> *camera_rotation;
+ auto ptr = (std::shared_ptr<VK::View>*)DATA_PTR(self);
+
+ mrb_get_args(mrb, "d", &camera_rotation, &cg_rotation_3d_type);
+ (*ptr)->camera_rotation = (*camera_rotation);
+
+ return self;
+}
+
+void
+cg_view_init(mrb_state *mrb)
+{
+ struct RClass *cg_m, *cg_cView;
+
+ cg_m = mrb_module_get(mrb, "CandyGear");
+ cg_cView = mrb_define_class_under(mrb, cg_m, "View", mrb->object_class);
+ MRB_SET_INSTANCE_TT(cg_cView, MRB_TT_DATA);
+ mrb_define_method(
+ mrb, cg_cView, "initialize", cg_cView_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(
+ mrb, cg_cView, "camera_position=", cg_cView_set_camera_position,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(
+ mrb, cg_cView, "camera_rotation=", cg_cView_set_camera_rotation,
+ MRB_ARGS_REQ(1));
+}
diff --git a/src/view.hpp b/src/view.hpp
new file mode 100644
index 0000000..ae22b59
--- /dev/null
+++ b/src/view.hpp
@@ -0,0 +1,27 @@
+/*
+ * 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_VIEW_H
+#define CANDY_GEAR_VIEW_H 1
+
+#include "core.hpp"
+
+extern const struct mrb_data_type cg_view_type;
+
+void
+cg_view_init(mrb_state *mrb);
+
+#endif /* CANDY_GEAR_VIEW_H */
diff --git a/src/vk/graphics_pipeline_2d.cpp b/src/vk/graphics_pipeline_2d.cpp
index 61cfe3f..08bdb6e 100644
--- a/src/vk/graphics_pipeline_2d.cpp
+++ b/src/vk/graphics_pipeline_2d.cpp
@@ -25,123 +25,6 @@ namespace
{
void
-load_projection_uniform_buffer(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- try
- {
- self->ub_projection.reserve(cg_core.vk_swapchain->images_count);
- for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
- self->ub_projection.emplace_back(
- cg_core.vk_device_with_swapchain, sizeof(VK::UBOProjection));
- }
- catch(const std::exception& e)
- {
- throw CommandError{e.what()};
- }
-}
-
-void
-unload_projection_uniform_buffer(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- self->ub_projection.clear();
-}
-
-void
-load_descriptor_pool(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- VkDescriptorPoolSize descriptor_pool_size{};
- descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptor_pool_size.descriptorCount = self->ub_projection.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->ub_projection.size();
- 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<VK::GraphicsPipeline2D*>(obj);
-
- vkDestroyDescriptorPool(
- cg_core.vk_device_with_swapchain->device, self->descriptor_pool,
- nullptr);
-}
-
-void
-load_projection_descriptor_sets(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- std::vector<VkDescriptorSetLayout> layouts(
- self->ub_projection.size(),
- cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_projection);
-
- 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->projection_descriptor_sets.resize(layouts.size());
- if(vkAllocateDescriptorSets(
- cg_core.vk_device_with_swapchain->device, &alloc_info,
- self->projection_descriptor_sets.data()) != VK_SUCCESS)
- throw CommandError{"Failed to create Vulkan projection descriptor sets."};
-}
-
-void
-load_resources_to_descriptor_sets(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- for(auto i{0}; i < self->ub_projection.size(); i++)
- {
- VkDescriptorBufferInfo projection_info{};
- projection_info.buffer = self->ub_projection[i].buffer;
- projection_info.offset = 0;
- projection_info.range = sizeof(VK::UBOProjection);
-
- std::array<VkWriteDescriptorSet, 1> write_descriptors{};
- write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptors[0].dstSet = self->projection_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 = &projection_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::UBOProjection ubo_projection;
- ubo_projection.proj = glm::ortho(
- 0.0f, static_cast<float>(cg_core.game_width),
- 0.0f, static_cast<float>(cg_core.game_height),
- 0.0f, 100.0f);
- self->ub_projection[i].copy_data(&ubo_projection);
- }
-}
-
-void
load_framebuffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
@@ -245,10 +128,10 @@ load_pipeline(void *obj)
input_assembly.primitiveRestartEnable = VK_FALSE;
VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast<float>(cg_core.screen_width);
- viewport.height = static_cast<float>(cg_core.screen_height);
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = cg_core.screen_width;
+ viewport.height = cg_core.screen_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
@@ -368,11 +251,6 @@ unload_pipeline(void *obj)
}
const CommandChain loader{
- {&load_projection_uniform_buffer, &unload_projection_uniform_buffer},
- {&load_descriptor_pool, &unload_descriptor_pool},
- // By destroying the pool the sets are also destroyed.
- {&load_projection_descriptor_sets, nullptr},
- {&load_resources_to_descriptor_sets, nullptr},
{&load_framebuffer, &unload_framebuffer},
{&load_pipeline, &unload_pipeline}
};
@@ -382,8 +260,7 @@ const CommandChain loader{
namespace VK
{
-GraphicsPipeline2D::GraphicsPipeline2D():
- sprites_to_draw{cg_core.vk_swapchain->images_count}
+GraphicsPipeline2D::GraphicsPipeline2D()
{
loader.execute(this);
}
@@ -395,74 +272,61 @@ GraphicsPipeline2D::~GraphicsPipeline2D()
void
GraphicsPipeline2D::draw(
- const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index)
+ std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const size_t next_frame,
+ const uint32_t image_index)
{
- // Load command
+ // Set viewport
{
- 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_graphics_pipeline_2d_layout->render_pass;
- render_pass_begin.framebuffer = this->swapchain_framebuffers[image_index];
- render_pass_begin.renderArea.offset = {0, 0};
- render_pass_begin.renderArea.extent = {
- cg_core.screen_width, cg_core.screen_height};
- render_pass_begin.clearValueCount = 0;
- render_pass_begin.pClearValues = nullptr;
-
- vkCmdBeginRenderPass(
- draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
-
VkViewport vk_viewport{};
- vk_viewport.width = static_cast<float>(cg_core.screen_width);
- vk_viewport.height = static_cast<float>(cg_core.screen_height);
+ 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.extent.width = cg_core.screen_width;
- vk_scissor.extent.height = cg_core.screen_height;
- vk_scissor.offset.x = 0;
- vk_scissor.offset.y = 0;
+ vk_scissor.offset.x = static_cast<int32_t>(view->region.x);
+ vk_scissor.offset.y = static_cast<int32_t>(view->region.y);
+ vk_scissor.extent.width = static_cast<uint32_t>(view->region.z);
+ vk_scissor.extent.height = static_cast<uint32_t>(view->region.w);
vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor);
+ }
- // Draw sprites
- for(auto& [sprite, positions]: this->sprites_to_draw[current_frame])
+ // Draw sprites
+ for(auto& [sprite, positions]: view->sprites_to_draw[current_frame])
+ {
+ // Commands
{
- // Commands
- {
- std::array<VkDescriptorSet, 2> vk_descriptor_sets{
- this->projection_descriptor_sets[image_index],
- sprite->descriptor_sets[image_index]};
- VkDeviceSize offsets[]{0};
-
- vkCmdBindDescriptorSets(
- draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- cg_core.vk_graphics_pipeline_2d_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);
- vkCmdBindVertexBuffers(
- draw_command_buffer, 0, 1, &sprite->vertex_buffer->buffer, offsets);
- vkCmdDraw(
- draw_command_buffer, Sprite::vertex_count, positions.size(), 0, 0);
- }
-
- VK::UBOSpritePositions ubo_sprite_positions;
- for(auto i{0}; i < positions.size(); i++)
- ubo_sprite_positions.positions[i] = positions[i];
- sprite->ub_sprite_positions[image_index].copy_data(
- &ubo_sprite_positions);
+ std::array<VkDescriptorSet, 2> vk_descriptor_sets{
+ view->descriptor_sets_2d[image_index],
+ sprite->descriptor_sets[image_index]};
+ VkDeviceSize offsets[]{0};
+
+ vkCmdBindDescriptorSets(
+ draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ cg_core.vk_graphics_pipeline_2d_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);
+ vkCmdBindVertexBuffers(
+ draw_command_buffer, 0, 1, &sprite->vertex_buffer->buffer, offsets);
+ vkCmdDraw(
+ draw_command_buffer, Sprite::vertex_count, positions.size(), 0, 0);
}
+
+ VK::UBOSpritePositions ubo_sprite_positions;
+ for(auto i{0}; i < positions.size(); i++)
+ ubo_sprite_positions.positions[i] = positions[i];
+ sprite->ub_sprite_positions[image_index].copy_data(
+ &ubo_sprite_positions);
}
- vkCmdEndRenderPass(draw_command_buffer);
// Prepare for the next frame.
- this->sprites_to_draw[next_frame].clear();
+ view->sprites_to_draw[next_frame].clear();
}
}
diff --git a/src/vk/graphics_pipeline_2d.hpp b/src/vk/graphics_pipeline_2d.hpp
index 193c06d..dd4bb29 100644
--- a/src/vk/graphics_pipeline_2d.hpp
+++ b/src/vk/graphics_pipeline_2d.hpp
@@ -17,36 +17,30 @@
#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H
#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H 1
+#include <memory>
+#include <unordered_map>
#include <vector>
#include "core.hpp"
#include "sprite.hpp"
+#include "view.hpp"
namespace VK
{
struct GraphicsPipeline2D
{
- // FIXME: if this vector get resized, it will cause a segmentation fault!
- std::vector<UniformBuffer> ub_projection;
-
- VkDescriptorPool descriptor_pool;
- std::vector<VkDescriptorSet> projection_descriptor_sets;
-
VkRenderPass render_pass;
std::vector<VkFramebuffer> swapchain_framebuffers;
VkPipeline graphic_pipeline;
- std::vector<
- std::unordered_map<std::shared_ptr<Sprite>, std::vector<glm::vec4>>>
- sprites_to_draw;
-
GraphicsPipeline2D();
~GraphicsPipeline2D();
void
- draw(const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index);
+ draw(std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const size_t next_frame,
+ const uint32_t image_index);
};
}
diff --git a/src/vk/graphics_pipeline_2d_layout.cpp b/src/vk/graphics_pipeline_2d_layout.cpp
index f8822b9..6840f2c 100644
--- a/src/vk/graphics_pipeline_2d_layout.cpp
+++ b/src/vk/graphics_pipeline_2d_layout.cpp
@@ -24,7 +24,7 @@ namespace
{
void
-load_descriptor_set_layout_projection(void *obj)
+load_descriptor_set_view(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
@@ -45,23 +45,23 @@ load_descriptor_set_layout_projection(void *obj)
if(vkCreateDescriptorSetLayout(
cg_core.vk_device_with_swapchain->device, &layout_info, nullptr,
- &self->descriptor_set_projection) != VK_SUCCESS)
+ &self->descriptor_set_view) != VK_SUCCESS)
throw CommandError{
"Failed to create Vulkan descriptor set layout for projection."};
}
void
-unload_descriptor_set_layout_projection(void *obj)
+unload_descriptor_set_view(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
vkDestroyDescriptorSetLayout(
- cg_core.vk_device_with_swapchain->device, self->descriptor_set_projection,
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_view,
nullptr);
}
void
-load_descriptor_set_layout_sprite(void *obj)
+load_descriptor_set_sprite(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
@@ -95,22 +95,22 @@ load_descriptor_set_layout_sprite(void *obj)
}
void
-unload_descriptor_set_layout_sprite(void *obj)
+unload_descriptor_set_sprite(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
vkDestroyDescriptorSetLayout(
- cg_core.vk_device_with_swapchain->device,
- self->descriptor_set_sprite, nullptr);
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_sprite,
+ nullptr);
}
void
-load_pipeline_layout(void *obj)
+load_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
std::array<VkDescriptorSetLayout, 2> set_layouts{
- self->descriptor_set_projection, self->descriptor_set_sprite
+ self->descriptor_set_view, self->descriptor_set_sprite
};
VkPipelineLayoutCreateInfo pipeline_layout_info{};
@@ -127,7 +127,7 @@ load_pipeline_layout(void *obj)
}
void
-unload_pipeline_layout(void *obj)
+unload_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
@@ -207,10 +207,9 @@ unload_render_pass(void *obj)
}
const CommandChain loader{
- {&load_descriptor_set_layout_projection,
- &unload_descriptor_set_layout_projection},
- {&load_descriptor_set_layout_sprite, &unload_descriptor_set_layout_sprite},
- {&load_pipeline_layout, &unload_pipeline_layout},
+ {&load_descriptor_set_view, &unload_descriptor_set_view},
+ {&load_descriptor_set_sprite, &unload_descriptor_set_sprite},
+ {&load_pipeline, &unload_pipeline},
{&load_render_pass, &unload_render_pass}
};
diff --git a/src/vk/graphics_pipeline_2d_layout.hpp b/src/vk/graphics_pipeline_2d_layout.hpp
index 520bbc1..1e0a794 100644
--- a/src/vk/graphics_pipeline_2d_layout.hpp
+++ b/src/vk/graphics_pipeline_2d_layout.hpp
@@ -22,9 +22,19 @@
namespace VK
{
+struct UBOView2D
+{
+ glm::mat4 proj;
+};
+
+struct UBOSpritePositions
+{
+ glm::vec4 positions[128];
+};
+
struct GraphicsPipeline2DLayout
{
- VkDescriptorSetLayout descriptor_set_projection;
+ VkDescriptorSetLayout descriptor_set_view;
VkDescriptorSetLayout descriptor_set_sprite;
VkPipelineLayout pipeline;
VkRenderPass render_pass;
diff --git a/src/vk/graphics_pipeline_3d.cpp b/src/vk/graphics_pipeline_3d.cpp
index 31e9365..02fbfd9 100644
--- a/src/vk/graphics_pipeline_3d.cpp
+++ b/src/vk/graphics_pipeline_3d.cpp
@@ -28,16 +28,16 @@ namespace
{
void
-load_view_projection_uniform_buffer(void *obj)
+load_world_vert_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
try
{
- self->ub_view_projection.reserve(cg_core.vk_swapchain->images_count);
+ 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_view_projection.emplace_back(
- cg_core.vk_device_with_swapchain, sizeof(VK::UBOViewProjection));
+ self->ub_world_vert.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOWorld3D_Vert));
}
catch(const std::exception& e)
{
@@ -46,24 +46,24 @@ load_view_projection_uniform_buffer(void *obj)
}
void
-unload_view_projection_uniform_buffer(void *obj)
+unload_world_vert_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
- self->ub_view_projection.clear();
+ self->ub_world_vert.clear();
}
void
-load_directional_light_uniform_buffer(void *obj)
+load_world_frag_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
try
{
- self->ub_view_projection.reserve(cg_core.vk_swapchain->images_count);
+ 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_directional_light.emplace_back(
- cg_core.vk_device_with_swapchain, sizeof(VK::UBODirectionalLight));
+ self->ub_world_frag.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOWorld3D_Frag));
}
catch(const std::exception& e)
{
@@ -72,11 +72,11 @@ load_directional_light_uniform_buffer(void *obj)
}
void
-unload_directional_light_uniform_buffer(void *obj)
+unload_world_frag_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
- self->ub_directional_light.clear();
+ self->ub_world_frag.clear();
}
void
@@ -84,17 +84,18 @@ load_descriptor_pool(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(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 =
- self->ub_view_projection.size() + self->ub_directional_light.size();
+ 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 = self->ub_view_projection.size() +
- self->ub_directional_light.size();
+ pool_info.maxSets = uniform_buffers_count;
pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &descriptor_pool_size;
@@ -115,26 +116,25 @@ unload_descriptor_pool(void *obj)
}
void
-load_world_view_descriptor_sets(void *obj)
+load_descriptor_sets_world(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
std::vector<VkDescriptorSetLayout> layouts(
cg_core.vk_swapchain->images_count,
- cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_world_view);
+ cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_world);
VkDescriptorSetAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = self->descriptor_pool;
- alloc_info.descriptorSetCount = self->ub_view_projection.size();
+ alloc_info.descriptorSetCount = layouts.size();
alloc_info.pSetLayouts = layouts.data();
- self->world_view_descriptor_sets.resize(
- cg_core.vk_swapchain->images_count);
+ self->descriptor_sets_world.resize(layouts.size());
if(vkAllocateDescriptorSets(
cg_core.vk_device_with_swapchain->device, &alloc_info,
- self->world_view_descriptor_sets.data()) != VK_SUCCESS)
- throw CommandError{"Failed to create Vulkan world view descriptor set."};
+ self->descriptor_sets_world.data()) != VK_SUCCESS)
+ throw CommandError{"Failed to create Vulkan world descriptor set."};
}
void
@@ -142,36 +142,36 @@ load_resources_to_descriptor_sets(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
- for(auto i{0}; i < self->ub_view_projection.size(); i++)
+ for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
{
- VkDescriptorBufferInfo view_projection_info{};
- view_projection_info.buffer = self->ub_view_projection[i].buffer;
- view_projection_info.offset = 0;
- view_projection_info.range = sizeof(VK::UBOViewProjection);
+ 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::UBOWorld3D_Vert);
- VkDescriptorBufferInfo directional_light_info{};
- directional_light_info.buffer = self->ub_directional_light[i].buffer;
- directional_light_info.offset = 0;
- directional_light_info.range = sizeof(VK::UBODirectionalLight);
+ 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::UBOWorld3D_Frag);
std::array<VkWriteDescriptorSet, 2> write_descriptors{};
write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptors[0].dstSet = self->world_view_descriptor_sets[i];
+ 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 = &view_projection_info;
+ 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->world_view_descriptor_sets[i];
+ 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 = &directional_light_info;
+ write_descriptors[1].pBufferInfo = &world_frag_info;
write_descriptors[1].pImageInfo = nullptr;
write_descriptors[1].pTexelBufferView = nullptr;
@@ -369,10 +369,10 @@ load_pipeline(void *obj)
input_assembly.primitiveRestartEnable = VK_FALSE;
VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast<float>(cg_core.screen_width);
- viewport.height = static_cast<float>(cg_core.screen_height);
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = cg_core.screen_width;
+ viewport.height = cg_core.screen_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
@@ -505,13 +505,11 @@ unload_pipeline(void *obj)
}
const CommandChain loader{
- {&load_view_projection_uniform_buffer,
- &unload_view_projection_uniform_buffer},
- {&load_directional_light_uniform_buffer,
- &unload_directional_light_uniform_buffer},
+ {&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_world_view_descriptor_sets, nullptr},
+ {&load_descriptor_sets_world, nullptr},
{&load_resources_to_descriptor_sets, nullptr},
{&load_depth_image, &unload_depth_image},
{&load_depth_image_view, &unload_depth_image_view},
@@ -524,10 +522,7 @@ const CommandChain loader{
namespace VK
{
-GraphicsPipeline3D::GraphicsPipeline3D():
- camera_position{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
- camera_rotation{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
- models_to_draw{cg_core.vk_swapchain->images_count}
+GraphicsPipeline3D::GraphicsPipeline3D()
{
loader.execute(this);
}
@@ -539,138 +534,116 @@ GraphicsPipeline3D::~GraphicsPipeline3D()
void
GraphicsPipeline3D::draw(
- const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index)
+ std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const uint32_t image_index)
{
- // Load command.
+ // Set viewport
{
- // Dark gray blue.
- std::array<VkClearValue, 2> clear_values{};
- clear_values[0].color = {0.12f, 0.12f, 0.18f, 1.0f};
- clear_values[1].depthStencil = {1.0f, 0};
-
- 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_graphics_pipeline_3d_layout->render_pass;
- render_pass_begin.framebuffer = this->swapchain_framebuffers[image_index];
- render_pass_begin.renderArea.offset = {0, 0};
- render_pass_begin.renderArea.extent = {
- cg_core.screen_width, cg_core.screen_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);
-
VkViewport vk_viewport{};
- vk_viewport.width = static_cast<float>(cg_core.screen_width);
- vk_viewport.height = static_cast<float>(cg_core.screen_height);
+ 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.extent.width = cg_core.screen_width;
- vk_scissor.extent.height = cg_core.screen_height;
- vk_scissor.offset.x = 0;
- vk_scissor.offset.y = 0;
+ vk_scissor.offset.x = static_cast<int32_t>(view->region.x);
+ vk_scissor.offset.y = static_cast<int32_t>(view->region.y);
+ vk_scissor.extent.width = static_cast<uint32_t>(view->region.z);
+ vk_scissor.extent.height = static_cast<uint32_t>(view->region.w);
vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor);
+ }
- // Draw models
- for(auto& [model, instances] : this->models_to_draw[current_frame])
+ // Draw models
+ for(auto& [model, instances]:
+ cg_core.vk_renderer->models_to_draw[current_frame])
+ {
+ // Commands
{
- // Commands
- {
- std::array<VkDescriptorSet, 2> vk_descriptor_sets{
- this->world_view_descriptor_sets[image_index],
- model->descriptor_sets[image_index]};
- VkBuffer vertex_buffers[]{model->vertex_buffer->buffer};
- VkDeviceSize offsets[]{0};
-
- 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);
- vkCmdBindPipeline(
- draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- this->graphic_pipeline);
- vkCmdBindVertexBuffers(
- draw_command_buffer, 0, 1, vertex_buffers, offsets);
- vkCmdBindIndexBuffer(
- draw_command_buffer, model->index_buffer->buffer, 0,
- VK_INDEX_TYPE_UINT32);
- vkCmdDrawIndexed(
- draw_command_buffer, model->index_count, instances.size(), 0, 0, 0);
- }
-
- VK::UBOModelInstance ubo_model_instance;
-
- for(int i{0}; i < instances.size(); i++)
- {
- // Object matrix.
- glm::mat4 instance_matrix{1.0f};
- instance_matrix = glm::translate(
- instance_matrix, instances[i].position);
- instance_matrix = glm::rotate(
- instance_matrix, instances[i].rotation.x, glm::vec3{1.0, 0.0, 0.0});
- instance_matrix = glm::rotate(
- instance_matrix, instances[i].rotation.y, glm::vec3{0.0, 1.0, 0.0});
- instance_matrix = glm::rotate(
- instance_matrix, instances[i].rotation.z, glm::vec3{0.0, 0.0, 1.0});
-
- ubo_model_instance.instances[i] = instance_matrix;
- }
-
- model->ub_model_instance[image_index].copy_data(&ubo_model_instance);
+ std::array<VkDescriptorSet, 3> vk_descriptor_sets{
+ this->descriptor_sets_world[image_index],
+ view->descriptor_sets_3d[image_index],
+ model->descriptor_sets[image_index]};
+ VkBuffer vertex_buffers[]{model->vertex_buffer->buffer};
+ VkDeviceSize offsets[]{0};
+
+ 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);
+ vkCmdBindPipeline(
+ draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ this->graphic_pipeline);
+ vkCmdBindVertexBuffers(
+ draw_command_buffer, 0, 1, vertex_buffers, offsets);
+ vkCmdBindIndexBuffer(
+ draw_command_buffer, model->index_buffer->buffer, 0,
+ VK_INDEX_TYPE_UINT32);
+ vkCmdDrawIndexed(
+ draw_command_buffer, model->index_count, instances.size(), 0, 0, 0);
}
- vkCmdEndRenderPass(draw_command_buffer);
+ VK::UBOModelInstance ubo_model_instance;
+
+ for(int i{0}; i < instances.size(); i++)
+ {
+ // Object matrix.
+ glm::mat4 instance_matrix{1.0f};
+ instance_matrix = glm::translate(
+ instance_matrix, instances[i].position);
+ instance_matrix = glm::rotate(
+ instance_matrix, instances[i].rotation.x, glm::vec3{1.0, 0.0, 0.0});
+ instance_matrix = glm::rotate(
+ instance_matrix, instances[i].rotation.y, glm::vec3{0.0, 1.0, 0.0});
+ instance_matrix = glm::rotate(
+ instance_matrix, instances[i].rotation.z, glm::vec3{0.0, 0.0, 1.0});
+
+ ubo_model_instance.instances[i] = instance_matrix;
+ }
+
+ model->ub_model_instance[image_index].copy_data(&ubo_model_instance);
}
- // Update view projection uniform buffers
+ // Update view uniform buffers
{
- VK::UBOViewProjection ubo_view_projection{};
+ VK::UBOView3D ubo_view_3d{};
// View matrix.
- ubo_view_projection.view = glm::mat4{1.0f};
- ubo_view_projection.view = glm::translate(
- ubo_view_projection.view, *this->camera_position);
- ubo_view_projection.view = glm::rotate(
- ubo_view_projection.view, this->camera_rotation->y,
- glm::vec3{0.0, 1.0, 0.0});
- ubo_view_projection.view = glm::rotate(
- ubo_view_projection.view, this->camera_rotation->x,
- glm::vec3{1.0, 0.0, 0.0});
- ubo_view_projection.view = glm::rotate(
- ubo_view_projection.view, this->camera_rotation->z,
- glm::vec3{0.0, 0.0, 1.0});
- ubo_view_projection.view = glm::inverse(ubo_view_projection.view);
+ ubo_view_3d.view = glm::mat4{1.0f};
+ ubo_view_3d.view = glm::translate(
+ ubo_view_3d.view, *view->camera_position);
+ ubo_view_3d.view = glm::rotate(
+ ubo_view_3d.view, view->camera_rotation->y, glm::vec3{0.0, 1.0, 0.0});
+ ubo_view_3d.view = glm::rotate(
+ ubo_view_3d.view, view->camera_rotation->x, glm::vec3{1.0, 0.0, 0.0});
+ ubo_view_3d.view = glm::rotate(
+ ubo_view_3d.view, view->camera_rotation->z, glm::vec3{0.0, 0.0, 1.0});
+ ubo_view_3d.view = glm::inverse(ubo_view_3d.view);
// Projection matrix.
- ubo_view_projection.proj = glm::perspective(
+ ubo_view_3d.proj = glm::perspective(
glm::radians(45.0f),
- cg_core.screen_width / static_cast<float>(cg_core.screen_height),
+ view->region.z / view->region.w,
0.1f, 100.0f);
- ubo_view_projection.proj[1][1] *= -1;
+ ubo_view_3d.proj[1][1] *= -1;
- ubo_view_projection.ambient_color = glm::vec4{0.25, 0.25, 0.25, 1.0};
-
- this->ub_view_projection[image_index].copy_data(&ubo_view_projection);
+ view->ub_3d[image_index].copy_data(&ubo_view_3d);
}
- // Update directional light uniform buffers
+ // Update world uniform buffer
{
- UBODirectionalLight ubo_directional_light{};
- ubo_directional_light.direction = glm::vec3{-0.57735, -0.57735, -0.57735};
- ubo_directional_light.color = glm::vec4{0.8, 0.8, 0.8, 1.0};
-
- this->ub_directional_light[image_index].copy_data(&ubo_directional_light);
+ UBOWorld3D_Vert ubo_world_3d_vert{};
+ ubo_world_3d_vert.ambient_light_color = glm::vec4{0.25, 0.25, 0.25, 1.0};
+ this->ub_world_vert[image_index].copy_data(&ubo_world_3d_vert);
+
+ UBOWorld3D_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};
+ this->ub_world_frag[image_index].copy_data(&ubo_world_3d_frag);
}
-
- // Prepare for the next frame.
- this->models_to_draw[next_frame].clear();
}
}
diff --git a/src/vk/graphics_pipeline_3d.hpp b/src/vk/graphics_pipeline_3d.hpp
index 97ca63c..a7cf117 100644
--- a/src/vk/graphics_pipeline_3d.hpp
+++ b/src/vk/graphics_pipeline_3d.hpp
@@ -26,6 +26,7 @@
#include "model.hpp"
#include "model_instance.hpp"
#include "uniform_buffer.hpp"
+#include "view.hpp"
namespace VK
{
@@ -38,27 +39,21 @@ struct GraphicsPipeline3D
VkImageView depth_image_view;
// FIXME: if this vector get resized, it will cause a segmentation fault!
- std::vector<UniformBuffer> ub_view_projection;
- std::vector<UniformBuffer> ub_directional_light;
+ std::vector<UniformBuffer> ub_world_vert;
+ std::vector<UniformBuffer> ub_world_frag;
VkDescriptorPool descriptor_pool;
- std::vector<VkDescriptorSet> world_view_descriptor_sets;
+ std::vector<VkDescriptorSet> descriptor_sets_world;
std::vector<VkFramebuffer> swapchain_framebuffers;
VkPipeline graphic_pipeline;
- std::shared_ptr<glm::vec3> camera_position;
- std::shared_ptr<glm::vec3> camera_rotation;
- std::vector<std::unordered_map<
- std::shared_ptr<Model>, std::vector<ModelInstance>>>
- models_to_draw;
-
GraphicsPipeline3D();
~GraphicsPipeline3D();
void
- draw(const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index);
+ draw(std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const uint32_t image_index);
};
}
diff --git a/src/vk/graphics_pipeline_3d_layout.cpp b/src/vk/graphics_pipeline_3d_layout.cpp
index 62c894c..4374ab9 100644
--- a/src/vk/graphics_pipeline_3d_layout.cpp
+++ b/src/vk/graphics_pipeline_3d_layout.cpp
@@ -22,8 +22,9 @@
namespace
{
+
void
-load_descriptor_set_layout_world_view(void *obj)
+load_descriptor_set_world(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -49,23 +50,59 @@ load_descriptor_set_layout_world_view(void *obj)
if(vkCreateDescriptorSetLayout(
cg_core.vk_device_with_swapchain->device, &layout_info, nullptr,
- &self->descriptor_set_world_view) != VK_SUCCESS)
+ &self->descriptor_set_world) != VK_SUCCESS)
throw CommandError{
"Failed to create Vulkan descriptor set layout for world view."};
}
void
-unload_descriptor_set_layout_world_view(void *obj)
+unload_descriptor_set_world(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
vkDestroyDescriptorSetLayout(
- cg_core.vk_device_with_swapchain->device,
- self->descriptor_set_world_view, nullptr);
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_world,
+ nullptr);
+}
+
+void
+load_descriptor_set_view(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
+
+ std::array<VkDescriptorSetLayoutBinding, 1> 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;
+
+ 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->descriptor_set_view) != VK_SUCCESS)
+ throw CommandError{
+ "Failed to create Vulkan descriptor set layout for world view."};
+}
+
+void
+unload_descriptor_set_view(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
+
+ vkDestroyDescriptorSetLayout(
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_view,
+ nullptr);
}
void
-load_descriptor_set_layout_model_instance(void *obj)
+load_descriptor_set_model_instance(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -99,7 +136,7 @@ load_descriptor_set_layout_model_instance(void *obj)
}
void
-unload_descriptor_set_layout_model_instance(void *obj)
+unload_descriptor_set_model_instance(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -109,12 +146,13 @@ unload_descriptor_set_layout_model_instance(void *obj)
}
void
-load_pipeline_layout(void *obj)
+load_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
- std::array<VkDescriptorSetLayout, 2> set_layouts{
- self->descriptor_set_world_view,
+ std::array<VkDescriptorSetLayout, 3> set_layouts{
+ self->descriptor_set_world,
+ self->descriptor_set_view,
self->descriptor_set_model_instance};
VkPipelineLayoutCreateInfo pipeline_layout_info{};
@@ -131,7 +169,7 @@ load_pipeline_layout(void *obj)
}
void
-unload_pipeline_layout(void *obj)
+unload_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -226,11 +264,10 @@ unload_render_pass(void *obj)
}
const CommandChain loader{
- {&load_descriptor_set_layout_world_view,
- &unload_descriptor_set_layout_world_view},
- {&load_descriptor_set_layout_model_instance,
- &unload_descriptor_set_layout_model_instance},
- {&load_pipeline_layout, &unload_pipeline_layout},
+ {&load_descriptor_set_world, &unload_descriptor_set_world},
+ {&load_descriptor_set_view, &unload_descriptor_set_view},
+ {&load_descriptor_set_model_instance, &unload_descriptor_set_model_instance},
+ {&load_pipeline, &unload_pipeline},
{&load_render_pass, &unload_render_pass}
};
diff --git a/src/vk/graphics_pipeline_3d_layout.hpp b/src/vk/graphics_pipeline_3d_layout.hpp
index 296bdb2..d45a778 100644
--- a/src/vk/graphics_pipeline_3d_layout.hpp
+++ b/src/vk/graphics_pipeline_3d_layout.hpp
@@ -22,9 +22,32 @@
namespace VK
{
+struct UBOWorld3D_Vert
+{
+ glm::vec4 ambient_light_color;
+};
+
+struct UBOWorld3D_Frag
+{
+ glm::vec3 directional_light_direction;
+ glm::vec4 directional_light_color;
+};
+
+struct UBOView3D
+{
+ glm::mat4 view;
+ glm::mat4 proj;
+};
+
+struct UBOModelInstance
+{
+ glm::mat4 instances[128];
+};
+
struct GraphicsPipeline3DLayout
{
- VkDescriptorSetLayout descriptor_set_world_view;
+ VkDescriptorSetLayout descriptor_set_world;
+ VkDescriptorSetLayout descriptor_set_view;
VkDescriptorSetLayout descriptor_set_model_instance;
VkPipelineLayout pipeline;
VkRenderPass render_pass;
diff --git a/src/vk/renderer.cpp b/src/vk/renderer.cpp
index 33a4bf7..e806716 100644
--- a/src/vk/renderer.cpp
+++ b/src/vk/renderer.cpp
@@ -16,64 +16,14 @@
#include "renderer.hpp"
+#include <array>
+
#include "../core.hpp"
namespace
{
void
-load_frame_sync(void *obj)
-{
- auto self = static_cast<VK::Renderer*>(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<VK::Renderer*>(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);
- }
-}
-
-void
load_queue_family(void *obj)
{
auto self = static_cast<VK::Renderer*>(obj);
@@ -103,9 +53,10 @@ unload_command_pool(void *obj)
{
auto self = static_cast<VK::Renderer*>(obj);
- vkWaitForFences(cg_core.vk_device_with_swapchain->device, 2,
- self->in_flight_fences.data(), VK_TRUE,
- std::numeric_limits<uint64_t>::max());
+ 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<uint64_t>::max());
vkDestroyCommandPool(
self->queue_family->device->device, self->command_pool, nullptr);
}
@@ -132,7 +83,6 @@ load_draw_command_buffer(void *obj)
}
const CommandChain loader{
- {&load_frame_sync, &unload_frame_sync},
{&load_queue_family, nullptr},
{&load_command_pool, &unload_command_pool},
{&load_draw_command_buffer, nullptr}
@@ -143,12 +93,18 @@ const CommandChain loader{
namespace VK
{
-Renderer::Renderer():
- current_frame{0}
+Renderer::Renderer(std::vector<std::shared_ptr<View>> views):
+ models_to_draw{cg_core.vk_swapchain->images_count},
+ views{views}
{
loader.execute(this);
}
+Renderer::Renderer(std::initializer_list<std::shared_ptr<View>> views):
+ Renderer{std::vector<std::shared_ptr<View>>(views)}
+{
+}
+
Renderer::~Renderer()
{
loader.revert(this);
@@ -158,24 +114,26 @@ void
Renderer::draw()
{
vkWaitForFences(cg_core.vk_device_with_swapchain->device, 1,
- &this->in_flight_fences[this->current_frame], VK_TRUE,
- std::numeric_limits<uint64_t>::max());
+ &cg_core.vk_swapchain->in_flight_fences[
+ cg_core.vk_swapchain->current_frame], VK_TRUE,
+ std::numeric_limits<uint64_t>::max());
vkResetFences(cg_core.vk_device_with_swapchain->device, 1,
- &this->in_flight_fences[this->current_frame]);
+ &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<uint64_t>::max(),
- this->image_available_semaphores[this->current_frame],
- VK_NULL_HANDLE, &image_index);
+ cg_core.vk_device_with_swapchain->device,
+ cg_core.vk_swapchain->swapchain, std::numeric_limits<uint64_t>::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[this->current_frame];
+ this->draw_command_buffers[cg_core.vk_swapchain->current_frame];
vkResetCommandBuffer(draw_command_buffer, 0);
- auto next_frame = this->current_frame + 1;
- if(next_frame == this->max_frames_in_flight) next_frame = 0;
+ auto next_frame = cg_core.vk_swapchain->current_frame + 1;
+ if(next_frame == Swapchain::max_frames_in_flight) next_frame = 0;
// Begin command buffer.
{
@@ -187,10 +145,64 @@ Renderer::draw()
throw std::runtime_error{"Failed to beggin draw command buffer."};
}
- cg_core.vk_graphics_pipeline_3d->draw(
- draw_command_buffer, current_frame, next_frame, image_index);
- cg_core.vk_graphics_pipeline_2d->draw(
- draw_command_buffer, current_frame, next_frame, image_index);
+ // 3D drawing.
+ {
+ // Dark gray blue.
+ std::array<VkClearValue, 2> clear_values{};
+ clear_values[0].color = {0.12f, 0.12f, 0.18f, 1.0f};
+ clear_values[1].depthStencil = {1.0f, 0};
+
+ 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_graphics_pipeline_3d_layout->render_pass;
+ render_pass_begin.framebuffer =
+ cg_core.vk_graphics_pipeline_3d->swapchain_framebuffers[image_index];
+ render_pass_begin.renderArea.offset = {0, 0};
+ render_pass_begin.renderArea.extent = {
+ static_cast<uint32_t>(cg_core.screen_width),
+ static_cast<uint32_t>(cg_core.screen_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)
+ cg_core.vk_graphics_pipeline_3d->draw(
+ view, draw_command_buffer, cg_core.vk_swapchain->current_frame,
+ image_index);
+
+ vkCmdEndRenderPass(draw_command_buffer);
+ }
+
+ // 2D drawing
+ {
+ 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_graphics_pipeline_2d_layout->render_pass;
+ render_pass_begin.framebuffer =
+ cg_core.vk_graphics_pipeline_2d->swapchain_framebuffers[image_index];
+ render_pass_begin.renderArea.offset = {0, 0};
+ render_pass_begin.renderArea.extent = {
+ static_cast<uint32_t>(cg_core.screen_width),
+ static_cast<uint32_t>(cg_core.screen_height)};
+ render_pass_begin.clearValueCount = 0;
+ render_pass_begin.pClearValues = nullptr;
+
+ vkCmdBeginRenderPass(
+ draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+ for(auto &view: this->views)
+ cg_core.vk_graphics_pipeline_2d->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)
@@ -201,11 +213,13 @@ Renderer::draw()
auto queue{this->queue_family->get_queue()};
VkSemaphore wait_semaphores[]{
- this->image_available_semaphores[this->current_frame]};
+ 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[]{
- this->render_finished_semaphores[this->current_frame]};
+ cg_core.vk_swapchain->render_finished_semaphores[
+ cg_core.vk_swapchain->current_frame]};
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -219,8 +233,8 @@ Renderer::draw()
submit_info.pSignalSemaphores = signal_semaphores;
if(vkQueueSubmit(
- queue.queue, 1, &submit_info,
- this->in_flight_fences[this->current_frame]) != VK_SUCCESS)
+ 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};
@@ -239,7 +253,8 @@ Renderer::draw()
}
// Prepare for the next frame.
- this->current_frame = next_frame;
+ this->models_to_draw[next_frame].clear();
+ cg_core.vk_swapchain->current_frame = next_frame;
}
}
diff --git a/src/vk/renderer.hpp b/src/vk/renderer.hpp
index 4b6c91d..4cd7739 100644
--- a/src/vk/renderer.hpp
+++ b/src/vk/renderer.hpp
@@ -17,27 +17,32 @@
#ifndef CANDY_GEAR_VK_RENDERER_H
#define CANDY_GEAR_VK_RENDERER_H 1
+#include <initializer_list>
+#include <memory>
#include <vector>
#include "core.hpp"
+#include "model.hpp"
+#include "model_instance.hpp"
#include "queue_family.hpp"
+#include "view.hpp"
namespace VK
{
struct Renderer
{
- static const int max_frames_in_flight{2};
- size_t current_frame;
- std::vector<VkSemaphore> image_available_semaphores;
- std::vector<VkSemaphore> render_finished_semaphores;
- std::vector<VkFence> in_flight_fences;
+ std::vector<std::unordered_map<
+ std::shared_ptr<Model>, std::vector<ModelInstance>>>
+ models_to_draw;
+ std::vector<std::shared_ptr<View>> views;
QueueFamily *queue_family;
VkCommandPool command_pool;
std::vector<VkCommandBuffer> draw_command_buffers;
- Renderer();
+ Renderer(std::vector<std::shared_ptr<View>> views);
+ Renderer(std::initializer_list<std::shared_ptr<View>> views);
~Renderer();
void
diff --git a/src/vk/swapchain.cpp b/src/vk/swapchain.cpp
index 678279e..1dd19d9 100644
--- a/src/vk/swapchain.cpp
+++ b/src/vk/swapchain.cpp
@@ -127,9 +127,62 @@ unload_image_view(void *obj)
cg_core.vk_device_with_swapchain->device, self->image_views[i], nullptr);
}
+void
+load_frame_sync(void *obj)
+{
+ auto self = static_cast<VK::Swapchain*>(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<VK::Swapchain*>(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_image_view, &unload_image_view},
+ {&load_frame_sync, &unload_frame_sync}
};
}
@@ -137,7 +190,8 @@ const CommandChain loader{
namespace VK
{
-Swapchain::Swapchain()
+Swapchain::Swapchain():
+ current_frame{0}
{
loader.execute(this);
}
diff --git a/src/vk/swapchain.hpp b/src/vk/swapchain.hpp
index 64df208..a5ade81 100644
--- a/src/vk/swapchain.hpp
+++ b/src/vk/swapchain.hpp
@@ -32,6 +32,12 @@ struct Swapchain
VkImage *images;
VkImageView *image_views;
+ static const int max_frames_in_flight{2};
+ size_t current_frame;
+ std::vector<VkSemaphore> image_available_semaphores;
+ std::vector<VkSemaphore> render_finished_semaphores;
+ std::vector<VkFence> in_flight_fences;
+
Swapchain();
~Swapchain();
};
diff --git a/src/vk/uniform_buffer.hpp b/src/vk/uniform_buffer.hpp
index 2cee9ff..e978894 100644
--- a/src/vk/uniform_buffer.hpp
+++ b/src/vk/uniform_buffer.hpp
@@ -26,34 +26,6 @@
namespace VK
{
-struct UBOSpritePositions
-{
- glm::vec4 positions[128];
-};
-
-struct UBOProjection
-{
- glm::mat4 proj;
-};
-
-struct UBOModelInstance
-{
- glm::mat4 instances[128];
-};
-
-struct UBOViewProjection
-{
- glm::mat4 view;
- glm::mat4 proj;
- glm::vec4 ambient_color;
-};
-
-struct UBODirectionalLight
-{
- glm::vec3 direction;
- glm::vec4 color;
-};
-
// FIXME: this class need to delete or create custom copy constructors!
class UniformBuffer: public BaseBuffer
{
diff --git a/src/vk/view.cpp b/src/vk/view.cpp
new file mode 100644
index 0000000..16ee60c
--- /dev/null
+++ b/src/vk/view.cpp
@@ -0,0 +1,259 @@
+/*
+ * 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 "view.hpp"
+
+#include <array>
+
+#include "../core.hpp"
+
+namespace
+{
+
+void
+load_3d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(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::UBOView3D));
+ }
+ catch(const std::exception& e)
+ {
+ throw CommandError{e.what()};
+ }
+}
+
+void
+unload_3d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ self->ub_3d.clear();
+}
+
+void
+load_2d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(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::UBOView2D));
+ }
+ catch(const std::exception& e)
+ {
+ throw CommandError{e.what()};
+ }
+}
+
+void
+unload_2d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ self->ub_2d.clear();
+}
+
+void
+load_descriptor_pool(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ uint32_t uniform_buffer_count = self->ub_3d.size() + self->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."};
+}
+
+void
+unload_descriptor_pool(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ vkDestroyDescriptorPool(
+ cg_core.vk_device_with_swapchain->device, self->descriptor_pool,
+ nullptr);
+}
+
+void
+load_descriptor_sets_3d(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ std::vector<VkDescriptorSetLayout> layouts(
+ cg_core.vk_swapchain->images_count,
+ cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_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_descriptor_sets_2d(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ std::vector<VkDescriptorSetLayout> layouts(
+ cg_core.vk_swapchain->images_count,
+ cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_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_3d(void *obj)
+{
+ auto self = static_cast<VK::View*>(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::UBOView3D);
+
+ std::array<VkWriteDescriptorSet, 1> 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);
+
+ VK::UBOView3D ubo_view_3d;
+ ubo_view_3d.proj = glm::ortho(
+ 0.0f, self->region.z,
+ 0.0f, self->region.w,
+ 0.0f, 100.0f);
+ self->ub_3d[i].copy_data(&ubo_view_3d);
+ }
+}
+
+void
+load_resources_to_descriptor_sets_2d(void *obj)
+{
+ auto self = static_cast<VK::View*>(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::UBOView2D);
+
+ std::array<VkWriteDescriptorSet, 1> 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::UBOView2D ubo_view_2d;
+ ubo_view_2d.proj = glm::ortho(
+ 0.0f, self->region.z,
+ 0.0f, self->region.w,
+ 0.0f, 100.0f);
+ self->ub_2d[i].copy_data(&ubo_view_2d);
+ }
+}
+
+const CommandChain loader{
+ {&load_3d_uniform_buffer, &unload_3d_uniform_buffer},
+ {&load_2d_uniform_buffer, &unload_2d_uniform_buffer},
+ {&load_descriptor_pool, &unload_descriptor_pool},
+ // By destroying the pool the sets are also destroyed.
+ {&load_descriptor_sets_3d, nullptr},
+ {&load_descriptor_sets_2d, nullptr},
+ {&load_resources_to_descriptor_sets_3d, nullptr},
+ {&load_resources_to_descriptor_sets_2d, nullptr}
+};
+
+}
+
+namespace VK
+{
+
+View::View(glm::vec4 region):
+ region{region},
+ camera_position{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
+ camera_rotation{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
+ sprites_to_draw{cg_core.vk_swapchain->images_count}
+{
+ loader.execute(this);
+}
+
+View::~View()
+{
+ loader.revert(this);
+}
+
+}
diff --git a/src/vk/view.hpp b/src/vk/view.hpp
new file mode 100644
index 0000000..3936413
--- /dev/null
+++ b/src/vk/view.hpp
@@ -0,0 +1,55 @@
+/*
+ * 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_H
+#define CANDY_GEAR_VK_VIEW_H 1
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "core.hpp"
+#include "sprite.hpp"
+
+namespace VK
+{
+
+struct View
+{
+ glm::vec4 region;
+
+ // FIXME: if these vectors get resized, they can cause a segmentation fault!
+ std::vector<UniformBuffer> ub_3d;
+ std::vector<UniformBuffer> ub_2d;
+
+ VkDescriptorPool descriptor_pool;
+ std::vector<VkDescriptorSet> descriptor_sets_3d;
+ std::vector<VkDescriptorSet> descriptor_sets_2d;
+
+ std::shared_ptr<glm::vec3> camera_position;
+ std::shared_ptr<glm::vec3> camera_rotation;
+
+ std::vector<
+ std::unordered_map<std::shared_ptr<Sprite>, std::vector<glm::vec4>>>
+ sprites_to_draw;
+
+ View(glm::vec4 region);
+ ~View();
+};
+
+}
+
+#endif /* CANDY_GEAR_VK_VIEW_H */
diff --git a/test/config/init.yaml b/test/config/init.yaml
index 2139b75..0a7fdcf 100644
--- a/test/config/init.yaml
+++ b/test/config/init.yaml
@@ -1,7 +1,4 @@
name: "Candy Gear Test"
-game:
- width: 640
- height: 360
screen:
width: 1280
height: 720
diff --git a/test/src/main.rb b/test/src/main.rb
index f5c0676..67ef80c 100644
--- a/test/src/main.rb
+++ b/test/src/main.rb
@@ -35,8 +35,14 @@ def init()
$camera_position = CandyGear::Vector3D.new(0.0, 0.0, 0.0);
$camera_rotation = CandyGear::Rotation3D.new(0.0, 0.0, 0.0);
- CandyGear.camera_position = $camera_position;
- CandyGear.camera_rotation = $camera_rotation;
+
+ color = CandyGear::Vector3D.new(0.12, 0.12, 0.18);
+ $view1 = CandyGear::View.new(CandyGear::Vector4D.new(0, 0, 1280, 360));
+ $view2 = CandyGear::View.new(CandyGear::Vector4D.new(0, 360, 1280, 360));
+ CandyGear.views = [$view1, $view2];
+
+ $view1.camera_position = $camera_position;
+ $view1.camera_rotation = $camera_rotation;
end
def key_down(key)
@@ -70,7 +76,7 @@ end
def quit() = CandyGear.quit();
def tick()
- $sprite.draw($sprite_position);
+ $sprite.draw($view2, $sprite_position);
$instances_rotation.rotate(0.0, BOX_ROTATION_SPEED);
$instances.each do |i|
$model.draw(i, $instances_rotation);