adding multiple font support

This commit is contained in:
2023-12-14 19:13:41 +01:00
parent a0a764d6a2
commit c7e59cbbeb
20 changed files with 131 additions and 86 deletions

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();

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/11 22:06:09 by kbz_8 #+# #+# */
/* Updated: 2023/12/12 23:57:53 by kbz_8 ### ########.fr */
/* Updated: 2023/12/14 19:11:41 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -18,7 +18,7 @@ constexpr const int RANGE = 1024;
namespace mlx
{
Font::Font(Renderer& renderer, const std::filesystem::path& path, float scale) : non_copyable(), _name(path.string())
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);
@@ -47,20 +47,20 @@ namespace mlx
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);
_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)
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, 6.0, 32, 96, _cdata.data());
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)
{
@@ -70,7 +70,7 @@ namespace mlx
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);
_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

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/11 21:17:04 by kbz_8 #+# #+# */
/* Updated: 2023/12/13 00:25:30 by kbz_8 ### ########.fr */
/* Updated: 2023/12/14 17:51:40 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -17,24 +17,29 @@
#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 VkDescriptorSet getDescriptorSet() noexcept { return _atlas.getSet(); }
inline bool operator==(const Font& rhs) { return rhs._name == _name; }
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;
};
}
@@ -45,7 +50,9 @@ namespace std
{
std::size_t operator()(const mlx::Font& f) const noexcept
{
return std::hash<std::string>()(f.getName());
std::size_t hash = 0;
mlx::hashCombine(hash, f.getName(), f.getScale());
return hash;
}
};
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/03/08 02:24:58 by maldavid #+# #+# */
/* Updated: 2023/12/08 19:10:09 by kbz_8 ### ########.fr */
/* Updated: 2023/12/14 16:28:07 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -76,16 +76,4 @@ namespace mlx
};
}
namespace std
{
template <>
struct hash<mlx::TextureRenderData>
{
size_t operator()(const mlx::TextureRenderData& td) const noexcept
{
return std::hash<mlx::Texture*>()(td.texture) + std::hash<int>()(td.x) + std::hash<int>()(td.y);
}
};
}
#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/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; }

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/06 16:41:13 by maldavid #+# #+# */
/* Updated: 2023/12/14 00:06:29 by maldavid ### ########.fr */
/* Updated: 2023/12/14 17:49:37 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -83,7 +83,10 @@ namespace mlx
void TextPutPipeline::loadFont(const std::filesystem::path& filepath, float scale)
{
_font_in_use = &const_cast<Font&>(*_font_set.emplace(*_renderer, filepath, scale).first);
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)
@@ -91,16 +94,28 @@ namespace mlx
auto res = _drawlist.emplace(std::move(str), color, x, y);
if(res.second)
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());
}
}

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/13 00:24:21 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
{
@@ -35,6 +36,7 @@ namespace mlx
TextDrawData(std::string text, int _color, int _x, int _y);
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,9 +63,9 @@ namespace mlx
void init(Renderer* renderer) noexcept;
void put(int x, int y, int color, std::string str);
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;