From 4d1f8bb3c7439c1c35b6958f32a3bc01d03c93d3 Mon Sep 17 00:00:00 2001 From: "matthias@arch" Date: Mon, 14 Nov 2022 22:55:14 +0100 Subject: [PATCH] Moved to strategy design patter for 2D drawables --- src/drawables/draw_strategy_base.hpp | 14 ++++ src/drawables/print_draw_strategy.hpp | 34 +++++++++ src/drawables/rectangle.cpp | 23 ++++++ src/drawables/rectangle.hpp | 27 +++++++ src/drawables/text.cpp | 25 +++++++ src/drawables/text.hpp | 25 +++++++ src/shape.cpp | 72 ------------------- src/shape.hpp | 67 ----------------- src/vulkan_draw_strategies/ds_vk_base.cpp | 34 +++++++++ src/vulkan_draw_strategies/ds_vk_base.hpp | 62 ++++++++++++++++ .../ds_vk_rectangle.cpp | 45 ++++++++++++ .../ds_vk_rectangle.hpp | 27 +++++++ src/vulkan_draw_strategies/ds_vk_text.cpp | 19 +++++ src/vulkan_draw_strategies/ds_vk_text.hpp | 24 +++++++ 14 files changed, 359 insertions(+), 139 deletions(-) create mode 100644 src/drawables/draw_strategy_base.hpp create mode 100644 src/drawables/print_draw_strategy.hpp create mode 100644 src/drawables/rectangle.cpp create mode 100644 src/drawables/rectangle.hpp create mode 100644 src/drawables/text.cpp create mode 100644 src/drawables/text.hpp delete mode 100644 src/shape.cpp delete mode 100644 src/shape.hpp create mode 100644 src/vulkan_draw_strategies/ds_vk_base.cpp create mode 100644 src/vulkan_draw_strategies/ds_vk_base.hpp create mode 100644 src/vulkan_draw_strategies/ds_vk_rectangle.cpp create mode 100644 src/vulkan_draw_strategies/ds_vk_rectangle.hpp create mode 100644 src/vulkan_draw_strategies/ds_vk_text.cpp create mode 100644 src/vulkan_draw_strategies/ds_vk_text.hpp diff --git a/src/drawables/draw_strategy_base.hpp b/src/drawables/draw_strategy_base.hpp new file mode 100644 index 0000000..315686d --- /dev/null +++ b/src/drawables/draw_strategy_base.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace gz { + /** + * @brief Base class for draw strategies for type T + */ + template + class DrawStrategy { + public: + virtual void draw() = 0; + virtual void update(const T&) = 0; + virtual ~DrawStrategy() {}; + }; +} diff --git a/src/drawables/print_draw_strategy.hpp b/src/drawables/print_draw_strategy.hpp new file mode 100644 index 0000000..3631257 --- /dev/null +++ b/src/drawables/print_draw_strategy.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "draw_strategy_base.hpp" + +#include +#include + +namespace gz { + /** + * @brief Print the object to stdout when draw() is called + * @details + * When update() is called, to object is converted to string and stored in tAsString. + * When draw() is called, tAsString is passed to `std::cout`. + */ + template + class PrintDrawStrategy : public DrawStrategy { + public: + void draw() override; + void update(const T& t) override; + private: + std::string tAsString; + }; + + + template + void PrintDrawStrategy::draw() { + std::cout << tAsString << '\n'; + } + + template + void PrintDrawStrategy::update(const T& t) { + tAsString = gz::toString(t); + } +} // namespace gz diff --git a/src/drawables/rectangle.cpp b/src/drawables/rectangle.cpp new file mode 100644 index 0000000..a051129 --- /dev/null +++ b/src/drawables/rectangle.cpp @@ -0,0 +1,23 @@ +#include "rectangle.hpp" + +#include "texture_manager.hpp" +#include + +namespace gz { + Rectangle::Rectangle(float left, float top, float width, float height, std::unique_ptr>&& drawStrategy) + : position(left, top), size(width, height), drawStrategy(std::move(drawStrategy)) + { + update(); + } + + std::string Rectangle::toString() const { + return ""; + } + + + void Rectangle::update() { + drawStrategy->update(*this); + } + + +} // namespace gz::vlk diff --git a/src/drawables/rectangle.hpp b/src/drawables/rectangle.hpp new file mode 100644 index 0000000..722b9ff --- /dev/null +++ b/src/drawables/rectangle.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "vertex.hpp" +#include "draw_strategy_base.hpp" +#include + +namespace gz { + class Rectangle { + public: + Rectangle(float top, float left, float width, float height, std::unique_ptr>&& drawStrategy); + inline const glm::vec2& getPosition() const { return position; } + inline void setPosition(const glm::vec2& v) { position = v; } + inline void setPosition(glm::vec2&& v) { position = std::move(v); } + inline const glm::vec2& getSize() const { return size; } + inline void setSize(const glm::vec2& v) { size = v; } + inline void setSize(glm::vec2&& v) { size = std::move(v); } + void draw() { drawStrategy->draw(); }; + std::string toString() const; + private: + void update(); + glm::vec2 position; + glm::vec2 size; + std::unique_ptr> drawStrategy; + }; + + +} // namespace gz diff --git a/src/drawables/text.cpp b/src/drawables/text.cpp new file mode 100644 index 0000000..c05df5d --- /dev/null +++ b/src/drawables/text.cpp @@ -0,0 +1,25 @@ +#include "text.hpp" + +#include "font.hpp" + +namespace gz::vlk { + Text::Text(Font font, std::string&& text) + : text(std::move(text)), font(font) + { + + } + std::string Text::toString() const { + return ""; + } + + void Text::setTextureCoordinates(FontManager& fontManager) { + for (char c : text) { + fontManager.getTexCoords(font, c, vertices[0].texCoord); + fontManager.getTexCoords(font, c, vertices[1].texCoord); + fontManager.getTexCoords(font, c, vertices[2].texCoord); + fontManager.getTexCoords(font, c, vertices[3].texCoord); + } + // must be after getTexCoords, since that might load the texture + } + +} // namespace gz::vlk diff --git a/src/drawables/text.hpp b/src/drawables/text.hpp new file mode 100644 index 0000000..6ce29f7 --- /dev/null +++ b/src/drawables/text.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "buffer_manager.hpp" +#include +#include "font.hpp" + +namespace gz::vlk { + class Text { + public: + Text(Font font, std::string&& text); + private: + std::string text; + void setTextureCoordinates(FontManager& fontManager); + + uint32_t textureAtlasIndex; + Font font; + std::vector vertices; + std::vector indices; + + BufferInfo vertexBufferInfo; + BufferInfo indexBufferInfo; + std::string toString() const; + }; + +} // namespace gz::vlk diff --git a/src/shape.cpp b/src/shape.cpp deleted file mode 100644 index 420c788..0000000 --- a/src/shape.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "shape.hpp" - -#include "buffer_manager.hpp" -#include "texture_manager.hpp" - -namespace gz::vlk { - Rectangle::Rectangle(float top, float left, uint32_t width, uint32_t height, glm::vec3 color, std::string&& texture) - : top(top), left(left), width(width), height(height), color(color) - { - this->texture = std::move(texture); - generateVertices(); - - } - - - void Rectangle::generateVertices() { - vertices.clear(); - vertices.emplace_back(Vertex2D{glm::vec2(top, left), color, glm::vec2(0, 0)}); - vertices.emplace_back(Vertex2D{glm::vec2(top, left + width), color, glm::vec2(0, 1)}); - vertices.emplace_back(Vertex2D{glm::vec2(top + height, left + width), color, glm::vec2(1, 1)}); - vertices.emplace_back(Vertex2D{glm::vec2(top + height, left), color, glm::vec2(1, 0)}); - indices = { 0, 1, 2, 2, 3, 0 }; - /* indices = { 2, 1, 0, 2, 3, 0 }; */ - } - - void Shape::setIndexOffset(uint32_t offset) { - for (size_t i = 0; i < indices.size(); i++) { - indices[i] += offset; - } - - } - - void Shape::normalizeVertices(float width, float height) { - for (size_t i = 0; i < vertices.size(); i++) { - vertices[i].pos.x /= width; - vertices[i].pos.y /= height; - } - } - - - void Shape::initalizeBufferInfos(BufferManager& bufferManager) { - assert(vertexBufferInfo.index == BUFFER_NOT_INITIALIZED); - std::tie(vertexBufferInfo, indexBufferInfo) = bufferManager.addVertices(vertices, indices); - } - - - void Rectangle::setTextureCoordinates(glm::vec2 topLeft, glm::vec2 bottomRight) { - vertices[0].texCoord = topLeft; - vertices[1].texCoord.x = bottomRight.x; - vertices[1].texCoord.y = topLeft.y; - vertices[2].texCoord = bottomRight; - vertices[3].texCoord.x = topLeft.x; - vertices[3].texCoord.y = bottomRight.y; - } - - void Rectangle::setTextureCoordinates(TextureManager& textureManager) { - if (texture != "atlas") { - textureManager.getTexCoords(texture, vertices[0].texCoord); - textureManager.getTexCoords(texture, vertices[1].texCoord); - textureManager.getTexCoords(texture, vertices[2].texCoord); - textureManager.getTexCoords(texture, vertices[3].texCoord); - textureAtlasIndex = textureManager.getTextureAtlasIndex(texture); - } - else { - textureAtlasIndex = 0; - - } - // must be after getTexCoords, since that might load the texture - } - - -} // namespace gz::vlk diff --git a/src/shape.hpp b/src/shape.hpp deleted file mode 100644 index 2a77221..0000000 --- a/src/shape.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "buffer_manager.hpp" -#include "vertex.hpp" -#include - -namespace gz::vlk { - // defined in texture_manager.hpp - class TextureManager; - /** - * @brief Base class for shapes - * @details - * In this implementaiton, a shape is a 2D object made of several vertices. - * Each shape has its own vertex and index buffers, which are managed by a BufferManager. - * Their texture is managed by a TextureManager. - * @todo free resources and rule of 5 - */ - class Shape { - public: - const std::vector& getVertices() const { return vertices; } - const std::vector& getIndices() const { return indices; } - const std::string& getTexture() const { return texture; } - uint32_t getTexureAtlasIndex() const { return textureAtlasIndex; } - const BufferInfo& getVertexBufferInfo() const { return vertexBufferInfo; } - const BufferInfo& getIndexBufferInfo() const { return indexBufferInfo; } - - /** - * @brief Add an offset to all indices (useful when putting multiple shapes in the same vertex buffer) - */ - void setIndexOffset(uint32_t offset); - /** - * @brief Normalize the vertices, so that (1, 1) is (width, height) - */ - void normalizeVertices(float width, float height); - virtual void setTextureCoordinates(glm::vec2 topLeft, glm::vec2 bottomRight) {}; - virtual void setTextureCoordinates(TextureManager& textureManager) {}; - bool buffersInitalized() const { return vertexBufferInfo.index != BUFFER_NOT_INITIALIZED; } - void initalizeBufferInfos(BufferManager& bufferManager); - virtual ~Shape() {}; - protected: - std::string texture = "texture.png"; - uint32_t textureAtlasIndex; - std::vector vertices; - std::vector indices; - - BufferInfo vertexBufferInfo; - BufferInfo indexBufferInfo; - }; - - class Rectangle : public Shape { - public: - Rectangle(float top, float left, uint32_t width, uint32_t height, glm::vec3 color, std::string&& texture); - void setTextureCoordinates(glm::vec2 topLeft, glm::vec2 bottomRight) override; - /** - * @brief Get the correct texture coordinates from a TextureManager - * @details - * If the texture is "atlas", the texture coordinates will remain at (0,0), (0,1), (1, 1), (1, 0) and - * thus show the entire atlas. - */ - void setTextureCoordinates(TextureManager& textureManager) override; - private: - float top, left; - uint32_t width, height; - glm::vec3 color; - void generateVertices(); - }; -} // namespace gz::vlk diff --git a/src/vulkan_draw_strategies/ds_vk_base.cpp b/src/vulkan_draw_strategies/ds_vk_base.cpp new file mode 100644 index 0000000..598f7c6 --- /dev/null +++ b/src/vulkan_draw_strategies/ds_vk_base.cpp @@ -0,0 +1,34 @@ +#include "ds_vk_base.hpp" + +#include "renderer2D.hpp" + +namespace gz::vlk { + void VulkanDS::setIndexOffset(uint32_t offset) { + for (size_t i = 0; i < indices.size(); i++) { + indices[i] += offset; + } + } + + + void VulkanDS::normalizeVertices(float width, float height) { + for (size_t i = 0; i < vertices.size(); i++) { + vertices[i].pos.x /= width; + vertices[i].pos.y /= height; + } + } + + + void VulkanDS::updateBufferInfos() { + assert(vertexBufferInfo.index == BUFFER_NOT_INITIALIZED); + std::tie(vertexBufferInfo, indexBufferInfo) = bufferManager.get().addVertices(vertices, indices); + } + + + VulkanTexturedDS::VulkanTexturedDS(TextureManager& textureManager, Texture texture) + : texture(texture), textureAtlasIndex(textureManager.getTextureAtlasIndex(texture)), textureManager(textureManager) + { + + } + + +} // namespace gz::vlk diff --git a/src/vulkan_draw_strategies/ds_vk_base.hpp b/src/vulkan_draw_strategies/ds_vk_base.hpp new file mode 100644 index 0000000..420a1d1 --- /dev/null +++ b/src/vulkan_draw_strategies/ds_vk_base.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "draw_strategy_base.hpp" + +#include "buffer_manager.hpp" +#include "texture_manager.hpp" + +namespace gz::vlk { + class Renderer2D; + class TextureManager; + /** + * @brief Draw rectangles using the vlk::Renderer2D + * + * @todo free resources and rule of 5 + */ + class VulkanDS { + public: + VulkanDS(Renderer2D& renderer, BufferManager& bufferManager) + : renderer(renderer), bufferManager(bufferManager) {}; + + const std::vector& getVertices() const { return vertices; } + const std::vector& getIndices() const { return indices; } + const BufferInfo& getVertexBufferInfo() const { return vertexBufferInfo; } + const BufferInfo& getIndexBufferInfo() const { return indexBufferInfo; } + + /** + * @brief Add an offset to all indices (useful when putting multiple shapes in the same vertex buffer) + */ + void setIndexOffset(uint32_t offset); + /** + * @brief Normalize the vertices, so that (1, 1) is (width, height) + */ + void normalizeVertices(float width, float height); + inline bool buffersInitalized() const { return vertexBufferInfo.index != BUFFER_NOT_INITIALIZED; } + virtual ~VulkanDS() {}; + protected: + /** + * @todo free resources + */ + void updateBufferInfos(); + std::vector vertices; + std::vector indices; + BufferInfo vertexBufferInfo; + BufferInfo indexBufferInfo; + std::reference_wrapper renderer; + std::reference_wrapper> bufferManager; + }; + + + class VulkanTexturedDS { + public: + VulkanTexturedDS(TextureManager& textureManager, Texture texture); + inline const Texture& getTexture() const { return texture; } + inline uint32_t getTexureAtlasIndex() const { return textureAtlasIndex; } + virtual ~VulkanTexturedDS() {}; + protected: + Texture texture; + TextureAtlasIndex textureAtlasIndex; + std::reference_wrapper textureManager; + }; + +} // namespace gz::vlk diff --git a/src/vulkan_draw_strategies/ds_vk_rectangle.cpp b/src/vulkan_draw_strategies/ds_vk_rectangle.cpp new file mode 100644 index 0000000..df54945 --- /dev/null +++ b/src/vulkan_draw_strategies/ds_vk_rectangle.cpp @@ -0,0 +1,45 @@ +#include "ds_vk_rectangle.hpp" + +#include "texture_manager.hpp" +#include "renderer2D.hpp" + +namespace gz::vlk { + + RectangleTexturedVkDS::RectangleTexturedVkDS(Renderer2D& renderer, BufferManager& bufferManager, const std::string& textureName) + : VulkanDS(renderer, bufferManager), + VulkanTexturedDS(this->renderer.get().getTextureManager(), this->renderer.get().getTextureManager().getTexture(textureName)) + { + + } + + + void RectangleTexturedVkDS::update(const Rectangle& rect) { + // update buffers + vertices.clear(); + const auto& pos = rect.getPosition(); + const auto& size = rect.getSize(); + glm::vec3 color(0, 0, 0); + // topleft, topright, botright, botleft -> clockwise + vertices.emplace_back(Vertex2D{pos, color, glm::vec2(0, 0)}); + vertices.emplace_back(Vertex2D{glm::vec2(pos.x + size.x, pos.y), color, glm::vec2(1, 0)}); + vertices.emplace_back(Vertex2D{glm::vec2(pos.x + size.x, pos.y + size.y), color, glm::vec2(1, 1)}); + vertices.emplace_back(Vertex2D{glm::vec2(pos.x, pos.y + size.y), color, glm::vec2(0, 1)}); + /* indices = { 0, 1, 2, 2, 3, 0 }; */ + /* indices = { 2, 1, 0, 2, 3, 0 }; */ + indices = { 0, 2, 1, 0, 3, 2 }; + normalizeVertices(renderer.get().getScExtent().width, renderer.get().getScExtent().height); + + // update texture + TextureManager& tm = textureManager.get(); + tm.setTexCoords(texture, vertices[0].texCoord); + tm.setTexCoords(texture, vertices[1].texCoord); + tm.setTexCoords(texture, vertices[2].texCoord); + tm.setTexCoords(texture, vertices[3].texCoord); + + updateBufferInfos(); + } + + void RectangleTexturedVkDS::draw() { + renderer.get().drawShape(bufferManager.get(), vertexBufferInfo, indexBufferInfo, textureAtlasIndex); + } +} // namespace gz::vlk diff --git a/src/vulkan_draw_strategies/ds_vk_rectangle.hpp b/src/vulkan_draw_strategies/ds_vk_rectangle.hpp new file mode 100644 index 0000000..890ae65 --- /dev/null +++ b/src/vulkan_draw_strategies/ds_vk_rectangle.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "rectangle.hpp" +#include "ds_vk_base.hpp" +namespace gz::vlk { + /** + * @details + * Rectangle has vertex and index buffers from vlk::BufferManager + * and a texture from vlk::TextureManager + */ + class RectangleTexturedVkDS : public DrawStrategy, public VulkanDS, public VulkanTexturedDS { + public: + RectangleTexturedVkDS(Renderer2D& renderer, BufferManager& bufferManager, const std::string& textureName); + /** + * @todo + */ + void draw() override; + + /** + * @brief Set the new vertices and indices + */ + void update(const Rectangle& rect) override; + private: + void setTextureCoordinates(); + }; + +} // namespace gz::vlk diff --git a/src/vulkan_draw_strategies/ds_vk_text.cpp b/src/vulkan_draw_strategies/ds_vk_text.cpp new file mode 100644 index 0000000..76f8200 --- /dev/null +++ b/src/vulkan_draw_strategies/ds_vk_text.cpp @@ -0,0 +1,19 @@ +#include "ds_vk_text.hpp" + +namespace gz::vlk { + + void TextVkDS::draw() { + + } + + + void TextVkDS::update(const Text& text) { + + + } + + + void TextVkDS::setTextureCoordinates() { + + } +} diff --git a/src/vulkan_draw_strategies/ds_vk_text.hpp b/src/vulkan_draw_strategies/ds_vk_text.hpp new file mode 100644 index 0000000..54917dd --- /dev/null +++ b/src/vulkan_draw_strategies/ds_vk_text.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "text.hpp" +#include "ds_vk_base.hpp" + +namespace gz::vlk { + + class TextVkDS : public DrawStrategy, public VulkanDS, public VulkanTexturedDS { + public: + TextVkDS(Renderer2D& renderer, BufferManager& bufferManager, const std::string& textureName); + /** + * @todo + */ + void draw() override; + + /** + * @brief Set the new vertices and indices + */ + void update(const Text& text) override; + private: + void setTextureCoordinates(); + }; + +} // namespace gz::vlk