summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederico Linhares <fred@linhares.blue>2022-11-09 16:11:15 -0300
committerFrederico Linhares <fred@linhares.blue>2022-11-09 17:19:06 -0300
commitbde8c8bd073abeb314748d66d6402f951ecb2902 (patch)
tree69c91317baf62a0ad9e36d8e35969fd82a02e91d
parent7e9107cb1c5012fef900dfa03408e2179f1f9915 (diff)
feat create method Rectangle#draw
-rw-r--r--glsl/shader_2d_wired.frag.glsl30
-rw-r--r--glsl/shader_2d_wired.vert.glsl30
-rw-r--r--src/core.cpp69
-rw-r--r--src/core.hpp12
-rw-r--r--src/rectangle.cpp122
-rw-r--r--src/rectangle.hpp6
-rw-r--r--src/sprite.cpp21
-rw-r--r--src/view_2d.cpp30
-rw-r--r--src/view_2d.hpp6
-rw-r--r--src/view_3d.cpp17
-rw-r--r--src/vk/destination_buffer.cpp70
-rw-r--r--src/vk/destination_buffer.hpp3
-rw-r--r--src/vk/device.cpp7
-rw-r--r--src/vk/device.hpp2
-rw-r--r--src/vk/graphics_pipeline_2d_solid.cpp (renamed from src/vk/graphics_pipeline_2d.cpp)25
-rw-r--r--src/vk/graphics_pipeline_2d_solid.hpp (renamed from src/vk/graphics_pipeline_2d.hpp)12
-rw-r--r--src/vk/graphics_pipeline_2d_solid_layout.cpp (renamed from src/vk/graphics_pipeline_2d_layout.cpp)24
-rw-r--r--src/vk/graphics_pipeline_2d_solid_layout.hpp (renamed from src/vk/graphics_pipeline_2d_layout.hpp)6
-rw-r--r--src/vk/graphics_pipeline_2d_wired.cpp324
-rw-r--r--src/vk/graphics_pipeline_2d_wired.hpp46
-rw-r--r--src/vk/graphics_pipeline_2d_wired_layout.cpp225
-rw-r--r--src/vk/graphics_pipeline_2d_wired_layout.hpp43
-rw-r--r--src/vk/rectangle.cpp245
-rw-r--r--src/vk/rectangle.hpp66
-rw-r--r--src/vk/renderer.cpp51
-rw-r--r--src/vk/source_buffer.cpp13
-rw-r--r--src/vk/source_buffer.hpp4
-rw-r--r--src/vk/sprite.cpp2
-rw-r--r--src/vk/view_2d.cpp3
-rw-r--r--src/vk/view_2d.hpp2
-rw-r--r--test/src/main.rb6
31 files changed, 1323 insertions, 199 deletions
diff --git a/glsl/shader_2d_wired.frag.glsl b/glsl/shader_2d_wired.frag.glsl
new file mode 100644
index 0000000..0671223
--- /dev/null
+++ b/glsl/shader_2d_wired.frag.glsl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#version 450
+
+layout(location = 0) out vec4 out_color;
+
+layout(set = 1, binding = 0) uniform UBOModel2D
+{
+ vec3 color;
+} ubo_model_2d;
+
+void
+main()
+{
+ out_color = vec4(ubo_model_2d.color, 1.0);
+}
diff --git a/glsl/shader_2d_wired.vert.glsl b/glsl/shader_2d_wired.vert.glsl
new file mode 100644
index 0000000..97330dc
--- /dev/null
+++ b/glsl/shader_2d_wired.vert.glsl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#version 450
+
+layout(location = 0) in vec2 in_position;
+
+layout(set = 0, binding = 0) uniform UBOView2D
+{
+ mat4 proj;
+} ubo_view;
+
+void
+main()
+{
+ gl_Position = ubo_view.proj * vec4(in_position, 0.0, 1.0);
+}
diff --git a/src/core.cpp b/src/core.cpp
index f3f0e14..ae8db70 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -540,12 +540,12 @@ unload_vk_graphics_pipeline_3d_layout(void *obj)
}
void
-load_vk_graphics_pipeline_2d_layout(void *obj)
+load_vk_graphics_pipeline_2d_solid_layout(void *obj)
{
try
{
- cg_core.vk_graphics_pipeline_2d_layout =
- new VK::GraphicsPipeline2DLayout();
+ cg_core.vk_graphics_pipeline_2d_solid_layout =
+ new VK::GraphicsPipeline2DSolidLayout();
}
catch(const CommandError &e)
{
@@ -554,9 +554,29 @@ load_vk_graphics_pipeline_2d_layout(void *obj)
}
void
-unload_vk_graphics_pipeline_2d_layout(void *obj)
+unload_vk_graphics_pipeline_2d_solid_layout(void *obj)
{
- delete cg_core.vk_graphics_pipeline_2d_layout;
+ delete cg_core.vk_graphics_pipeline_2d_solid_layout;
+}
+
+void
+load_vk_graphics_pipeline_2d_wired_layout(void *obj)
+{
+ try
+ {
+ cg_core.vk_graphics_pipeline_2d_wired_layout =
+ new VK::GraphicsPipeline2DWiredLayout();
+ }
+ catch(const CommandError &e)
+ {
+ throw CommandError{"Failed to create 2d graphics pipeline."};
+ }
+}
+
+void
+unload_vk_graphics_pipeline_2d_wired_layout(void *obj)
+{
+ delete cg_core.vk_graphics_pipeline_2d_wired_layout;
}
void
@@ -580,12 +600,32 @@ unload_vk_graphics_pipeline_3d(void *obj)
}
void
-load_vk_graphics_pipeline_2d(void *obj)
+load_vk_graphics_pipeline_2d_solid(void *obj)
+{
+ try
+ {
+ cg_core.vk_graphics_pipeline_2d_solid =
+ std::make_unique<VK::GraphicsPipeline2DSolid>();
+ }
+ catch(const CommandError &e)
+ {
+ throw CommandError{"Failed to create 2d graphics pipeline."};
+ }
+}
+
+void
+unload_vk_graphics_pipeline_2d_solid(void *obj)
+{
+ cg_core.vk_graphics_pipeline_2d_solid = nullptr;
+}
+
+void
+load_vk_graphics_pipeline_2d_wired(void *obj)
{
try
{
- cg_core.vk_graphics_pipeline_2d =
- std::make_unique<VK::GraphicsPipeline2D>();
+ cg_core.vk_graphics_pipeline_2d_wired =
+ std::make_unique<VK::GraphicsPipeline2DWired>();
}
catch(const CommandError &e)
{
@@ -594,9 +634,9 @@ load_vk_graphics_pipeline_2d(void *obj)
}
void
-unload_vk_graphics_pipeline_2d(void *obj)
+unload_vk_graphics_pipeline_2d_wired(void *obj)
{
- cg_core.vk_graphics_pipeline_2d = nullptr;
+ cg_core.vk_graphics_pipeline_2d_wired = nullptr;
}
void
@@ -672,10 +712,13 @@ const CommandChain cg_sCore::loader{
{&load_vk_graphics_pipeline_3d_layout,
&unload_vk_graphics_pipeline_3d_layout},
- {&load_vk_graphics_pipeline_2d_layout,
- &unload_vk_graphics_pipeline_2d_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_graphics_pipeline_3d, &unload_vk_graphics_pipeline_3d},
- {&load_vk_graphics_pipeline_2d, &unload_vk_graphics_pipeline_2d},
+ {&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_mruby_interface, nullptr}
diff --git a/src/core.hpp b/src/core.hpp
index 0830a49..5d92cfa 100644
--- a/src/core.hpp
+++ b/src/core.hpp
@@ -46,10 +46,12 @@
#include "worker.hpp"
#include "vk/device.hpp"
+#include "vk/graphics_pipeline_2d_solid_layout.hpp"
+#include "vk/graphics_pipeline_2d_wired_layout.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_2d_layout.hpp"
#include "vk/graphics_pipeline_3d.hpp"
-#include "vk/graphics_pipeline_2d.hpp"
#include "vk/renderer.hpp"
#include "vk/swapchain.hpp"
@@ -110,9 +112,11 @@ struct cg_sCore
VK::Swapchain *vk_swapchain;
VK::GraphicsPipeline3DLayout *vk_graphics_pipeline_3d_layout;
- VK::GraphicsPipeline2DLayout *vk_graphics_pipeline_2d_layout;
+ VK::GraphicsPipeline2DSolidLayout *vk_graphics_pipeline_2d_solid_layout;
+ VK::GraphicsPipeline2DWiredLayout *vk_graphics_pipeline_2d_wired_layout;
std::unique_ptr<VK::GraphicsPipeline3D> vk_graphics_pipeline_3d;
- std::unique_ptr<VK::GraphicsPipeline2D> vk_graphics_pipeline_2d;
+ std::unique_ptr<VK::GraphicsPipeline2DSolid> vk_graphics_pipeline_2d_solid;
+ std::unique_ptr<VK::GraphicsPipeline2DWired> vk_graphics_pipeline_2d_wired;
VK::Renderer *vk_renderer;
diff --git a/src/rectangle.cpp b/src/rectangle.cpp
index 3bc0a84..18c86a4 100644
--- a/src/rectangle.cpp
+++ b/src/rectangle.cpp
@@ -16,28 +16,16 @@
#include "rectangle.hpp"
-namespace
-{
-
-constexpr bool
-align_vertically(float a_x, float a_width, float b_x, float b_width)
-{
- return a_x <= b_x + b_width && a_x + a_width >= b_x;
-}
-
-constexpr bool
-align_horizontally(float a_y, float a_height, float b_y, float b_height)
-{
- return a_y <= b_y + b_height && a_y + a_height >= b_y;
-}
-
-}
+#include "vector_3d.hpp"
+#include "view_2d.hpp"
+#include "view_3d.hpp"
void
cg_free_rectangle(mrb_state *mrb, void* obj)
{
- auto ptr = static_cast<cg_rectangle*>(obj);
+ auto ptr = static_cast<std::shared_ptr<VK::Rectangle>*>(obj);
+ ptr->~shared_ptr();
mrb_free(mrb, ptr);
}
@@ -48,17 +36,16 @@ static mrb_value
cg_cRectangle_initialize(mrb_state *mrb, mrb_value self)
{
mrb_float x, y, width, height;
- struct cg_rectangle *ptr;
+ std::shared_ptr<VK::Rectangle> *ptr;
mrb_get_args(mrb, "ffff", &x, &y, &width, &height);
- ptr = (cg_rectangle *)DATA_PTR(self);
+ ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
if(ptr) mrb_free(mrb, ptr);
- ptr = (cg_rectangle *)mrb_malloc(mrb, sizeof(cg_rectangle));
+ ptr = (std::shared_ptr<VK::Rectangle>*)mrb_malloc(
+ mrb, sizeof(std::shared_ptr<VK::Rectangle>));
- ptr->x = x;
- ptr->y = y;
- ptr->width = width;
- ptr->height = height;
+ new(ptr)std::shared_ptr<VK::Rectangle>(
+ std::make_shared<VK::Rectangle>(x, y, width, height));
mrb_data_init(self, ptr, &cg_rectangle_type);
return self;
@@ -67,122 +54,141 @@ cg_cRectangle_initialize(mrb_state *mrb, mrb_value self)
static mrb_value
cg_cRectangle_get_x(mrb_state *mrb, mrb_value self)
{
- auto ptr = (cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_float_value(mrb, ptr->x);
+ return mrb_float_value(mrb, (*ptr)->x);
}
static mrb_value
cg_cRectangle_set_x(mrb_state *mrb, mrb_value self)
{
mrb_float x;
- auto ptr = (cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
mrb_get_args(mrb, "f", &x);
- ptr->x = x;
+ (*ptr)->x = x;
- return mrb_float_value(mrb, ptr->x);
+ return mrb_float_value(mrb, (*ptr)->x);
}
static mrb_value
cg_cRectangle_get_y(mrb_state *mrb, mrb_value self)
{
- auto ptr = (cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_float_value(mrb, ptr->y);
+ return mrb_float_value(mrb, (*ptr)->y);
}
static mrb_value
cg_cRectangle_set_y(mrb_state *mrb, mrb_value self)
{
mrb_float y;
- auto *ptr = (cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
mrb_get_args(mrb, "f", &y);
- ptr->y = y;
+ (*ptr)->y = y;
- return mrb_float_value(mrb, ptr->y);
+ return mrb_float_value(mrb, (*ptr)->y);
}
static mrb_value
cg_cRectangle_get_width(mrb_state *mrb, mrb_value self)
{
- auto *ptr = (cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_float_value(mrb, ptr->width);
+ return mrb_float_value(mrb, (*ptr)->width);
}
static mrb_value
cg_cRectangle_set_width(mrb_state *mrb, mrb_value self)
{
mrb_float width;
- auto *ptr = (struct cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
mrb_get_args(mrb, "f", &width);
- ptr->width = width;
+ (*ptr)->width = width;
- return mrb_float_value(mrb, ptr->width);
+ return mrb_float_value(mrb, (*ptr)->width);
}
static mrb_value
cg_cRectangle_get_height(mrb_state *mrb, mrb_value self)
{
- auto *ptr = (struct cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_float_value(mrb, ptr->height);
+ return mrb_float_value(mrb, (*ptr)->height);
}
static mrb_value
cg_cRectangle_set_height(mrb_state *mrb, mrb_value self)
{
mrb_float height;
- auto *ptr = (cg_rectangle *)DATA_PTR(self);
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
mrb_get_args(mrb, "f", &height);
- ptr->height = height;
+ (*ptr)->height = height;
- return mrb_float_value(mrb, ptr->height);
+ return mrb_float_value(mrb, (*ptr)->height);
}
static mrb_value
cg_cRectangle_align_vertically(mrb_state *mrb, mrb_value self)
{
- cg_rectangle *ptr, *that;
+ std::shared_ptr<VK::Rectangle> *ptr, *that;
mrb_get_args(mrb, "d", &that, &cg_rectangle_type);
- ptr = (cg_rectangle *)DATA_PTR(self);
+ ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_bool_value(
- align_vertically(ptr->x, ptr->width, that->x, that->width));
+ return mrb_bool_value((*ptr)->align_vertically(**that));
}
static mrb_value
cg_cRectangle_align_horizontally(mrb_state *mrb, mrb_value self)
{
- cg_rectangle *ptr, *that;
+ std::shared_ptr<VK::Rectangle> *ptr, *that;
mrb_get_args(mrb, "d", &that, &cg_rectangle_type);
- ptr = (cg_rectangle *)DATA_PTR(self);
+ ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_bool_value(
- align_horizontally(ptr->y, ptr->height, that->y, that->height));
+ return mrb_bool_value((*ptr)->align_horizontally(**that));
}
static mrb_value
cg_cRectangle_collide(mrb_state *mrb, mrb_value self)
{
- cg_rectangle *ptr, *that;
+ std::shared_ptr<VK::Rectangle> *ptr, *that;
mrb_get_args(mrb, "d", &that, &cg_rectangle_type);
- ptr = (cg_rectangle *)DATA_PTR(self);
+ ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
- return mrb_bool_value(
- align_vertically(ptr->x, ptr->width, that->x, that->width) &&
- align_horizontally(ptr->y, ptr->height, that->y, that->height));
+ return mrb_bool_value((*ptr)->collide(**that));
+}
+
+static mrb_value
+cg_cRectangle_draw(mrb_state *mrb, mrb_value self)
+{
+ mrb_value view_value;
+ VK::View2D *view_2d;
+ std::shared_ptr<glm::vec3> *color;
+ auto ptr = (std::shared_ptr<VK::Rectangle>*)DATA_PTR(self);
+
+ mrb_get_args(mrb, "od", &view_value, &color, &cg_vector_3d_type);
+
+ view_2d = cg_cView_to_view_2d(mrb, view_value);
+
+ VK::UBOModel2D model;
+ model.color = **color;
+ (*ptr)->ub_rectangle[cg_core.vk_swapchain->current_frame].copy_data(&model);
+ (*ptr)->update_vertex_buffer();
+ auto &rectangles = view_2d->rectangles_to_draw[
+ cg_core.vk_swapchain->current_frame];
+ rectangles.push_back(*ptr);
+
+ return self;
}
void
@@ -221,4 +227,6 @@ cg_rectangle_init(mrb_state *mrb)
cg_cRectangle_align_horizontally, MRB_ARGS_REQ(1));
mrb_define_method(
mrb, cg_cRectangle, "collide?", cg_cRectangle_collide, MRB_ARGS_REQ(1));
+ mrb_define_method(
+ mrb, cg_cRectangle, "draw", cg_cRectangle_draw, MRB_ARGS_REQ(2));
}
diff --git a/src/rectangle.hpp b/src/rectangle.hpp
index e89b6ba..8ed1748 100644
--- a/src/rectangle.hpp
+++ b/src/rectangle.hpp
@@ -18,11 +18,7 @@
#define CANDY_GEAR_RECTANGLE_H 1
#include "core.hpp"
-
-struct cg_rectangle
-{
- float x, y, width, height;
-};
+#include "vk/rectangle.hpp"
extern const struct mrb_data_type cg_rectangle_type;
diff --git a/src/sprite.cpp b/src/sprite.cpp
index 5f815f6..fa5e22f 100644
--- a/src/sprite.cpp
+++ b/src/sprite.cpp
@@ -18,6 +18,7 @@
#include "texture.hpp"
#include "vector_4d.hpp"
+#include "view_2d.hpp"
#include "vk/sprite.hpp"
void
@@ -52,6 +53,25 @@ cg_cSprite_initialize(mrb_state *mrb, mrb_value self)
return self;
}
+static mrb_value
+cg_cSprite_draw(mrb_state *mrb, mrb_value self)
+{
+ mrb_value view_value;
+ VK::View2D *view_2d;
+ std::shared_ptr<glm::vec4> *position;
+ auto ptr = (std::shared_ptr<VK::Sprite>*)DATA_PTR(self);
+
+ mrb_get_args(mrb, "od", &view_value, &position, &cg_vector_4d_type);
+
+ view_2d = cg_cView_to_view_2d(mrb, view_value);
+
+ auto &positions = view_2d->sprites_to_draw[
+ cg_core.vk_swapchain->current_frame][*ptr];
+ positions.push_back(*position->get());
+
+ return self;
+}
+
void
cg_sprite_init(mrb_state *mrb)
{
@@ -62,4 +82,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(2));
}
diff --git a/src/view_2d.cpp b/src/view_2d.cpp
index c84cbee..3f4325d 100644
--- a/src/view_2d.cpp
+++ b/src/view_2d.cpp
@@ -18,6 +18,7 @@
#include "sprite.hpp"
#include "vector_4d.hpp"
+#include "view_3d.hpp"
#include "vk/sprite.hpp"
#include "vk/view_2d.hpp"
@@ -51,20 +52,26 @@ cg_cView2D_initialize(mrb_state *mrb, mrb_value self)
return self;
}
-static mrb_value
-cg_cView2D_draw(mrb_state *mrb, mrb_value self)
+VK::View2D*
+cg_cView_to_view_2d(mrb_state *mrb, mrb_value view_value)
{
- std::shared_ptr<VK::Sprite> *sprite;
- std::shared_ptr<glm::vec4> *position;
- auto *ptr = (std::shared_ptr<VK::View2D>*)DATA_PTR(self);
+ VK::View2D* view_2d;
+ const mrb_data_type *type = DATA_TYPE(view_value);
- mrb_get_args(mrb, "dd", &sprite, &cg_sprite_type,
- &position, &cg_vector_4d_type);
- auto &positions = (*ptr)->sprites_to_draw[
- cg_core.vk_swapchain->current_frame][*sprite];
- positions.push_back(*position->get());
+ if(type == &cg_view_2d_type)
+ view_2d = static_cast<std::shared_ptr<VK::View2D>*>(
+ DATA_PTR(view_value))->get();
+ else if (type == &cg_view_3d_type)
+ view_2d = static_cast<VK::View2D*>(
+ static_cast<std::shared_ptr<VK::View3D>*>(
+ DATA_PTR(view_value))->get());
+ else
+ mrb_raisef(
+ mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s or %s)",
+ type->struct_name, cg_view_2d_type.struct_name,
+ cg_view_3d_type.struct_name);
- return self;
+ return view_2d;
}
void
@@ -77,5 +84,4 @@ cg_view_2d_init(mrb_state *mrb)
MRB_SET_INSTANCE_TT(cg_cView2D, MRB_TT_DATA);
mrb_define_method(
mrb, cg_cView2D, "initialize", cg_cView2D_initialize, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, cg_cView2D, "draw", cg_cView2D_draw, MRB_ARGS_REQ(2));
}
diff --git a/src/view_2d.hpp b/src/view_2d.hpp
index 0b33380..c2b1701 100644
--- a/src/view_2d.hpp
+++ b/src/view_2d.hpp
@@ -21,6 +21,12 @@
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*
+cg_cView_to_view_2d(mrb_state *mrb, mrb_value view_value);
+
void
cg_view_2d_init(mrb_state *mrb);
diff --git a/src/view_3d.cpp b/src/view_3d.cpp
index 4e8b254..1b733b8 100644
--- a/src/view_3d.cpp
+++ b/src/view_3d.cpp
@@ -77,22 +77,6 @@ cg_cView3D_set_camera_rotation(mrb_state *mrb, mrb_value self)
return self;
}
-static mrb_value
-cg_cView3D_draw(mrb_state *mrb, mrb_value self)
-{
- std::shared_ptr<VK::Sprite> *sprite;
- std::shared_ptr<glm::vec4> *position;
- auto *ptr = (std::shared_ptr<VK::View3D>*)DATA_PTR(self);
-
- mrb_get_args(mrb, "dd", &sprite, &cg_sprite_type,
- &position, &cg_vector_4d_type);
- auto &positions = (*ptr)->sprites_to_draw[
- cg_core.vk_swapchain->current_frame][*sprite];
- positions.push_back(*position->get());
-
- return self;
-}
-
void
cg_view_3d_init(mrb_state *mrb)
{
@@ -109,5 +93,4 @@ cg_view_3d_init(mrb_state *mrb)
mrb_define_method(
mrb, cg_cView3D, "camera_rotation=", cg_cView3D_set_camera_rotation,
MRB_ARGS_REQ(1));
- mrb_define_method(mrb, cg_cView3D, "draw", cg_cView3D_draw, MRB_ARGS_REQ(2));
}
diff --git a/src/vk/destination_buffer.cpp b/src/vk/destination_buffer.cpp
index 872f8a8..5c55fd2 100644
--- a/src/vk/destination_buffer.cpp
+++ b/src/vk/destination_buffer.cpp
@@ -34,39 +34,7 @@ DestinationBuffer::DestinationBuffer(
BaseBuffer::loader.execute(dynamic_cast<BaseBuffer*>(this));
- // Load command
- {
- CommandPool command_pool(this->queue_family, 1);
- Queue transfer_queue{this->queue_family->get_queue()};
-
- 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,
- &copy_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);
- }
+ this->copy_data();
}
DestinationBuffer::DestinationBuffer(
@@ -102,4 +70,40 @@ DestinationBuffer::~DestinationBuffer()
BaseBuffer::loader.revert(dynamic_cast<BaseBuffer*>(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,
+ &copy_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
index e856f4d..9b42af3 100644
--- a/src/vk/destination_buffer.hpp
+++ b/src/vk/destination_buffer.hpp
@@ -44,6 +44,9 @@ struct DestinationBuffer: public BaseBuffer
operator=(DestinationBuffer &&that);
~DestinationBuffer();
+
+ void
+ copy_data();
};
}
diff --git a/src/vk/device.cpp b/src/vk/device.cpp
index 74727f9..957ae6d 100644
--- a/src/vk/device.cpp
+++ b/src/vk/device.cpp
@@ -126,6 +126,7 @@ Device::Device(VkPhysicalDevice vk_physical_device, bool with_swapchain)
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;
@@ -165,6 +166,10 @@ Device::Device(VkPhysicalDevice vk_physical_device, bool with_swapchain)
this->device, DATA_DIR "/glsl/shader_2d.vert.spv");
this->frag2d_shader_module = create_shader_module(
this->device, DATA_DIR "/glsl/shader_2d.frag.spv");
+ this->vert2d_wired_shader_module = create_shader_module(
+ this->device, DATA_DIR "/glsl/shader_2d_wired.vert.spv");
+ this->frag2d_wired_shader_module = create_shader_module(
+ this->device, DATA_DIR "/glsl/shader_2d_wired.frag.spv");
}
this->queue_families = static_cast<QueueFamily*>(
@@ -202,6 +207,8 @@ Device::~Device()
vkDestroyShaderModule(this->device, this->frag3d_shader_module, nullptr);
vkDestroyShaderModule(this->device, this->vert2d_shader_module, nullptr);
vkDestroyShaderModule(this->device, this->frag2d_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);
diff --git a/src/vk/device.hpp b/src/vk/device.hpp
index cc5df82..9f5a776 100644
--- a/src/vk/device.hpp
+++ b/src/vk/device.hpp
@@ -41,6 +41,8 @@ public:
VkShaderModule frag3d_shader_module;
VkShaderModule vert2d_shader_module;
VkShaderModule frag2d_shader_module;
+ VkShaderModule vert2d_wired_shader_module;
+ VkShaderModule frag2d_wired_shader_module;
bool with_swapchain;
diff --git a/src/vk/graphics_pipeline_2d.cpp b/src/vk/graphics_pipeline_2d_solid.cpp
index 734a509..3906cc7 100644
--- a/src/vk/graphics_pipeline_2d.cpp
+++ b/src/vk/graphics_pipeline_2d_solid.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "graphics_pipeline_2d.hpp"
+#include "graphics_pipeline_2d_solid.hpp"
#include <array>
@@ -27,7 +27,7 @@ namespace
void
load_framebuffer(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolid*>(obj);
self->swapchain_framebuffers.resize(cg_core.vk_swapchain->images_count);
for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
@@ -39,7 +39,7 @@ load_framebuffer(void *obj)
VkFramebufferCreateInfo framebuffer_info{};
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebuffer_info.renderPass =
- cg_core.vk_graphics_pipeline_2d_layout->render_pass;
+ cg_core.vk_graphics_pipeline_2d_solid_layout->render_pass;
framebuffer_info.attachmentCount = attachments.size();
framebuffer_info.pAttachments = attachments.data();
framebuffer_info.width = cg_core.display_width;
@@ -57,7 +57,7 @@ load_framebuffer(void *obj)
void
unload_framebuffer(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolid*>(obj);
for(auto framebuffer: self->swapchain_framebuffers)
vkDestroyFramebuffer(
@@ -67,7 +67,7 @@ unload_framebuffer(void *obj)
void
load_pipeline(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolid*>(obj);
VkPipelineShaderStageCreateInfo vert_shader_stage_info{};
vert_shader_stage_info.sType =
@@ -227,9 +227,10 @@ load_pipeline(void *obj)
pipeline_info.pDepthStencilState = nullptr;
pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_state_info;
- pipeline_info.layout = cg_core.vk_graphics_pipeline_2d_layout->pipeline;
+ pipeline_info.layout =
+ cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline;
pipeline_info.renderPass =
- cg_core.vk_graphics_pipeline_2d_layout->render_pass;
+ cg_core.vk_graphics_pipeline_2d_solid_layout->render_pass;
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
pipeline_info.basePipelineIndex = -1;
@@ -244,7 +245,7 @@ load_pipeline(void *obj)
void
unload_pipeline(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolid*>(obj);
vkDestroyPipeline(
cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr);
@@ -260,18 +261,18 @@ const CommandChain loader{
namespace VK
{
-GraphicsPipeline2D::GraphicsPipeline2D()
+GraphicsPipeline2DSolid::GraphicsPipeline2DSolid()
{
loader.execute(this);
}
-GraphicsPipeline2D::~GraphicsPipeline2D()
+GraphicsPipeline2DSolid::~GraphicsPipeline2DSolid()
{
loader.revert(this);
}
void
-GraphicsPipeline2D::draw(
+GraphicsPipeline2DSolid::draw(
std::shared_ptr<View2D> view, const VkCommandBuffer draw_command_buffer,
const size_t current_frame, const size_t next_frame,
const uint32_t image_index)
@@ -307,7 +308,7 @@ GraphicsPipeline2D::draw(
vkCmdBindDescriptorSets(
draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- cg_core.vk_graphics_pipeline_2d_layout->pipeline, 0,
+ cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline, 0,
vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr);
vkCmdBindPipeline(
draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
diff --git a/src/vk/graphics_pipeline_2d.hpp b/src/vk/graphics_pipeline_2d_solid.hpp
index ffa373a..ec3c744 100644
--- a/src/vk/graphics_pipeline_2d.hpp
+++ b/src/vk/graphics_pipeline_2d_solid.hpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H
-#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H 1
+#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H
+#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H 1
#include <memory>
#include <unordered_map>
@@ -28,13 +28,13 @@
namespace VK
{
-struct GraphicsPipeline2D
+struct GraphicsPipeline2DSolid
{
std::vector<VkFramebuffer> swapchain_framebuffers;
VkPipeline graphic_pipeline;
- GraphicsPipeline2D();
- ~GraphicsPipeline2D();
+ GraphicsPipeline2DSolid();
+ ~GraphicsPipeline2DSolid();
void
draw(std::shared_ptr<View2D> view, const VkCommandBuffer draw_command_buffer,
@@ -44,4 +44,4 @@ struct GraphicsPipeline2D
}
-#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H */
+#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H */
diff --git a/src/vk/graphics_pipeline_2d_layout.cpp b/src/vk/graphics_pipeline_2d_solid_layout.cpp
index 6840f2c..6f0da0e 100644
--- a/src/vk/graphics_pipeline_2d_layout.cpp
+++ b/src/vk/graphics_pipeline_2d_solid_layout.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "graphics_pipeline_2d_layout.hpp"
+#include "graphics_pipeline_2d_solid_layout.hpp"
#include <array>
@@ -26,7 +26,7 @@ namespace
void
load_descriptor_set_view(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
std::array<VkDescriptorSetLayoutBinding, 1> layout_bindings{};
@@ -53,7 +53,7 @@ load_descriptor_set_view(void *obj)
void
unload_descriptor_set_view(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
vkDestroyDescriptorSetLayout(
cg_core.vk_device_with_swapchain->device, self->descriptor_set_view,
@@ -63,7 +63,7 @@ unload_descriptor_set_view(void *obj)
void
load_descriptor_set_sprite(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{};
@@ -97,7 +97,7 @@ load_descriptor_set_sprite(void *obj)
void
unload_descriptor_set_sprite(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
vkDestroyDescriptorSetLayout(
cg_core.vk_device_with_swapchain->device, self->descriptor_set_sprite,
@@ -107,7 +107,7 @@ unload_descriptor_set_sprite(void *obj)
void
load_pipeline(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
std::array<VkDescriptorSetLayout, 2> set_layouts{
self->descriptor_set_view, self->descriptor_set_sprite
@@ -129,7 +129,7 @@ load_pipeline(void *obj)
void
unload_pipeline(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
vkDestroyPipelineLayout(
cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr);
@@ -138,7 +138,7 @@ unload_pipeline(void *obj)
void
load_render_pass(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
std::array<VkAttachmentDescription, 1> attachments{};
// Color attachment.
@@ -150,7 +150,7 @@ load_render_pass(void *obj)
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;
+ attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference color_attachment_ref{};
color_attachment_ref.attachment = 0;
@@ -200,7 +200,7 @@ load_render_pass(void *obj)
static void
unload_render_pass(void *obj)
{
- auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
+ auto self = static_cast<VK::GraphicsPipeline2DSolidLayout*>(obj);
vkDestroyRenderPass(
cg_core.vk_device_with_swapchain->device, self->render_pass, nullptr);
@@ -218,12 +218,12 @@ const CommandChain loader{
namespace VK
{
-GraphicsPipeline2DLayout::GraphicsPipeline2DLayout()
+GraphicsPipeline2DSolidLayout::GraphicsPipeline2DSolidLayout()
{
loader.execute(this);
}
-GraphicsPipeline2DLayout::~GraphicsPipeline2DLayout()
+GraphicsPipeline2DSolidLayout::~GraphicsPipeline2DSolidLayout()
{
loader.revert(this);
}
diff --git a/src/vk/graphics_pipeline_2d_layout.hpp b/src/vk/graphics_pipeline_2d_solid_layout.hpp
index 1e0a794..121ddaa 100644
--- a/src/vk/graphics_pipeline_2d_layout.hpp
+++ b/src/vk/graphics_pipeline_2d_solid_layout.hpp
@@ -32,15 +32,15 @@ struct UBOSpritePositions
glm::vec4 positions[128];
};
-struct GraphicsPipeline2DLayout
+struct GraphicsPipeline2DSolidLayout
{
VkDescriptorSetLayout descriptor_set_view;
VkDescriptorSetLayout descriptor_set_sprite;
VkPipelineLayout pipeline;
VkRenderPass render_pass;
- GraphicsPipeline2DLayout();
- ~GraphicsPipeline2DLayout();
+ GraphicsPipeline2DSolidLayout();
+ ~GraphicsPipeline2DSolidLayout();
};
}
diff --git a/src/vk/graphics_pipeline_2d_wired.cpp b/src/vk/graphics_pipeline_2d_wired.cpp
new file mode 100644
index 0000000..2b416c2
--- /dev/null
+++ b/src/vk/graphics_pipeline_2d_wired.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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 "graphics_pipeline_2d_wired.hpp"
+
+#include <array>
+
+#include "../core.hpp"
+#include "rectangle.hpp"
+#include "sprite.hpp"
+
+namespace
+{
+
+void
+load_framebuffer(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWired*>(obj);
+
+ self->swapchain_framebuffers.resize(
+ cg_core.vk_swapchain->images_count);
+ for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
+ {
+ std::array<VkImageView, 1> 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_graphics_pipeline_2d_wired_layout->render_pass;
+ 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->swapchain_framebuffers[i]) != VK_SUCCESS)
+ throw CommandError{"Failed to create Vulkan Framebuffer."};
+ }
+}
+
+void
+unload_framebuffer(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWired*>(obj);
+
+ for(auto framebuffer: self->swapchain_framebuffers)
+ vkDestroyFramebuffer(
+ cg_core.vk_device_with_swapchain->device, framebuffer, nullptr);
+}
+
+void
+load_pipeline(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWired*>(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
+ };
+
+ 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<VkVertexInputAttributeDescription, 1> vertex_attribute{};
+ 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<uint32_t>(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_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_graphics_pipeline_2d_wired_layout->render_pass;
+ 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<VK::GraphicsPipeline2DWired*>(obj);
+
+ vkDestroyPipeline(
+ cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr);
+}
+
+const CommandChain loader{
+ {&load_framebuffer, &unload_framebuffer},
+ {&load_pipeline, &unload_pipeline}
+};
+
+}
+
+namespace VK
+{
+
+GraphicsPipeline2DWired::GraphicsPipeline2DWired()
+{
+ loader.execute(this);
+}
+
+GraphicsPipeline2DWired::~GraphicsPipeline2DWired()
+{
+ loader.revert(this);
+}
+
+void
+GraphicsPipeline2DWired::draw(
+ std::shared_ptr<View2D> 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<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 rectangles
+ for(auto& rectangle: view->rectangles_to_draw[current_frame])
+ {
+ std::array<VkDescriptorSet, 2> vk_descriptor_sets{
+ view->descriptor_sets_2d[image_index],
+ rectangle->descriptor_sets[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);
+ vkCmdBindVertexBuffers(
+ draw_command_buffer, 0, 1,
+ &rectangle->vertex_buffers[image_index].buffer, offsets);
+ vkCmdDraw(
+ draw_command_buffer, Rectangle::vertex_count, 1, 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
new file mode 100644
index 0000000..e6c40de
--- /dev/null
+++ b/src/vk/graphics_pipeline_2d_wired.hpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "core.hpp"
+#include "view_2d.hpp"
+
+namespace VK
+{
+
+struct GraphicsPipeline2DWired
+{
+ std::vector<VkFramebuffer> swapchain_framebuffers;
+ VkPipeline graphic_pipeline;
+
+ GraphicsPipeline2DWired();
+ ~GraphicsPipeline2DWired();
+
+ void
+ draw(std::shared_ptr<View2D> 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
new file mode 100644
index 0000000..c523bc7
--- /dev/null
+++ b/src/vk/graphics_pipeline_2d_wired_layout.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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 "graphics_pipeline_2d_wired_layout.hpp"
+
+#include <array>
+
+#include "../core.hpp"
+#include "graphics_pipeline_2d_solid_layout.hpp"
+
+namespace
+{
+
+void
+load_descriptor_set_view(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ std::array<VkDescriptorSetLayoutBinding, 1> 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<uint32_t>(layout_bindings.size());
+ layout_info.pBindings = layout_bindings.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 projection."};
+}
+
+void
+unload_descriptor_set_view(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ vkDestroyDescriptorSetLayout(
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_view,
+ nullptr);
+}
+
+void
+load_descriptor_set_instance(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ std::array<VkDescriptorSetLayoutBinding, 1> 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_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<uint32_t>(layout_bindings.size());
+ layout_info.pBindings = layout_bindings.data();
+
+ if(vkCreateDescriptorSetLayout(
+ cg_core.vk_device_with_swapchain->device, &layout_info, nullptr,
+ &self->descriptor_set_instance) != VK_SUCCESS)
+ throw CommandError{
+ "Failed to create Vulkan descriptor set layout for rectangles."};
+}
+
+void
+unload_descriptor_set_instance(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ vkDestroyDescriptorSetLayout(
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_instance,
+ nullptr);
+}
+
+void
+load_pipeline(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ std::array<VkDescriptorSetLayout, 2> set_layouts{
+ self->descriptor_set_view, self->descriptor_set_instance
+ };
+
+ 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<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ vkDestroyPipelineLayout(
+ cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr);
+}
+
+void
+load_render_pass(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ std::array<VkAttachmentDescription, 1> 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->render_pass) != VK_SUCCESS)
+ throw CommandError{"Failed to create Vulkan Render Pass 2D."};
+}
+
+static void
+unload_render_pass(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline2DWiredLayout*>(obj);
+
+ vkDestroyRenderPass(
+ cg_core.vk_device_with_swapchain->device, self->render_pass, nullptr);
+}
+
+const CommandChain loader{
+ {&load_descriptor_set_view, &unload_descriptor_set_view},
+ {&load_descriptor_set_instance, &unload_descriptor_set_instance},
+ {&load_pipeline, &unload_pipeline},
+ {&load_render_pass, &unload_render_pass}
+};
+
+}
+
+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
new file mode 100644
index 0000000..3d0268e
--- /dev/null
+++ b/src/vk/graphics_pipeline_2d_wired_layout.hpp
@@ -0,0 +1,43 @@
+/*
+ * 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_LAYOUT_H
+#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H 1
+
+#include "core.hpp"
+
+namespace VK
+{
+
+struct UBOModel2D
+{
+ glm::vec3 color;
+};
+
+struct GraphicsPipeline2DWiredLayout
+{
+ VkDescriptorSetLayout descriptor_set_view;
+ VkDescriptorSetLayout descriptor_set_instance;
+ VkPipelineLayout pipeline;
+ VkRenderPass render_pass;
+
+ GraphicsPipeline2DWiredLayout();
+ ~GraphicsPipeline2DWiredLayout();
+};
+
+}
+
+#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H */
diff --git a/src/vk/rectangle.cpp b/src/vk/rectangle.cpp
new file mode 100644
index 0000000..b0925f1
--- /dev/null
+++ b/src/vk/rectangle.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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"
+
+#include <array>
+
+#include "../core.hpp"
+#include "graphics_pipeline_2d_wired_layout.hpp"
+
+namespace
+{
+
+void
+load_mesh(void *obj)
+{
+ auto self = static_cast<VK::Rectangle*>(obj);
+
+ self->queue_family =
+ cg_core.vk_device_with_swapchain->get_queue_family_with_graphics();
+
+ glm::vec2 rect[4]{
+ glm::vec2{self->x, self->y},
+ glm::vec2{self->x, self->y + self->height},
+ glm::vec2{self->x + self->width, self->y},
+ glm::vec2{self->x + self->width, self->y + self->height}
+ };
+
+ void *vertexes_data{&rect};
+ static const size_t vertexes_size =
+ sizeof(glm::vec2) * VK::Rectangle::vertex_count;
+ self->source_buffers.reserve(cg_core.vk_swapchain->images_count);
+ self->vertex_buffers.reserve(cg_core.vk_swapchain->images_count);
+ for(int i{0}; i < cg_core.vk_swapchain->images_count; i++)
+ {
+ self->source_buffers.emplace_back(
+ self->queue_family->device, vertexes_data, vertexes_size);
+ self->vertex_buffers.emplace_back(
+ self->queue_family, &self->source_buffers[i],
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ }
+}
+
+void
+unload_mesh(void *obj)
+{
+ auto self = static_cast<VK::Rectangle*>(obj);
+
+ self->vertex_buffers.clear();
+ self->source_buffers.clear();
+}
+
+void
+load_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::Rectangle*>(obj);
+
+ self->ub_rectangle.reserve(cg_core.vk_swapchain->images_count);
+ for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
+ self->ub_rectangle.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOModel2D));
+}
+
+void
+unload_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::Rectangle*>(obj);
+
+ self->ub_rectangle.clear();
+}
+
+void
+load_descriptor_set_pool(void *obj)
+{
+ auto self = static_cast<VK::Rectangle*>(obj);
+
+ std::array<VkDescriptorPoolSize, 1> descriptor_pool_sizes{};
+ descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptor_pool_sizes[0].descriptorCount = self->ub_rectangle.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_rectangle.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<VK::Rectangle*>(obj);
+
+ vkDestroyDescriptorPool(
+ self->queue_family->device->device, self->descriptor_pool, nullptr);
+}
+
+void
+load_descriptor_sets(void *obj)
+{
+ auto self = static_cast<VK::Rectangle*>(obj);
+
+ std::vector<VkDescriptorSetLayout> layouts(
+ cg_core.vk_swapchain->images_count,
+ cg_core.vk_graphics_pipeline_2d_wired_layout->descriptor_set_instance);
+
+ 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<VK::Rectangle*>(obj);
+
+ for(auto i{0}; i < self->ub_rectangle.size(); i++)
+ {
+ VkDescriptorBufferInfo buffer_info{};
+ buffer_info.buffer = self->ub_rectangle[i].buffer;
+ buffer_info.offset = 0;
+ buffer_info.range = sizeof(VK::UBOModel2D);
+
+ std::array<VkWriteDescriptorSet, 1> 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_mesh, &unload_mesh},
+ {&load_uniform_buffer, &unload_uniform_buffer},
+ {&load_descriptor_set_pool, &unload_descriptor_set_pool},
+ {&load_descriptor_sets, nullptr},
+ {&load_data_to_descriptor_sets, nullptr},
+};
+
+constexpr bool
+_align_vertically(const float a_x, const float a_width,
+ const float b_x, const float b_width)
+{
+ return a_x <= b_x + b_width && a_x + a_width >= b_x;
+}
+
+constexpr bool
+_align_horizontally(const float a_y, const float a_height,
+ const float b_y, const float b_height)
+{
+ return a_y <= b_y + b_height && a_y + a_height >= b_y;
+}
+
+}
+
+namespace VK
+{
+
+Rectangle::Rectangle(float x, float y, float width, float height):
+ x{x},
+ y{y},
+ width{width},
+ height{height}
+{
+ loader.execute(this);
+}
+
+Rectangle::~Rectangle()
+{
+ loader.revert(this);
+}
+
+bool
+Rectangle::align_vertically(const Rectangle &that) const
+{
+ return _align_vertically(this->x, this->width, that.x, that.width);
+}
+
+bool
+Rectangle::align_horizontally(const Rectangle &that) const
+{
+ return _align_horizontally(this->y, this->height, that.y, that.height);
+}
+
+bool
+Rectangle::collide(const Rectangle &that) const
+{
+ return
+ _align_vertically(this->x, this->width, that.x, that.width) &&
+ _align_horizontally(this->y, this->height, that.y, that.height);
+}
+
+void
+Rectangle::update_vertex_buffer()
+{
+ glm::vec2 rect[4]{
+ glm::vec2{this->x, this->y},
+ glm::vec2{this->x, this->y + this->height},
+ glm::vec2{this->x + this->width, this->y},
+ glm::vec2{this->x + this->width, this->y + this->height}
+ };
+
+ void *vertexes_data{&rect};
+ this->source_buffers[cg_core.vk_swapchain->current_frame].copy_data(
+ vertexes_data);
+ this->vertex_buffers[cg_core.vk_swapchain->current_frame].copy_data();
+}
+
+}
diff --git a/src/vk/rectangle.hpp b/src/vk/rectangle.hpp
new file mode 100644
index 0000000..fc21135
--- /dev/null
+++ b/src/vk/rectangle.hpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <vector>
+
+#include "core.hpp"
+#include "destination_buffer.hpp"
+#include "queue_family.hpp"
+#include "uniform_buffer.hpp"
+
+namespace VK
+{
+
+struct Rectangle
+{
+ static const uint32_t vertex_count{4};
+
+ float x{0};
+ float y{0};
+ float width{1};
+ float height{1};
+
+ QueueFamily *queue_family;
+
+ std::vector<SourceBuffer> source_buffers;
+ std::vector<DestinationBuffer> vertex_buffers;
+
+ std::vector<UniformBuffer> ub_rectangle;
+
+ VkDescriptorPool descriptor_pool;
+ std::vector<VkDescriptorSet> descriptor_sets;
+
+ Rectangle() = default;
+ Rectangle(float x, float y, float width, float height);
+ ~Rectangle();
+
+ bool
+ align_vertically(const Rectangle &that) const;
+ bool
+ align_horizontally(const Rectangle &that) const;
+ bool
+ collide(const Rectangle &that) const;
+
+ void
+ update_vertex_buffer();
+};
+
+}
+
+#endif /* CANDY_GEAR_VK_RECTANGLE_H */
diff --git a/src/vk/renderer.cpp b/src/vk/renderer.cpp
index 8d82b00..a7e5f35 100644
--- a/src/vk/renderer.cpp
+++ b/src/vk/renderer.cpp
@@ -231,15 +231,16 @@ Renderer::draw()
vkCmdEndRenderPass(draw_command_buffer);
}
- // 2D drawing
+ // 2D solid 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;
+ cg_core.vk_graphics_pipeline_2d_solid_layout->render_pass;
render_pass_begin.framebuffer =
- cg_core.vk_graphics_pipeline_2d->swapchain_framebuffers[image_index];
+ cg_core.vk_graphics_pipeline_2d_solid->swapchain_framebuffers[
+ image_index];
render_pass_begin.renderArea.offset = {0, 0};
render_pass_begin.renderArea.extent = {
static_cast<uint32_t>(cg_core.display_width),
@@ -251,12 +252,45 @@ Renderer::draw()
draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
for(auto &view: this->views_2d)
- cg_core.vk_graphics_pipeline_2d->draw(
+ 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->draw(
+ cg_core.vk_graphics_pipeline_2d_solid->draw(
+ view, draw_command_buffer, cg_core.vk_swapchain->current_frame,
+ next_frame, image_index);
+
+ vkCmdEndRenderPass(draw_command_buffer);
+ }
+
+ // 2D wired 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_wired_layout->render_pass;
+ render_pass_begin.framebuffer =
+ cg_core.vk_graphics_pipeline_2d_wired->swapchain_framebuffers[
+ image_index];
+ render_pass_begin.renderArea.offset = {0, 0};
+ render_pass_begin.renderArea.extent = {
+ static_cast<uint32_t>(cg_core.display_width),
+ static_cast<uint32_t>(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);
+
+ 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);
@@ -313,11 +347,8 @@ Renderer::draw()
// Prepare for the next frame.
{
- this->models_to_draw[next_frame].clear();
- for(auto &view: this->views_2d) view->sprites_to_draw[next_frame].clear();
- for(auto &view: this->views_3d) view->sprites_to_draw[next_frame].clear();
-
- cg_core.vk_swapchain->current_frame = next_frame;
+ this->models_to_draw[next_frame].clear();
+ cg_core.vk_swapchain->current_frame = next_frame;
}
}
else
diff --git a/src/vk/source_buffer.cpp b/src/vk/source_buffer.cpp
index 7e6c570..f8f1aee 100644
--- a/src/vk/source_buffer.cpp
+++ b/src/vk/source_buffer.cpp
@@ -21,8 +21,7 @@
namespace VK
{
-SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size):
- data{data}
+SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size)
{
this->device = device;
this->device_size = data_size;
@@ -40,7 +39,7 @@ SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size):
error += command_error.what();
throw std::runtime_error{error};
}
- this->copy_data();
+ this->copy_data(data);
}
SourceBuffer::SourceBuffer(SourceBuffer &&that)
@@ -50,11 +49,9 @@ SourceBuffer::SourceBuffer(SourceBuffer &&that)
this->device_size = that.device_size;
this->buffer_usage = that.buffer_usage;
this->memory_properties = that.memory_properties;
- this->data = that.data;
that.buffer = VK_NULL_HANDLE;
that.device_memory = VK_NULL_HANDLE;
- that.data = nullptr;
}
SourceBuffer&
@@ -65,11 +62,9 @@ SourceBuffer::operator=(SourceBuffer &&that)
this->device_size = that.device_size;
this->buffer_usage = that.buffer_usage;
this->memory_properties = that.memory_properties;
- this->data = that.data;
that.buffer = VK_NULL_HANDLE;
that.device_memory = VK_NULL_HANDLE;
- that.data = nullptr;
return *this;
}
@@ -80,12 +75,12 @@ SourceBuffer::~SourceBuffer()
}
void
-SourceBuffer::copy_data()
+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, this->data, static_cast<size_t>(this->device_size));
+ memcpy(dst_data, src_data, static_cast<size_t>(this->device_size));
vkUnmapMemory(this->device->device, this->device_memory);
}
diff --git a/src/vk/source_buffer.hpp b/src/vk/source_buffer.hpp
index 713d708..440e561 100644
--- a/src/vk/source_buffer.hpp
+++ b/src/vk/source_buffer.hpp
@@ -28,8 +28,6 @@ struct SourceBuffer: public BaseBuffer
SourceBuffer&
operator=(const SourceBuffer &t) = delete;
- void *data;
-
SourceBuffer(Device *device, void *data, size_t data_size);
SourceBuffer(SourceBuffer &&that);
@@ -39,7 +37,7 @@ struct SourceBuffer: public BaseBuffer
~SourceBuffer();
void
- copy_data();
+ copy_data(void *src_data);
};
}
diff --git a/src/vk/sprite.cpp b/src/vk/sprite.cpp
index 9a718d7..a7b802a 100644
--- a/src/vk/sprite.cpp
+++ b/src/vk/sprite.cpp
@@ -137,7 +137,7 @@ load_descriptor_sets(void *obj)
std::vector<VkDescriptorSetLayout> layouts(
cg_core.vk_swapchain->images_count,
- cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_sprite);
+ cg_core.vk_graphics_pipeline_2d_solid_layout->descriptor_set_sprite);
VkDescriptorSetAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
diff --git a/src/vk/view_2d.cpp b/src/vk/view_2d.cpp
index 623aa63..011fb1a 100644
--- a/src/vk/view_2d.cpp
+++ b/src/vk/view_2d.cpp
@@ -56,7 +56,7 @@ load_descriptor_sets_2d(void *obj)
std::vector<VkDescriptorSetLayout> layouts(
cg_core.vk_swapchain->images_count,
- cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_view);
+ cg_core.vk_graphics_pipeline_2d_solid_layout->descriptor_set_view);
VkDescriptorSetAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@@ -124,6 +124,7 @@ const CommandChain View2D::descriptor_sets_loader{
View2D::View2D(glm::vec4 region):
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);
diff --git a/src/vk/view_2d.hpp b/src/vk/view_2d.hpp
index f6741cc..ec7225f 100644
--- a/src/vk/view_2d.hpp
+++ b/src/vk/view_2d.hpp
@@ -23,6 +23,7 @@
#include "core.hpp"
#include "sprite.hpp"
+#include "rectangle.hpp"
namespace VK
{
@@ -37,6 +38,7 @@ struct View2D
VkDescriptorPool descriptor_pool;
std::vector<VkDescriptorSet> descriptor_sets_2d;
+ std::vector<std::vector<std::shared_ptr<Rectangle>>> rectangles_to_draw;
std::vector<
std::unordered_map<std::shared_ptr<Sprite>, std::vector<glm::vec4>>>
sprites_to_draw;
diff --git a/test/src/main.rb b/test/src/main.rb
index be0ae0b..b7bbe85 100644
--- a/test/src/main.rb
+++ b/test/src/main.rb
@@ -25,9 +25,12 @@ end
def init()
texture = CandyGear::Texture.from_image("textures/color_texture.png");
mesh = CandyGear::Mesh.new("meshes/cube.cgmesh");
+
+ $color = CandyGear::Vector3D.new(0.8, 0.2, 0.2);
$model = CandyGear::Model.new(mesh, texture);
$sprite = CandyGear::Sprite.new(
texture, CandyGear::Vector4D.new(0, 0, 1.0, 1.0));
+ $rectangle = CandyGear::Rectangle.new(102.0, 1.0, 101.0, 101.0)
$sprite_position = CandyGear::Vector4D.new(1.0, 1.0, 101.0, 101.0);
$instances = [
@@ -83,8 +86,9 @@ end
def quit() = CandyGear.quit();
def tick()
- $view1.draw($sprite, $sprite_position);
+ $sprite.draw($view1, $sprite_position);
$instances_rotation.rotate(0.0, BOX_ROTATION_SPEED);
+ $rectangle.draw($view1, $color);
$instances.each do |i|
$model.draw(i, $instances_rotation);
end