diff --git a/includes/mlx.h b/includes/mlx.h index bab16ee..5e68ad4 100644 --- a/includes/mlx.h +++ b/includes/mlx.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/04 16:56:35 by maldavid #+# #+# */ -/* Updated: 2023/12/11 20:35:41 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 16:27:44 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -282,7 +282,7 @@ MLX_API int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* * * @param mlx Internal MLX application * @param win Internal window - * @param filepath Filepath to the font + * @param filepath Filepath to the font or "default" to reset to the embedded font * * @return (void) */ @@ -293,7 +293,7 @@ MLX_API void mlx_set_font(void* mlx, void* win, char* filepath); * * @param mlx Internal MLX application * @param win Internal window - * @param filepath Filepath to the font + * @param filepath Filepath to the font or "default" to reset to the embedded font * @param scale Scale to apply to the font * * @return (void) diff --git a/src/core/bridge.cpp b/src/core/bridge.cpp index af8ff8b..4091d3a 100644 --- a/src/core/bridge.cpp +++ b/src/core/bridge.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/04 17:35:20 by maldavid #+# #+# */ -/* Updated: 2023/12/11 15:56:18 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 17:47:17 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -178,7 +178,7 @@ extern "C" void mlx_set_font(void* mlx, void* win, char* filepath) { std::filesystem::path file(filepath); - if(file.extension() != ".ttf" && file.extension() != ".tte") + if(std::strcmp(filepath, "default") != 0 && file.extension() != ".ttf" && file.extension() != ".tte") { mlx::core::error::report(e_kind::error, "TTF loader : not a truetype font file '%s'", filepath); return; @@ -189,7 +189,7 @@ extern "C" void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale) { std::filesystem::path file(filepath); - if(file.extension() != ".ttf" && file.extension() != ".tte") + if(std::strcmp(filepath, "default") != 0 && file.extension() != ".ttf" && file.extension() != ".tte") { mlx::core::error::report(e_kind::error, "TTF loader : not a truetype font file '%s'", filepath); return; diff --git a/src/core/graphics.cpp b/src/core/graphics.cpp index 523ff3c..ec36a73 100644 --- a/src/core/graphics.cpp +++ b/src/core/graphics.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */ -/* Updated: 2023/12/10 22:20:38 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 17:14:30 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -51,11 +51,7 @@ namespace mlx sets[1] = _pixel_put_pipeline.getDescriptorSet(); vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr); _pixel_put_pipeline.render(*_renderer); - - sets[1] = _text_put_pipeline->getDescriptorSet(); - vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr); - _text_put_pipeline->render(); - + _text_put_pipeline->render(sets); _renderer->endFrame(); for(auto& data : _textures_to_render) diff --git a/src/core/graphics.inl b/src/core/graphics.inl index 055a332..54f00ee 100644 --- a/src/core/graphics.inl +++ b/src/core/graphics.inl @@ -47,9 +47,7 @@ namespace mlx void GraphicsSupport::texturePut(Texture* texture, int x, int y) { _textures_to_render.emplace_back(texture, x, y); - auto it = std::find(_textures_to_render.begin(), _textures_to_render.end() - 1, _textures_to_render.back()); - if(it != _textures_to_render.end() - 1) _textures_to_render.erase(it); } diff --git a/src/renderer/buffers/vk_buffer.cpp b/src/renderer/buffers/vk_buffer.cpp index bd25952..a98bb74 100644 --- a/src/renderer/buffers/vk_buffer.cpp +++ b/src/renderer/buffers/vk_buffer.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/08 18:55:57 by maldavid #+# #+# */ -/* Updated: 2023/12/10 23:05:14 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/12 22:11:47 by kbz_8 ### ########.fr */ /* */ /* ************************************************************************** */ @@ -23,9 +23,9 @@ namespace mlx void Buffer::create(Buffer::kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data) { _usage = usage; - if(type == Buffer::kind::constant) + if(type == Buffer::kind::constant || type == Buffer::kind::dynamic_device_local) { - if(data == nullptr) + if(data == nullptr && type == Buffer::kind::constant) { core::error::report(e_kind::warning, "Vulkan : trying to create constant buffer without data (constant buffers cannot be modified after creation)"); return; @@ -45,7 +45,7 @@ namespace mlx mapMem(&mapped); std::memcpy(mapped, data, size); unmapMem(); - if(type == Buffer::kind::constant) + if(type == Buffer::kind::constant || type == Buffer::kind::dynamic_device_local) pushToGPU(); } } @@ -83,6 +83,40 @@ namespace mlx _size = size; } + bool Buffer::copyFromBuffer(const Buffer& buffer) noexcept + { + if(!(_usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT)) + { + core::error::report(e_kind::error, "Vulkan : buffer cannot be the destination of a copy because it does not have the correct usage flag"); + return false; + } + if(!(buffer._usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) + { + core::error::report(e_kind::error, "Vulkan : buffer cannot be the source of a copy because it does not have the correct usage flag"); + return false; + } + + // TODO, use global cmd buffer pool to manage resources + CmdPool cmdpool; + cmdpool.init(); + CmdBuffer cmdBuffer; + cmdBuffer.init(&cmdpool); + + cmdBuffer.beginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + + VkBufferCopy copyRegion{}; + copyRegion.size = _size; + vkCmdCopyBuffer(cmdBuffer.get(), buffer._buffer, _buffer, 1, ©Region); + + cmdBuffer.endRecord(); + cmdBuffer.submitIdle(); + + cmdBuffer.destroy(); + cmdpool.destroy(); + + return true; + } + void Buffer::pushToGPU() noexcept { VmaAllocationCreateInfo alloc_info{}; @@ -97,25 +131,8 @@ namespace mlx newBuffer.createBuffer(newBuffer._usage, alloc_info, _size, nullptr); #endif - CmdPool cmdpool; - cmdpool.init(); - CmdBuffer cmdBuffer; - cmdBuffer.init(&cmdpool); - - cmdBuffer.beginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - - VkBufferCopy copyRegion{}; - copyRegion.size = _size; - vkCmdCopyBuffer(cmdBuffer.get(), _buffer, newBuffer._buffer, 1, ©Region); - - cmdBuffer.endRecord(); - cmdBuffer.submitIdle(); - - cmdBuffer.destroy(); - cmdpool.destroy(); - - this->swap(newBuffer); - + if(newBuffer.copyFromBuffer(*this)) // if the copy succeded we swap the buffers, else the new one is deleted + this->swap(newBuffer); newBuffer.destroy(); } diff --git a/src/renderer/buffers/vk_buffer.h b/src/renderer/buffers/vk_buffer.h index 08b4344..f3f1669 100644 --- a/src/renderer/buffers/vk_buffer.h +++ b/src/renderer/buffers/vk_buffer.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/06 23:18:52 by maldavid #+# #+# */ -/* Updated: 2023/12/11 19:47:39 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/12 21:12:44 by kbz_8 ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ namespace mlx class Buffer { public: - enum class kind { dynamic, uniform, constant }; + enum class kind { dynamic, dynamic_device_local, uniform, constant }; void create(kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data = nullptr); void destroy() noexcept; @@ -32,6 +32,7 @@ namespace mlx inline void unmapMem() noexcept { Render_Core::get().getAllocator().unmapMemory(_allocation); _is_mapped = false; } void flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); + bool copyFromBuffer(const Buffer& buffer) noexcept; inline VkBuffer& operator()() noexcept { return _buffer; } inline VkBuffer& get() noexcept { return _buffer; } diff --git a/src/renderer/buffers/vk_vbo.cpp b/src/renderer/buffers/vk_vbo.cpp index 1b2a0d3..8ceab7d 100644 --- a/src/renderer/buffers/vk_vbo.cpp +++ b/src/renderer/buffers/vk_vbo.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/06 18:28:08 by maldavid #+# #+# */ -/* Updated: 2023/11/10 08:33:52 by maldavid ### ########.fr */ +/* Updated: 2023/12/12 22:17:14 by kbz_8 ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,7 +18,10 @@ namespace mlx void VBO::setData(uint32_t size, const void* data) { if(size > getSize()) + { core::error::report(e_kind::error, "Vulkan : trying to store to much data in a vertex buffer (%d bytes in %d bytes)", size, getSize()); + return; + } if(data == nullptr) core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer"); @@ -28,4 +31,25 @@ namespace mlx std::memcpy(temp, data, static_cast(size)); unmapMem(); } + + void D_VBO::setData(uint32_t size, const void* data) + { + if(size > getSize()) + { + core::error::report(e_kind::error, "Vulkan : trying to store to much data in a vertex buffer (%d bytes in %d bytes)", size, getSize()); + return; + } + + if(data == nullptr) + core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer"); + + Buffer tmp_buf; + #ifdef DEBUG + tmp_buf.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "tmp_buffer", data); + #else + tmp_buf.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, data); + #endif + copyFromBuffer(tmp_buf); + tmp_buf.destroy(); + } } diff --git a/src/renderer/buffers/vk_vbo.h b/src/renderer/buffers/vk_vbo.h index 6c67332..1bf2209 100644 --- a/src/renderer/buffers/vk_vbo.h +++ b/src/renderer/buffers/vk_vbo.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/06 18:27:38 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:06:45 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/12 22:46:21 by kbz_8 ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,15 @@ namespace mlx class VBO : public Buffer { public: - inline void create(uint32_t size, const char* name) { Buffer::create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name); } + inline void create(uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); } + void setData(uint32_t size, const void* data); + inline void bind(Renderer& renderer) noexcept { vkCmdBindVertexBuffers(renderer.getActiveCmdBuffer().get(), 0, 1, &_buffer, &_offset); } + }; + + class D_VBO : public Buffer + { + public: + inline void create(uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::dynamic_device_local, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); } void setData(uint32_t size, const void* data); inline void bind(Renderer& renderer) noexcept { vkCmdBindVertexBuffers(renderer.getActiveCmdBuffer().get(), 0, 1, &_buffer, &_offset); } }; diff --git a/src/renderer/descriptors/vk_descriptor_set.cpp b/src/renderer/descriptors/vk_descriptor_set.cpp index 28bc816..f0365a1 100644 --- a/src/renderer/descriptors/vk_descriptor_set.cpp +++ b/src/renderer/descriptors/vk_descriptor_set.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/01/23 18:40:44 by maldavid #+# #+# */ -/* Updated: 2023/12/07 20:00:13 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 16:45:11 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -42,7 +42,7 @@ namespace mlx #endif } - void DescriptorSet::writeDescriptor(int binding, UBO* ubo) noexcept + void DescriptorSet::writeDescriptor(int binding, UBO* ubo) const noexcept { auto device = Render_Core::get().getDevice().get(); @@ -66,7 +66,7 @@ namespace mlx } } - void DescriptorSet::writeDescriptor(int binding, VkImageView view, VkSampler sampler) noexcept + void DescriptorSet::writeDescriptor(int binding, VkImageView view, VkSampler sampler) const noexcept { auto device = Render_Core::get().getDevice().get(); diff --git a/src/renderer/descriptors/vk_descriptor_set.h b/src/renderer/descriptors/vk_descriptor_set.h index 270b46e..601032f 100644 --- a/src/renderer/descriptors/vk_descriptor_set.h +++ b/src/renderer/descriptors/vk_descriptor_set.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/01/23 18:39:36 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:09:31 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 17:12:49 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -25,10 +25,10 @@ namespace mlx public: void init(class Renderer* renderer, class DescriptorPool* pool, class DescriptorSetLayout* layout); - void writeDescriptor(int binding, class UBO* ubo) noexcept; - void writeDescriptor(int binding, VkImageView view, VkSampler sampler) noexcept; + void writeDescriptor(int binding, class UBO* ubo) const noexcept; + void writeDescriptor(int binding, VkImageView view, VkSampler sampler) const noexcept; - inline bool isInit() noexcept { return _pool != nullptr && _renderer != nullptr; } + inline bool isInit() const noexcept { return _pool != nullptr && _renderer != nullptr; } DescriptorSet duplicate(); diff --git a/src/renderer/font.cpp b/src/renderer/font.cpp new file mode 100644 index 0000000..b053b8f --- /dev/null +++ b/src/renderer/font.cpp @@ -0,0 +1,84 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* font.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maldavid +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/11 22:06:09 by kbz_8 #+# #+# */ +/* Updated: 2023/12/14 19:11:41 by maldavid ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include + +constexpr const int RANGE = 1024; + +namespace mlx +{ + Font::Font(Renderer& renderer, const std::filesystem::path& path, float scale) : non_copyable(), _name(path.string()), _scale(scale) + { + std::vector tmp_bitmap(RANGE * RANGE); + std::vector vulkan_bitmap(RANGE * RANGE * 4); + + std::ifstream file(path, std::ios::binary); + if(!file.is_open()) + { + core::error::report(e_kind::error, "Font load : cannot open font file, %s", _name.c_str()); + return; + } + std::ifstream::pos_type fileSize = std::filesystem::file_size(path); + file.seekg(0, std::ios::beg); + std::vector bytes(fileSize); + file.read(reinterpret_cast(bytes.data()), fileSize); + file.close(); + + stbtt_pack_context pc; + stbtt_PackBegin(&pc, tmp_bitmap.data(), RANGE, RANGE, RANGE, 1, nullptr); + stbtt_PackFontRange(&pc, bytes.data(), 0, scale, 32, 96, _cdata.data()); + stbtt_PackEnd(&pc); + for(int i = 0, j = 0; i < RANGE * RANGE; i++, j += 4) + { + vulkan_bitmap[j + 0] = tmp_bitmap[i]; + vulkan_bitmap[j + 1] = tmp_bitmap[i]; + vulkan_bitmap[j + 2] = tmp_bitmap[i]; + vulkan_bitmap[j + 3] = tmp_bitmap[i]; + } + #ifdef DEBUG + _atlas.create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, std::string(_name + "_font_altas").c_str(), true); + #else + _atlas.create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, nullptr, true); + #endif + _atlas.setDescriptor(renderer.getFragDescriptorSet().duplicate()); + } + + Font::Font(class Renderer& renderer, const std::string& name, const std::vector& ttf_data, float scale) : non_copyable(), _name(name), _scale(scale) + { + std::vector tmp_bitmap(RANGE * RANGE); + std::vector vulkan_bitmap(RANGE * RANGE * 4); + stbtt_pack_context pc; + stbtt_PackBegin(&pc, tmp_bitmap.data(), RANGE, RANGE, RANGE, 1, nullptr); + stbtt_PackFontRange(&pc, ttf_data.data(), 0, scale, 32, 96, _cdata.data()); + stbtt_PackEnd(&pc); + for(int i = 0, j = 0; i < RANGE * RANGE; i++, j += 4) + { + vulkan_bitmap[j + 0] = tmp_bitmap[i]; + vulkan_bitmap[j + 1] = tmp_bitmap[i]; + vulkan_bitmap[j + 2] = tmp_bitmap[i]; + vulkan_bitmap[j + 3] = tmp_bitmap[i]; + } + #ifdef DEBUG + _atlas.create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, std::string(_name + "_font_altas").c_str(), true); + #else + _atlas.create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, nullptr, true); + #endif + _atlas.setDescriptor(renderer.getFragDescriptorSet().duplicate()); + } + + Font::~Font() + { + _atlas.destroy(); + } +} diff --git a/src/renderer/font.h b/src/renderer/font.h new file mode 100644 index 0000000..d25c4b7 --- /dev/null +++ b/src/renderer/font.h @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* font.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maldavid +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/11 21:17:04 by kbz_8 #+# #+# */ +/* Updated: 2023/12/14 17:51:40 by maldavid ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef __MLX_FONT__ +#define __MLX_FONT__ + +#include +#include +#include +#include +#include + +namespace mlx +{ + class Font : public non_copyable + { + public: + Font() = delete; + Font(class Renderer& renderer, const std::filesystem::path& path, float scale); + Font(class Renderer& renderer, const std::string& name, const std::vector& ttf_data, float scale); + inline const std::string& getName() const { return _name; } + inline float getScale() const noexcept { return _scale; } + inline const std::array& getCharData() const { return _cdata; } + inline const TextureAtlas& getAtlas() const noexcept { return _atlas; } + inline bool operator==(const Font& rhs) const { return rhs._name == _name; } + inline bool operator!=(const Font& rhs) const { return rhs._name != _name; } + ~Font(); + + private: + std::array _cdata; + TextureAtlas _atlas; + std::string _name; + float _scale = 0; + }; +} + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(const mlx::Font& f) const noexcept + { + std::size_t hash = 0; + mlx::hashCombine(hash, f.getName(), f.getScale()); + return hash; + } + }; +} + +#endif diff --git a/src/renderer/images/texture_atlas.cpp b/src/renderer/images/texture_atlas.cpp index f129baf..be611bc 100644 --- a/src/renderer/images/texture_atlas.cpp +++ b/src/renderer/images/texture_atlas.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/07 16:40:09 by maldavid #+# #+# */ -/* Updated: 2023/11/14 05:36:46 by maldavid ### ########.fr */ +/* Updated: 2023/12/14 16:39:54 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -36,7 +36,7 @@ namespace mlx } } - void TextureAtlas::render(Renderer& renderer, int x, int y, uint32_t ibo_size) + void TextureAtlas::render(Renderer& renderer, int x, int y, uint32_t ibo_size) const { auto cmd = renderer.getActiveCmdBuffer().get(); diff --git a/src/renderer/images/texture_atlas.h b/src/renderer/images/texture_atlas.h index c571e27..1cb8c09 100644 --- a/src/renderer/images/texture_atlas.h +++ b/src/renderer/images/texture_atlas.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/07 16:36:33 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:10:22 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 17:12:54 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -26,12 +26,12 @@ namespace mlx TextureAtlas() = default; void create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false); - void render(class Renderer& renderer, int x, int y, uint32_t ibo_size); + void render(class Renderer& renderer, int x, int y, uint32_t ibo_size) const; void destroy() noexcept override; inline void setDescriptor(DescriptorSet&& set) noexcept { _set = set; } inline VkDescriptorSet getSet() noexcept { return _set.isInit() ? _set.get() : VK_NULL_HANDLE; } - inline void updateSet(int binding) noexcept { _set.writeDescriptor(binding, getImageView(), getSampler()); } + inline void updateSet(int binding) const noexcept { _set.writeDescriptor(binding, getImageView(), getSampler()); } ~TextureAtlas() = default; diff --git a/src/renderer/images/vk_image.h b/src/renderer/images/vk_image.h index 2498c90..a55a2a4 100644 --- a/src/renderer/images/vk_image.h +++ b/src/renderer/images/vk_image.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/01/25 11:54:21 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:10:38 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 16:44:40 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -50,10 +50,10 @@ namespace mlx inline VkImage get() noexcept { return _image; } inline VkImage operator()() noexcept { return _image; } - inline VkImageView getImageView() noexcept { return _image_view; } - inline VkFormat getFormat() noexcept { return _format; } - inline VkImageTiling getTiling() noexcept { return _tiling; } - inline VkSampler getSampler() noexcept { return _sampler; } + inline VkImageView getImageView() const noexcept { return _image_view; } + inline VkFormat getFormat() const noexcept { return _format; } + inline VkImageTiling getTiling() const noexcept { return _tiling; } + inline VkSampler getSampler() const noexcept { return _sampler; } inline uint32_t getWidth() const noexcept { return _width; } inline uint32_t getHeight() const noexcept { return _height; } diff --git a/src/renderer/pixel_put.cpp b/src/renderer/pixel_put.cpp index 90e4fe1..7dcff20 100644 --- a/src/renderer/pixel_put.cpp +++ b/src/renderer/pixel_put.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/03/31 15:14:50 by maldavid #+# #+# */ -/* Updated: 2023/12/10 22:33:59 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 18:26:03 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,14 +22,14 @@ namespace mlx _buffer.create(Buffer::kind::dynamic, sizeof(uint32_t) * (width * height), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "__mlx_pixel_put_pipeline_texture"); _buffer.mapMem(&_buffer_map); - _cpu_map = std::vector(height * width, 0); + _cpu_map = std::vector(height * width + 1, 0); _width = width; _height = height; } - void PixelPutPipeline::setPixel(uint32_t x, uint32_t y, uint32_t color) noexcept + void PixelPutPipeline::setPixel(int x, int y, uint32_t color) noexcept { - if(x > _width || y > _height) + if(x < 0 || y < 0 || x > static_cast(_width) || y > static_cast(_height)) return; _cpu_map[(y * _width) + x] = color; _has_been_modified = true; diff --git a/src/renderer/pixel_put.h b/src/renderer/pixel_put.h index bd51d41..eddae2f 100644 --- a/src/renderer/pixel_put.h +++ b/src/renderer/pixel_put.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/03/31 13:18:50 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:11:43 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 18:24:58 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -26,7 +26,7 @@ namespace mlx void init(uint32_t width, uint32_t height, class Renderer& renderer) noexcept; - void setPixel(uint32_t x, uint32_t y, uint32_t color) noexcept; + void setPixel(int x, int y, uint32_t color) noexcept; void present() noexcept; void render(class Renderer& renderer) noexcept; inline VkDescriptorSet getDescriptorSet() noexcept { return _texture.getSet(); } diff --git a/src/renderer/text_library.cpp b/src/renderer/text_library.cpp index ec34951..0a68dd4 100644 --- a/src/renderer/text_library.cpp +++ b/src/renderer/text_library.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/10 11:59:57 by maldavid #+# #+# */ -/* Updated: 2023/11/16 13:45:31 by maldavid ### ########.fr */ +/* Updated: 2023/12/12 23:03:33 by kbz_8 ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,27 +17,36 @@ namespace mlx { - void TextData::init(std::string text, std::vector vbo_data, std::vector ibo_data) + void TextData::init(std::string text, Font const* font, std::vector vbo_data, std::vector ibo_data) { _text = std::move(text); + _font = font; #ifdef DEBUG - _vbo.create(sizeof(Vertex) * vbo_data.size(), vbo_data.data(), _text.c_str()); + for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + _vbo[i].create(sizeof(Vertex) * vbo_data.size(), static_cast(vbo_data.data()), _text.c_str()); _ibo.create(sizeof(uint16_t) * ibo_data.size(), ibo_data.data(), _text.c_str()); #else - _vbo.create(sizeof(Vertex) * vbo_data.size(), vbo_data.data(), nullptr); + for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + _vbo[i].create(sizeof(Vertex) * vbo_data.size(), static_cast(vbo_data.data()), nullptr); _ibo.create(sizeof(uint16_t) * ibo_data.size(), ibo_data.data(), nullptr); #endif } void TextData::bind(Renderer& renderer) noexcept { - _vbo.bind(renderer); + _vbo[renderer.getActiveImageIndex()].bind(renderer); _ibo.bind(renderer); } + void TextData::updateVertexData(int frame, std::vector vbo_data) + { + _vbo[frame].setData(sizeof(Vertex) * vbo_data.size(), static_cast(vbo_data.data())); + } + void TextData::destroy() noexcept { - _vbo.destroy(); + for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + _vbo[i].destroy(); _ibo.destroy(); } diff --git a/src/renderer/text_library.h b/src/renderer/text_library.h index b889224..1283a99 100644 --- a/src/renderer/text_library.h +++ b/src/renderer/text_library.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/10 11:52:30 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:12:24 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/12 23:07:13 by kbz_8 ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,6 +21,8 @@ #include #include #include +#include +#include namespace mlx { @@ -32,8 +34,10 @@ namespace mlx public: TextData() = default; - void init(std::string text, std::vector vbo_data, std::vector ibo_data); + void init(std::string text, Font const* font, std::vector vbo_data, std::vector ibo_data); void bind(class Renderer& renderer) noexcept; + inline const Font& getFontInUse() const noexcept { return *_font; } + void updateVertexData(int frame, std::vector vbo_data); inline uint32_t getIBOsize() noexcept { return _ibo.getSize(); } inline const std::string& getText() const { return _text; } void destroy() noexcept; @@ -41,9 +45,10 @@ namespace mlx ~TextData() = default; private: - C_VBO _vbo; + std::array _vbo; C_IBO _ibo; std::string _text; + Font const* _font = nullptr; }; class TextLibrary diff --git a/src/renderer/text_pipeline.cpp b/src/renderer/text_pipeline.cpp index 4468a0b..173e6f9 100644 --- a/src/renderer/text_pipeline.cpp +++ b/src/renderer/text_pipeline.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/06 16:41:13 by maldavid #+# #+# */ -/* Updated: 2023/12/11 15:12:02 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 17:49:37 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -36,7 +36,7 @@ namespace mlx text(std::move(_text)) {} - void TextDrawData::init(TextLibrary& library, std::array& cdata) noexcept + void TextDrawData::init(TextLibrary& library, Font* const font) noexcept { std::vector vertexData; std::vector indexData; @@ -50,7 +50,7 @@ namespace mlx continue; stbtt_aligned_quad q; - stbtt_GetPackedQuad(cdata.data(), RANGE, RANGE, c - 32, &stb_x, &stb_y, &q, 1); + stbtt_GetPackedQuad(font->getCharData().data(), RANGE, RANGE, c - 32, &stb_x, &stb_y, &q, 1); std::size_t index = vertexData.size(); @@ -67,7 +67,7 @@ namespace mlx indexData.emplace_back(index + 0); } std::shared_ptr text_data = std::make_shared(); - text_data->init(text, std::move(vertexData), std::move(indexData)); + text_data->init(text, font, std::move(vertexData), std::move(indexData)); id = library.addTextToLibrary(text_data); #ifdef DEBUG @@ -78,71 +78,44 @@ namespace mlx void TextPutPipeline::init(Renderer* renderer) noexcept { _renderer = renderer; - std::vector tmp_bitmap(RANGE * RANGE); - std::vector vulkan_bitmap(RANGE * RANGE * 4); - stbtt_pack_context pc; - stbtt_PackBegin(&pc, tmp_bitmap.data(), RANGE, RANGE, RANGE, 1, nullptr); - stbtt_PackFontRange(&pc, dogica_ttf, 0, 6.0, 32, 96, _cdata.data()); - stbtt_PackEnd(&pc); - for(int i = 0, j = 0; i < RANGE * RANGE; i++, j += 4) - { - vulkan_bitmap[j + 0] = tmp_bitmap[i]; - vulkan_bitmap[j + 1] = tmp_bitmap[i]; - vulkan_bitmap[j + 2] = tmp_bitmap[i]; - vulkan_bitmap[j + 3] = tmp_bitmap[i]; - } - _atlas.create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_texts_pipeline_texture_atlas", true); - _atlas.setDescriptor(renderer->getFragDescriptorSet().duplicate()); + _font_in_use = &const_cast(*_font_set.emplace(*_renderer, "default", dogica_ttf, 6.0f).first); } void TextPutPipeline::loadFont(const std::filesystem::path& filepath, float scale) { - std::vector tmp_bitmap(RANGE * RANGE); - std::vector vulkan_bitmap(RANGE * RANGE * 4); - - std::ifstream file(filepath, std::ios::binary); - if(!file.is_open()) - { - core::error::report(e_kind::error, "Font load : cannot open font file, %s", filepath.string().c_str()); - return; - } - std::ifstream::pos_type fileSize = std::filesystem::file_size(filepath); - file.seekg(0, std::ios::beg); - std::vector bytes(fileSize); - file.read(reinterpret_cast(bytes.data()), fileSize); - file.close(); - - stbtt_pack_context pc; - stbtt_PackBegin(&pc, tmp_bitmap.data(), RANGE, RANGE, RANGE, 1, nullptr); - stbtt_PackFontRange(&pc, bytes.data(), 0, scale, 32, 96, _cdata.data()); - stbtt_PackEnd(&pc); - for(int i = 0, j = 0; i < RANGE * RANGE; i++, j += 4) - { - vulkan_bitmap[j + 0] = tmp_bitmap[i]; - vulkan_bitmap[j + 1] = tmp_bitmap[i]; - vulkan_bitmap[j + 2] = tmp_bitmap[i]; - vulkan_bitmap[j + 3] = tmp_bitmap[i]; - } - destroy(); - _atlas.create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_texts_pipeline_texture_atlas", true); - _atlas.setDescriptor(_renderer->getFragDescriptorSet().duplicate()); + if(filepath.string() == "default") // we're sure it is already loaded + _font_in_use = &const_cast(*_font_set.emplace(*_renderer, "default", dogica_ttf, scale).first); + else + _font_in_use = &const_cast(*_font_set.emplace(*_renderer, filepath, scale).first); } void TextPutPipeline::put(int x, int y, int color, std::string str) { auto res = _drawlist.emplace(std::move(str), color, x, y); if(res.second) - const_cast(*res.first).init(_library, _cdata); + const_cast(*res.first).init(_library, _font_in_use); + else + { + auto text_ptr = _library.getTextData(res.first->id); + if(*_font_in_use != text_ptr->getFontInUse()) + { + _library.removeTextFromLibrary(res.first->id); + const_cast(*res.first).init(_library, _font_in_use); + } + } } - void TextPutPipeline::render() + void TextPutPipeline::render(std::array& sets) { - _atlas.updateSet(0); for(auto& draw : _drawlist) { std::shared_ptr draw_data = _library.getTextData(draw.id); + const TextureAtlas& atlas = draw_data->getFontInUse().getAtlas(); draw_data->bind(*_renderer); - _atlas.render(*_renderer, draw.x, draw.y, draw_data->getIBOsize()); + atlas.updateSet(0); + sets[1] = const_cast(atlas).getSet(); + vkCmdBindDescriptorSets(_renderer->getActiveCmdBuffer().get(), VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr); + atlas.render(*_renderer, draw.x, draw.y, draw_data->getIBOsize()); } } @@ -150,6 +123,6 @@ namespace mlx { _library.clearLibrary(); _drawlist.clear(); - _atlas.destroy(); + _font_set.clear(); } } diff --git a/src/renderer/text_pipeline.h b/src/renderer/text_pipeline.h index b6ca962..efb5058 100644 --- a/src/renderer/text_pipeline.h +++ b/src/renderer/text_pipeline.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/06 16:24:11 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:12:40 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 17:39:51 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,6 +21,7 @@ #include #include #include +#include namespace mlx { @@ -33,8 +34,9 @@ namespace mlx std::string text; TextDrawData(std::string text, int _color, int _x, int _y); - void init(TextLibrary& library, std::array& cdata) noexcept; + void init(TextLibrary& library, Font* const font) noexcept; bool operator==(const TextDrawData& rhs) const { return text == rhs.text && x == rhs.x && y == rhs.y && color == rhs.color; } + TextDrawData() = default; }; } @@ -45,7 +47,9 @@ namespace std { std::size_t operator()(const mlx::TextDrawData& d) const noexcept { - return std::hash()(d.text) + std::hash()(d.x) + std::hash()(d.y) + std::hash()(d.color); + std::size_t hash = 0; + mlx::hashCombine(hash, d.text, d.x, d.y, d.color); + return hash; } }; } @@ -59,20 +63,19 @@ namespace mlx void init(Renderer* renderer) noexcept; void put(int x, int y, int color, std::string str); - inline VkDescriptorSet getDescriptorSet() noexcept { return _atlas.getSet(); } - inline void clear() { _drawlist.clear(); } + inline void clear() { _drawlist.clear(); _library.clearLibrary(); } void loadFont(const std::filesystem::path& filepath, float scale); - void render(); + void render(std::array& sets); void destroy() noexcept; ~TextPutPipeline() = default; private: - std::array _cdata; - TextureAtlas _atlas; + std::unordered_set _font_set; TextLibrary _library; std::unordered_set _drawlist; Renderer* _renderer = nullptr; + Font* _font_in_use = nullptr; }; } diff --git a/src/utils/combine_hash.h b/src/utils/combine_hash.h new file mode 100644 index 0000000..48a33a3 --- /dev/null +++ b/src/utils/combine_hash.h @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* combine_hash.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maldavid +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/14 16:16:06 by maldavid #+# #+# */ +/* Updated: 2023/12/14 16:47:39 by maldavid ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef __MLX_HASH__ +#define __MLX_HASH__ + +#include +#include + +namespace mlx +{ + inline void hashCombine([[maybe_unused]] std::size_t& seed) noexcept {} + + template + inline void hashCombine(std::size_t& seed, const T& v, Rest... rest) + { + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + hashCombine(seed, rest...); + } +} + +#endif diff --git a/src/utils/dogica_ttf.h b/src/utils/dogica_ttf.h index a2907d3..e890ab3 100644 --- a/src/utils/dogica_ttf.h +++ b/src/utils/dogica_ttf.h @@ -6,16 +6,18 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/11 16:20:25 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:13:00 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/14 16:54:12 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ #ifndef __MLX_DOGICA_TTF__ #define __MLX_DOGICA_TTF__ +#include + constexpr const unsigned int dogica_ttf_len = 33860; -constexpr const unsigned char dogica_ttf[dogica_ttf_len] = { +static const std::vector dogica_ttf = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60, 0x46, 0x46, 0x54, 0x4d, 0x8f, 0xe1, 0x5b, 0x60, 0x00, 0x00, 0x84, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x47, 0x44, 0x45, 0x46, 0x00, 0x15, 0x00, 0x14, diff --git a/test/main.c b/test/main.c index e618462..3da1085 100644 --- a/test/main.c +++ b/test/main.c @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/04 17:55:21 by maldavid #+# #+# */ -/* Updated: 2023/12/14 13:49:22 by maldavid ### ########.fr */ +/* Updated: 2023/12/14 18:49:01 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -32,22 +32,21 @@ int update(void *param) mlx = (t_mlx *)param; mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->logo, 100, 100); mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->img, 150, 60); + if (i == 0) + mlx_set_font_scale(mlx->mlx, mlx->win, "font.ttf", 16.f); mlx_string_put(mlx->mlx, mlx->win, 20, 50, 0xFFFFFFFF, "that's a text"); j = 0; k = 0; - while (j < 400) + while (j++ < 400) { mlx_pixel_put(mlx->mlx, mlx->win, j, j, 0xFFFF0000 + k); mlx_pixel_put(mlx->mlx, mlx->win, 399 - j, j, 0xFF0000FF); - if (k < 255) - k++; - j++; + k += (k < 255); } if (++i == 5000) - { mlx_clear_window(mlx->mlx, mlx->win); - mlx_set_font_scale(mlx->mlx, mlx->win, "font.ttf", 16.f); - } + if (i == 7000) + mlx_set_font_scale(mlx->mlx, mlx->win, "default", 16.f); return (0); } diff --git a/valgrind.supp b/valgrind.supp index 3e26281..d746267 100644 --- a/valgrind.supp +++ b/valgrind.supp @@ -54,7 +54,16 @@ fun:*alloc obj:* ... - fun:_dl_* + fun:dl_* + ... +} +{ + name + Memcheck:Addr8 + fun:* + obj:* + ... + fun:dl_* ... } {