Merge pull request #17 from 420verfl0w/indev

merge dev to master
This commit is contained in:
kbz_8
2023-12-15 21:13:53 +01:00
committed by GitHub
36 changed files with 508 additions and 159 deletions

View File

@@ -13,6 +13,20 @@
###### MacroLibX, a rewrite of 42 School's MiniLibX using SDL2 and Vulkan.
The goal of this version is to provide a light, fast, and modern graphical tool while keeping the same API.
## 💫 Features
### 🏁 Performances
Built on top of Vulkan, the MacroLibX takes advantage of its very low-level nature to achieve high performance with great control over available resources.
### 💻 Cross-Platform
Designed to be totally cross-platform, it can run on any SDL2-supported platform that supports Vulkan (even the Nintendo Switch ! theoretically... ).
### 🗿 Close to the old minilibx
One of the guidelines of this lib was to get as close as possible to the old minilibx API, and therefore to the educational choices of the old minilibx.
### 📖 It's all FOSS
Everything in this repo is entirely free and open source, all available under the MIT license (even the third-party libraries used).
## 🖥️ Installation
### Dependencies

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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)

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 22:10:52 by maldavid #+# #+# */
/* Updated: 2023/12/11 19:46:13 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 20:51:41 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -61,7 +61,7 @@ namespace mlx::core
void Application::destroyTexture(void* ptr)
{
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); // TODO : synchronize with another method than stopping all the GPU porcess
Texture* texture = static_cast<Texture*>(ptr);
texture->destroy();
}

View File

@@ -74,7 +74,15 @@ namespace mlx::core
void Application::texturePut(void* win, void* img, int x, int y)
{
if(img == nullptr)
{
core::error::report(e_kind::error, "wrong texture (NULL)");
return;
}
Texture* texture = static_cast<Texture*>(img);
if(!texture->isInit())
core::error::report(e_kind::error, "trying to put a texture that has been destroyed");
else
_graphics[*static_cast<int*>(win)]->texturePut(texture, x, y);
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */
/* Updated: 2023/12/10 22:20:38 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 21:04:50 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -37,6 +37,8 @@ namespace mlx
for(auto& data : _textures_to_render)
{
if(!data.texture->isInit())
continue;
if(data.texture->getSet() == VK_NULL_HANDLE)
data.texture->setDescriptor(_renderer->getFragDescriptorSet().duplicate());
if(!data.texture->hasBeenUpdated())
@@ -51,11 +53,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)

View File

@@ -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);
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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, &copyRegion);
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, &copyRegion);
cmdBuffer.endRecord();
cmdBuffer.submitIdle();
cmdBuffer.destroy();
cmdpool.destroy();
if(newBuffer.copyFromBuffer(*this)) // if the copy succeded we swap the buffers, else the new one is deleted
this->swap(newBuffer);
newBuffer.destroy();
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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; }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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_t>(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();
}
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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); }
};

View File

@@ -0,0 +1,47 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* single_time_cmd_manager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/15 19:57:49 by maldavid #+# #+# */
/* Updated: 2023/12/15 20:21:54 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <algorithm>
#include <renderer/command/single_time_cmd_manager.h>
#include <renderer/core/render_core.h>
namespace mlx
{
SingleTimeCmdManager::SingleTimeCmdManager() : _buffers(MIN_POOL_SIZE) {}
void SingleTimeCmdManager::init() noexcept
{
_pool.init();
for(int i = 0; i < MIN_POOL_SIZE; i++)
_buffers.emplace_back().init(&_pool);
}
void SingleTimeCmdManager::destroy() noexcept
{
std::for_each(_buffers.begin(), _buffers.end(), [](CmdBuffer& buf)
{
buf.destroy();
});
_pool.destroy();
}
CmdBuffer& SingleTimeCmdManager::getCmdBuffer() noexcept
{
for(CmdBuffer& buf : _buffers)
{
if(buf.isReadyToBeUsed())
return buf;
}
_buffers.emplace_back().init(&_pool);
return _buffers.back();
}
}

View File

@@ -0,0 +1,44 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* single_time_cmd_manager.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/15 18:25:57 by maldavid #+# #+# */
/* Updated: 2023/12/15 19:59:40 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_SINGLE_TIME_CMD_MANAGER__
#define __MLX_SINGLE_TIME_CMD_MANAGER__
#include <vector>
#include <renderer/command/vk_cmd_pool.h>
#include <renderer/command/vk_cmd_buffer.h>
namespace mlx
{
class SingleTimeCmdManager
{
public:
SingleTimeCmdManager();
void init() noexcept;
void destroy() noexcept;
inline CmdPool& getCmdPool() noexcept { return _pool; }
CmdBuffer& getCmdBuffer() noexcept;
~SingleTimeCmdManager() = default;
inline static constexpr const uint8_t MIN_POOL_SIZE = 8;
private:
std::vector<CmdBuffer> _buffers;
CmdPool _pool;
};
}
#endif

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:25:42 by maldavid #+# #+# */
/* Updated: 2023/12/08 19:07:11 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 20:19:42 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -31,6 +31,7 @@ namespace mlx
void submitIdle() noexcept;
inline void waitForExecution() noexcept { _fence.waitAndReset(); }
inline void reset() noexcept { vkResetCommandBuffer(_cmd_buffer, 0); }
inline bool isReadyToBeUsed() const noexcept { return _fence.isReady(); }
void endRecord();
inline bool isRecording() const noexcept { return _is_recording; }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/17 23:33:34 by maldavid #+# #+# */
/* Updated: 2023/12/12 15:45:26 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 20:32:01 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -16,8 +16,10 @@
#define VK_USE_PLATFORM_WIN32_KHR
#elif defined(__APPLE__) || defined(__MACH__)
#define VK_USE_PLATFORM_MACOS_MVK
#define VK_USE_PLATFORM_METAL_EXT
#else
#define VK_USE_PLATFORM_XLIB_KHR
#define VK_USE_PLATFORM_WAYLAND_KHR
#endif
#include "render_core.h"
@@ -95,6 +97,7 @@ namespace mlx
volkLoadDevice(_device.get());
_queues.init();
_allocator.init();
_cmd_manager.init();
_is_init = true;
}
@@ -105,6 +108,7 @@ namespace mlx
vkDeviceWaitIdle(_device());
_cmd_manager.destroy();
_allocator.destroy();
_device.destroy();
_layers.destroy();

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:16:32 by maldavid #+# #+# */
/* Updated: 2023/12/12 15:45:39 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 20:31:08 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -16,6 +16,7 @@
#include <volk.h>
#include <optional>
#include <renderer/command/single_time_cmd_manager.h>
#include "vk_queues.h"
#include "vk_device.h"
#include "vk_instance.h"
@@ -57,11 +58,13 @@ namespace mlx
inline Queues& getQueue() noexcept { return _queues; }
inline GPUallocator& getAllocator() noexcept { return _allocator; }
inline ValidationLayers& getLayers() noexcept { return _layers; }
inline CmdBuffer& getSingleTimeCmdBuffer() noexcept { return _cmd_manager.getCmdBuffer(); }
~Render_Core() = default;
private:
ValidationLayers _layers;
SingleTimeCmdManager _cmd_manager;
Queues _queues;
Device _device;
Instance _instance;

View File

@@ -6,11 +6,12 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */
/* Updated: 2023/12/12 15:50:48 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 20:31:29 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <renderer/core/vk_fence.h>
#include <renderer/core/render_core.h>
namespace mlx
{
@@ -38,6 +39,11 @@ namespace mlx
vkResetFences(Render_Core::get().getDevice().get(), 1, &_fence);
}
bool Fence::isReady() const noexcept
{
return vkGetFenceStatus(Render_Core::get().getDevice().get(), _fence) == VK_SUCCESS;
}
void Fence::destroy() noexcept
{
if(_fence != VK_NULL_HANDLE)

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:52:09 by maldavid #+# #+# */
/* Updated: 2023/12/08 19:08:01 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 20:31:25 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -15,7 +15,6 @@
#include <volk.h>
#include <mlx_profile.h>
#include <renderer/core/render_core.h>
namespace mlx
{
@@ -29,6 +28,7 @@ namespace mlx
inline VkFence& get() noexcept { return _fence; }
void wait() noexcept;
void reset() noexcept;
bool isReady() const noexcept;
inline void waitAndReset() noexcept { wait(); reset(); }
void destroy() noexcept;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:04:21 by maldavid #+# #+# */
/* Updated: 2023/12/12 15:46:06 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 16:20:26 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -21,10 +21,8 @@ namespace mlx
{
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "MacroLibX";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "MacroLibX";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.engineVersion = VK_MAKE_VERSION(1, 2, 1);
appInfo.apiVersion = VK_API_VERSION_1_2;
VkInstanceCreateInfo createInfo{};

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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();

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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();

84
src/renderer/font.cpp git.filemode.normal_file
View File

@@ -0,0 +1,84 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* font.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/11 22:06:09 by kbz_8 #+# #+# */
/* Updated: 2023/12/14 19:11:41 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <renderer/font.h>
#include <renderer/renderer.h>
#include <fstream>
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<uint8_t> tmp_bitmap(RANGE * RANGE);
std::vector<uint8_t> 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<uint8_t> bytes(fileSize);
file.read(reinterpret_cast<char*>(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<uint8_t>& ttf_data, float scale) : non_copyable(), _name(name), _scale(scale)
{
std::vector<uint8_t> tmp_bitmap(RANGE * RANGE);
std::vector<uint8_t> 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();
}
}

60
src/renderer/font.h git.filemode.normal_file
View File

@@ -0,0 +1,60 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* font.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 <array>
#include <stb_truetype.h>
#include <utils/non_copyable.h>
#include <renderer/images/texture_atlas.h>
#include <utils/combine_hash.h>
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<uint8_t>& ttf_data, float scale);
inline const std::string& getName() const { return _name; }
inline float getScale() const noexcept { return _scale; }
inline const std::array<stbtt_packedchar, 96>& 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<stbtt_packedchar, 96> _cdata;
TextureAtlas _atlas;
std::string _name;
float _scale = 0;
};
}
namespace std
{
template <>
struct hash<mlx::Font>
{
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

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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();

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/25 11:54:21 by maldavid #+# #+# */
/* Updated: 2023/12/08 19:10:38 by kbz_8 ### ########.fr */
/* Updated: 2023/12/15 21:07:34 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -16,6 +16,7 @@
#include <volk.h>
#include <cstddef>
#include <vector>
#include <vma.h>
#include <renderer/command/vk_cmd_buffer.h>
#include <renderer/command/vk_cmd_pool.h>
#include <mlx_profile.h>
@@ -50,12 +51,13 @@ 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; }
inline bool isInit() const noexcept { return _image != VK_NULL_HANDLE; }
virtual ~Image() = default;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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<uint32_t>(height * width, 0);
_cpu_map = std::vector<uint32_t>(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<int>(_width) || y > static_cast<int>(_height))
return;
_cpu_map[(y * _width) + x] = color;
_has_been_modified = true;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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(); }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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<Vertex> vbo_data, std::vector<uint16_t> ibo_data)
void TextData::init(std::string text, Font const* font, std::vector<Vertex> vbo_data, std::vector<uint16_t> 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<const void*>(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<const void*>(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<Vertex> vbo_data)
{
_vbo[frame].setData(sizeof(Vertex) * vbo_data.size(), static_cast<const void*>(vbo_data.data()));
}
void TextData::destroy() noexcept
{
_vbo.destroy();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
_vbo[i].destroy();
_ibo.destroy();
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 <vector>
#include <cstdint>
#include <mlx_profile.h>
#include <renderer/font.h>
#include <renderer/core/render_core.h>
namespace mlx
{
@@ -32,8 +34,10 @@ namespace mlx
public:
TextData() = default;
void init(std::string text, std::vector<Vertex> vbo_data, std::vector<uint16_t> ibo_data);
void init(std::string text, Font const* font, std::vector<Vertex> vbo_data, std::vector<uint16_t> ibo_data);
void bind(class Renderer& renderer) noexcept;
inline const Font& getFontInUse() const noexcept { return *_font; }
void updateVertexData(int frame, std::vector<Vertex> 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<D_VBO, MAX_FRAMES_IN_FLIGHT> _vbo;
C_IBO _ibo;
std::string _text;
Font const* _font = nullptr;
};
class TextLibrary

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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<stbtt_packedchar, 96>& cdata) noexcept
void TextDrawData::init(TextLibrary& library, Font* const font) noexcept
{
std::vector<Vertex> vertexData;
std::vector<uint16_t> 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<TextData> text_data = std::make_shared<TextData>();
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<uint8_t> tmp_bitmap(RANGE * RANGE);
std::vector<uint8_t> 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&>(*_font_set.emplace(*_renderer, "default", dogica_ttf, 6.0f).first);
}
void TextPutPipeline::loadFont(const std::filesystem::path& filepath, float scale)
{
std::vector<uint8_t> tmp_bitmap(RANGE * RANGE);
std::vector<uint8_t> 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<uint8_t> bytes(fileSize);
file.read(reinterpret_cast<char*>(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&>(*_font_set.emplace(*_renderer, "default", dogica_ttf, scale).first);
else
_font_in_use = &const_cast<Font&>(*_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<TextDrawData&>(*res.first).init(_library, _cdata);
const_cast<TextDrawData&>(*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<TextDrawData&>(*res.first).init(_library, _font_in_use);
}
}
}
void TextPutPipeline::render()
void TextPutPipeline::render(std::array<VkDescriptorSet, 2>& sets)
{
_atlas.updateSet(0);
for(auto& draw : _drawlist)
{
std::shared_ptr<TextData> 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<TextureAtlas&>(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();
}
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 <unordered_set>
#include <renderer/text_library.h>
#include <mlx_profile.h>
#include <utils/combine_hash.h>
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<stbtt_packedchar, 96>& 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<std::string>()(d.text) + std::hash<int>()(d.x) + std::hash<int>()(d.y) + std::hash<int>()(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<VkDescriptorSet, 2>& sets);
void destroy() noexcept;
~TextPutPipeline() = default;
private:
std::array<stbtt_packedchar, 96> _cdata;
TextureAtlas _atlas;
std::unordered_set<Font> _font_set;
TextLibrary _library;
std::unordered_set<TextDrawData> _drawlist;
Renderer* _renderer = nullptr;
Font* _font_in_use = nullptr;
};
}

32
src/utils/combine_hash.h git.filemode.normal_file
View File

@@ -0,0 +1,32 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* combine_hash.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 <cstddef>
#include <functional>
namespace mlx
{
inline void hashCombine([[maybe_unused]] std::size_t& seed) noexcept {}
template <typename T, typename... Rest>
inline void hashCombine(std::size_t& seed, const T& v, Rest... rest)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
hashCombine(seed, rest...);
}
}
#endif

View File

@@ -6,16 +6,18 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 <vector>
constexpr const unsigned int dogica_ttf_len = 33860;
constexpr const unsigned char dogica_ttf[dogica_ttf_len] = {
static const std::vector<unsigned char> 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,

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:55:21 by maldavid #+# #+# */
/* Updated: 2023/12/14 13:49:22 by maldavid ### ########.fr */
/* Updated: 2023/12/15 21:08:07 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);
}

View File

@@ -54,7 +54,16 @@
fun:*alloc
obj:*
...
fun:_dl_*
fun:dl_*
...
}
{
name
Memcheck:Addr8
fun:*
obj:*
...
fun:dl_*
...
}
{