diff --git a/CMakeLists.txt b/CMakeLists.txt index c13b0c5..ee8e0e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ find_package(glm CONFIG REQUIRED) find_package(Ktx CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) find_package(fmt CONFIG REQUIRED) +find_package(unofficial-lunasvg CONFIG REQUIRED) find_package(VulkanMemoryAllocator CONFIG REQUIRED) if(UNIX) @@ -75,7 +76,9 @@ target_link_libraries(Engine PUBLIC KTX::ktx) target_link_libraries(Engine PUBLIC nlohmann_json::nlohmann_json) target_link_libraries(Engine PUBLIC crcpp) target_link_libraries(Engine PUBLIC fmt::fmt) +target_link_libraries(Engine PUBLIC unofficial::lunasvg::lunasvg) target_link_libraries(Engine PUBLIC GPUOpen::VulkanMemoryAllocator) + target_link_libraries(Engine PUBLIC slang) if(APPLE) target_link_libraries(Engine PUBLIC metal) diff --git a/Seele.natvis b/Seele.natvis index 53362e3..afc3c51 100644 --- a/Seele.natvis +++ b/Seele.natvis @@ -60,10 +60,10 @@ object - - UniquePtr {*handle} + + OwningPtr {*pointer} - handle + pointer diff --git a/src/Editor/Asset/CMakeLists.txt b/src/Editor/Asset/CMakeLists.txt index 42de029..240cb8f 100644 --- a/src/Editor/Asset/CMakeLists.txt +++ b/src/Editor/Asset/CMakeLists.txt @@ -8,5 +8,7 @@ target_sources(Editor MaterialLoader.cpp MeshLoader.h MeshLoader.cpp + SVGLoader.h + SVGLoader.cpp TextureLoader.h - TextureLoader.cpp "../../../tests/Engine/UI/Element.cpp") \ No newline at end of file + TextureLoader.cpp) \ No newline at end of file diff --git a/src/Editor/Asset/FontLoader.cpp b/src/Editor/Asset/FontLoader.cpp index dd13f04..7291c82 100644 --- a/src/Editor/Asset/FontLoader.cpp +++ b/src/Editor/Asset/FontLoader.cpp @@ -31,45 +31,13 @@ void FontLoader::importAsset(FontImportArgs args) { // in case of the space character there is no bitmap // so we create a single pixel empty texture void FontLoader::import(FontImportArgs args, PFontAsset asset) { - FT_Library ft; - FT_Error error = FT_Init_FreeType(&ft); - assert(!error); - FT_Face face; - error = FT_New_Face(ft, args.filePath.string().c_str(), 0, &face); - assert(!error); - FT_Set_Pixel_Sizes(face, 0, 48); - for (uint32 c = 0; c < 256; ++c) { - if (FT_Load_Char(face, c, FT_LOAD_RENDER | FT_LOAD_COLOR)) { - std::cout << "error loading " << (char)c << std::endl; - continue; - } - FontAsset::Glyph& glyph = asset->glyphs[c]; - glyph.size = IVector2(face->glyph->bitmap.width, face->glyph->bitmap.rows); - glyph.bearing = IVector2(face->glyph->bitmap_left, face->glyph->bitmap_top); - glyph.advance = face->glyph->advance.x; - glyph.textureData.resize(glyph.size.x * glyph.size.y); - if (glyph.textureData.size() == 0) { - glyph.size.x = 1; - glyph.size.y = 1; - glyph.textureData.add(0); - // load a single transparent pixel, so that we dont have to handle empty textures later - } else { - std::memcpy(glyph.textureData.data(), face->glyph->bitmap.buffer, glyph.textureData.size()); - } - glyph.texture = graphics->createTexture2D(TextureCreateInfo{ - .sourceData = - { - .size = glyph.textureData.size(), - .data = glyph.textureData.data(), - }, - .format = Gfx::SE_FORMAT_R8_UNORM, - .width = glyph.size.x, - .height = glyph.size.y, - .name = "FontGlyph", - }); - } - FT_Done_Face(face); - FT_Done_FreeType(ft); + std::ifstream stream(args.filePath.c_str(), std::ios::binary | std::ios::ate); + Array ttfFile(stream.tellg()); + stream.seekg(0); + stream.read((char*)ttfFile.data(), ttfFile.size()); + asset->ttfFile = std::move(ttfFile); + asset->graphics = graphics; + asset->loadFace(); AssetRegistry::saveAsset(asset, FontAsset::IDENTIFIER, asset->getFolderPath(), asset->getName()); diff --git a/src/Editor/Asset/SVGLoader.cpp b/src/Editor/Asset/SVGLoader.cpp new file mode 100644 index 0000000..b972b9f --- /dev/null +++ b/src/Editor/Asset/SVGLoader.cpp @@ -0,0 +1,35 @@ +#include "SVGLoader.h" +#include "Asset/SVGAsset.h" +#include "Asset/AssetRegistry.h" +#include + +using namespace Seele; + +SVGLoader::SVGLoader(Gfx::PGraphics graphic) {} + +SVGLoader::~SVGLoader() {} + +void SVGLoader::importAsset(SVGImportArgs args) { + std::filesystem::path assetPath = args.filePath.filename(); + assetPath.replace_extension("asset"); + OSVGAsset asset = new SVGAsset(args.importPath, assetPath.stem().string()); + asset->setStatus(Asset::Status::Loading); + // the registry takes ownership, but we need to edit the reference + PSVGAsset ref = asset; + AssetRegistry::get().registerSVG(std::move(asset)); + import(args, ref); +} + +void SVGLoader::import(SVGImportArgs args, PSVGAsset asset) { + std::ifstream stream(args.filePath.c_str(), std::ios::binary | std::ios::ate); + Array svgFile(stream.tellg()); + stream.seekg(0); + stream.read((char*)svgFile.data(), svgFile.size()); + asset->document = lunasvg::Document::loadFromData(svgFile.data()); + asset->data = std::move(svgFile); + asset->graphics = graphics; + + AssetRegistry::saveAsset(asset, SVGAsset::IDENTIFIER, asset->getFolderPath(), asset->getName()); + + asset->setStatus(Asset::Status::Ready); +} diff --git a/src/Editor/Asset/SVGLoader.h b/src/Editor/Asset/SVGLoader.h new file mode 100644 index 0000000..2e62445 --- /dev/null +++ b/src/Editor/Asset/SVGLoader.h @@ -0,0 +1,24 @@ +#pragma once +#include "Containers/List.h" +#include "MinimalEngine.h" +#include + +namespace Seele { +DECLARE_REF(SVGAsset) +DECLARE_NAME_REF(Gfx, Graphics) +struct SVGImportArgs { + std::filesystem::path filePath; + std::string importPath; +}; +class SVGLoader { + public: + SVGLoader(Gfx::PGraphics graphic); + ~SVGLoader(); + void importAsset(SVGImportArgs args); + + private: + void import(SVGImportArgs args, PSVGAsset asset); + Gfx::PGraphics graphics; +}; +DECLARE_REF(SVGLoader) +} // namespace Seele \ No newline at end of file diff --git a/src/Editor/Window/InspectorView.cpp b/src/Editor/Window/InspectorView.cpp index e17c35f..06b22a9 100644 --- a/src/Editor/Window/InspectorView.cpp +++ b/src/Editor/Window/InspectorView.cpp @@ -11,8 +11,14 @@ using namespace Seele::Editor; InspectorView::InspectorView(Gfx::PGraphics graphics, PWindow window, const ViewportCreateInfo& createInfo) : View(graphics, window, createInfo, "InspectorView"), - uiSystem(new UI::System(new UI::Div( - UI::Attributes{}, {new UI::Div({}, {new UI::Text("OtherTest")}), new UI::Text("Test")}))) { + uiSystem(new UI::System( + new UI::Div(UI::Attributes{}, { + new UI::Div({}, + { + new UI::Text("OtherTestT"), + }), + new UI::Text("Test"), + }))) { renderGraph.addPass(new UIPass(graphics, uiSystem)); renderGraph.setViewport(viewport); renderGraph.createRenderPass(); diff --git a/src/Editor/main.cpp b/src/Editor/main.cpp index 04b0ecc..69e18b8 100644 --- a/src/Editor/main.cpp +++ b/src/Editor/main.cpp @@ -87,6 +87,9 @@ int main() { AssetImporter::importFont(FontImportArgs{ .filePath = "./fonts/arial.ttf", }); + AssetImporter::importFont(FontImportArgs{ + .filePath = "C:\\Windows\\Fonts\\Calibri.ttf", + }); AssetImporter::importMesh(MeshImportArgs{ .filePath = sourcePath / "import/models/cube.fbx", }); diff --git a/src/Engine/Asset/AssetRegistry.cpp b/src/Engine/Asset/AssetRegistry.cpp index 0aa02bf..2b563b4 100644 --- a/src/Engine/Asset/AssetRegistry.cpp +++ b/src/Engine/Asset/AssetRegistry.cpp @@ -5,6 +5,7 @@ #include "MaterialAsset.h" #include "MaterialInstanceAsset.h" #include "MeshAsset.h" +#include "SVGAsset.h" #include "TextureAsset.h" #include "Window/WindowManager.h" #include @@ -46,6 +47,15 @@ PFontAsset AssetRegistry::findFont(std::string_view folderPath, std::string_view return folder->fonts.at(std::string(filePath)); } +PSVGAsset AssetRegistry::findSVG(std::string_view folderPath, std::string_view filePath) { + std::unique_lock l(get().assetLock); + AssetFolder* folder = get().assetRoot; + if (!folderPath.empty()) { + folder = get().getOrCreateFolder(folderPath); + } + return folder->svgs.at(std::string(filePath)); +} + PMaterialAsset AssetRegistry::findMaterial(std::string_view folderPath, std::string_view filePath) { std::unique_lock l(get().assetLock); AssetFolder* folder = get().assetRoot; @@ -79,6 +89,11 @@ void AssetRegistry::registerFont(OFontAsset font) { get().registerFontInternal(std::move(font)); } +void AssetRegistry::registerSVG(OSVGAsset svg) { + std::unique_lock l(get().assetLock); + get().registerSVGInternal(std::move(svg)); +} + void AssetRegistry::registerMaterial(OMaterialAsset material) { std::unique_lock l(get().assetLock); get().registerMaterialInternal(std::move(material)); @@ -128,6 +143,9 @@ void AssetRegistry::loadAsset(ArchiveBuffer& buffer) { case FontAsset::IDENTIFIER: asset = PFontAsset(folder->fonts.at(name)); break; + case SVGAsset::IDENTIFIER: + asset = PSVGAsset(folder->svgs.at(name)); + break; default: throw new std::logic_error("Unknown Identifier"); } @@ -273,6 +291,10 @@ Pair AssetRegistry::peekAsset(ArchiveBuffer& buffer) { folder->fonts[name] = new FontAsset(folderPath, name); asset = PFontAsset(folder->fonts[name]); break; + case SVGAsset::IDENTIFIER: + folder->svgs[name] = new SVGAsset(folderPath, name); + asset = PSVGAsset(folder->svgs[name]); + break; default: throw new std::logic_error("Unknown Identifier"); } @@ -299,6 +321,9 @@ void AssetRegistry::saveFolder(const std::filesystem::path& folderPath, AssetFol for (const auto& [name, font] : folder->fonts) { saveAsset(PFontAsset(font), FontAsset::IDENTIFIER, folderPath, name); } + for (const auto& [name, svg] : folder->svgs) { + saveAsset(PSVGAsset(svg), SVGAsset::IDENTIFIER, folderPath, name); + } for (auto& [name, child] : folder->children) { saveFolder(folderPath / name, child); } @@ -321,6 +346,11 @@ void AssetRegistry::registerFontInternal(OFontAsset font) { folder->fonts[font->getName()] = std::move(font); } +void AssetRegistry::registerSVGInternal(OSVGAsset svg) { + AssetFolder* folder = getOrCreateFolder(svg->getFolderPath()); + folder->svgs[svg->getName()] = std::move(svg); +} + void AssetRegistry::registerMaterialInternal(OMaterialAsset material) { AssetFolder* folder = getOrCreateFolder(material->getFolderPath()); folder->materials[material->getName()] = std::move(material); diff --git a/src/Engine/Asset/AssetRegistry.h b/src/Engine/Asset/AssetRegistry.h index c6bea59..e9a1424 100644 --- a/src/Engine/Asset/AssetRegistry.h +++ b/src/Engine/Asset/AssetRegistry.h @@ -10,6 +10,7 @@ namespace Seele { DECLARE_REF(TextureAsset) DECLARE_REF(FontAsset) +DECLARE_REF(SVGAsset) DECLARE_REF(MeshAsset) DECLARE_REF(MaterialAsset) DECLARE_REF(MaterialInstanceAsset) @@ -24,12 +25,14 @@ class AssetRegistry { static PMeshAsset findMesh(std::string_view folderPath, std::string_view filePath); static PTextureAsset findTexture(std::string_view folderPath, std::string_view filePath); static PFontAsset findFont(std::string_view folderPath, std::string_view name); + static PSVGAsset findSVG(std::string_view folderPath, std::string_view name); static PMaterialAsset findMaterial(std::string_view folderPath, std::string_view filePath); static PMaterialInstanceAsset findMaterialInstance(std::string_view folderPath, std::string_view filePath); static void registerMesh(OMeshAsset mesh); static void registerTexture(OTextureAsset texture); static void registerFont(OFontAsset font); + static void registerSVG(OSVGAsset svg); static void registerMaterial(OMaterialAsset material); static void registerMaterialInstance(OMaterialInstanceAsset instance); @@ -48,6 +51,7 @@ class AssetRegistry { Map children; Map textures; Map fonts; + Map svgs; Map meshes; Map materials; Map instances; @@ -70,6 +74,7 @@ class AssetRegistry { void registerMeshInternal(OMeshAsset mesh); void registerTextureInternal(OTextureAsset texture); void registerFontInternal(OFontAsset font); + void registerSVGInternal(OSVGAsset svg); void registerMaterialInternal(OMaterialAsset material); void registerMaterialInstanceInternal(OMaterialInstanceAsset instance); diff --git a/src/Engine/Asset/CMakeLists.txt b/src/Engine/Asset/CMakeLists.txt index b5b635a..24ecfd4 100644 --- a/src/Engine/Asset/CMakeLists.txt +++ b/src/Engine/Asset/CMakeLists.txt @@ -14,6 +14,8 @@ target_sources(Engine MaterialInstanceAsset.cpp MeshAsset.h MeshAsset.cpp + SVGAsset.h + SVGAsset.cpp TextureAsset.h TextureAsset.cpp) diff --git a/src/Engine/Asset/FontAsset.cpp b/src/Engine/Asset/FontAsset.cpp index dd72d64..0acb33d 100644 --- a/src/Engine/Asset/FontAsset.cpp +++ b/src/Engine/Asset/FontAsset.cpp @@ -6,35 +6,61 @@ using namespace Seele; FontAsset::FontAsset() {} -FontAsset::FontAsset(std::string_view folderPath, std::string_view name) : Asset(folderPath, name) {} - -FontAsset::~FontAsset() {} - -void FontAsset::save(ArchiveBuffer& buffer) const { Serialization::save(buffer, glyphs); } - -void FontAsset::load(ArchiveBuffer& buffer) { Serialization::load(buffer, glyphs); } - -void FontAsset::Glyph::save(ArchiveBuffer& buffer) const { - Serialization::save(buffer, size); - Serialization::save(buffer, bearing); - Serialization::save(buffer, advance); - Serialization::save(buffer, textureData); +FontAsset::FontAsset(std::string_view folderPath, std::string_view name) : Asset(folderPath, name) { + FT_Error error = FT_Init_FreeType(&ft); + assert(!error); } -void FontAsset::Glyph::load(ArchiveBuffer& buffer) { - Serialization::load(buffer, size); - Serialization::load(buffer, bearing); - Serialization::load(buffer, advance); - Serialization::load(buffer, textureData); - texture = buffer.getGraphics()->createTexture2D(TextureCreateInfo{ - .sourceData = - { - .size = textureData.size(), - .data = textureData.data(), - }, - .format = Gfx::SE_FORMAT_R8_UNORM, - .width = size.x, - .height = size.y, - .name = "FontGlyph", - }); +FontAsset::~FontAsset() { + FT_Done_Face(face); + FT_Done_FreeType(ft); } + +void FontAsset::save(ArchiveBuffer& buffer) const { Serialization::save(buffer, ttfFile); } + +void FontAsset::load(ArchiveBuffer& buffer) { + Serialization::load(buffer, ttfFile); + graphics = buffer.getGraphics(); + loadFace(); +} + +void FontAsset::loadFace() { + FT_Error error = FT_New_Memory_Face(ft, ttfFile.data(), ttfFile.size(), 0, &face); + assert(!error); +} + +void FontAsset::loadFontSize(uint32 fontSize) { + FT_Set_Pixel_Sizes(face, 0, fontSize); + fontSizes[fontSize].ascent = face->ascender; + fontSizes[fontSize].descent = face->descender; + fontSizes[fontSize].linegap = 0; + for (uint32 c = 0; c < 256; ++c) { + if (FT_Load_Char(face, c, FT_LOAD_RENDER | FT_LOAD_COLOR)) { + continue; + } + FontAsset::Glyph& glyph = fontSizes[fontSize].glyphs[c]; + glyph.size = IVector2(face->glyph->bitmap.width, face->glyph->bitmap.rows); + glyph.bearing = IVector2(face->glyph->bitmap_left, face->glyph->bitmap_top); + glyph.advance = face->glyph->advance.x; + glyph.textureData.resize(glyph.size.x * glyph.size.y); + if (glyph.textureData.size() == 0) { + glyph.size.x = 1; + glyph.size.y = 1; + glyph.textureData.add(0); + // load a single transparent pixel, so that we dont have to handle empty textures later + } else { + std::memcpy(glyph.textureData.data(), face->glyph->bitmap.buffer, glyph.textureData.size()); + } + glyph.texture = graphics->createTexture2D(TextureCreateInfo{ + .sourceData = + { + .size = glyph.textureData.size(), + .data = glyph.textureData.data(), + }, + .format = Gfx::SE_FORMAT_R8_UNORM, + .width = glyph.size.x, + .height = glyph.size.y, + .name = "FontGlyph", + }); + } +} \ No newline at end of file diff --git a/src/Engine/Asset/FontAsset.h b/src/Engine/Asset/FontAsset.h index 19888cc..13ac6aa 100644 --- a/src/Engine/Asset/FontAsset.h +++ b/src/Engine/Asset/FontAsset.h @@ -1,11 +1,11 @@ #pragma once #include "Asset.h" #include "Containers/Map.h" +#include "Graphics/Texture.h" #include "Math/Math.h" #include namespace Seele { -DECLARE_NAME_REF(Gfx, Texture2D) class FontAsset : public Asset { public: static constexpr uint64 IDENTIFIER = 0x10; @@ -24,10 +24,27 @@ class FontAsset : public Asset { void save(ArchiveBuffer& buffer) const; void load(ArchiveBuffer& buffer); }; - const Glyph& getGlyphData(char c) const { return glyphs[c]; } + struct FontData { + int32 ascent; + int32 descent; + int32 linegap; + Map glyphs; + }; + const Glyph& getGlyphData(char c, uint32 fontSize) { + if (!fontSizes.contains(fontSize)) + loadFontSize(fontSize); + return fontSizes[fontSize].glyphs[c]; + } + const FontData& getFontData(uint32 fontSize) { return fontSizes[fontSize]; } + void loadFace(); private: - Map glyphs; + void loadFontSize(uint32 fontSize); + Gfx::PGraphics graphics; + FT_Library ft; + FT_Face face; + Array ttfFile; + Map fontSizes; friend class FontLoader; }; DECLARE_REF(FontAsset) diff --git a/src/Engine/Asset/SVGAsset.cpp b/src/Engine/Asset/SVGAsset.cpp new file mode 100644 index 0000000..d4d3473 --- /dev/null +++ b/src/Engine/Asset/SVGAsset.cpp @@ -0,0 +1,35 @@ +#include "SVGAsset.h" +#include "Graphics/Graphics.h" + +using namespace Seele; + +SVGAsset::SVGAsset() {} + +SVGAsset::SVGAsset(std::string_view folderPath, std::string_view name) : Asset(folderPath, name) {} + +SVGAsset::~SVGAsset() {} + +void SVGAsset::save(ArchiveBuffer& buffer) const { Serialization::save(buffer, data); } + +void SVGAsset::load(ArchiveBuffer& buffer) { + Serialization::load(buffer, data); + document = lunasvg::Document::loadFromData(data.data()); +} + +Gfx::PTexture2D SVGAsset::getTexture(UVector2 dimensions) { + auto viewbox = ViewBox{ + .width = dimensions.x, + .height = dimensions.y, + }; + if (!cachedTextures.contains(viewbox)) { + auto bitmap = document->renderToBitmap(viewbox.width, viewbox.height); + bitmap.convertToRGBA(); + cachedTextures[viewbox] = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, + .width = viewbox.width, + .height = viewbox.height, + .name = "SVGTexture", + }); + } + return cachedTextures[viewbox]; +} diff --git a/src/Engine/Asset/SVGAsset.h b/src/Engine/Asset/SVGAsset.h new file mode 100644 index 0000000..7866c8c --- /dev/null +++ b/src/Engine/Asset/SVGAsset.h @@ -0,0 +1,34 @@ +#pragma once +#include "Asset.h" +#include "Containers/Map.h" +#include "Graphics/Texture.h" +#include "Math/Math.h" +#include + +namespace Seele { +class SVGAsset : public Asset { + public: + static constexpr uint64 IDENTIFIER = 0x20; + SVGAsset(); + SVGAsset(std::string_view folderPath, std::string_view name); + virtual ~SVGAsset(); + virtual void save(ArchiveBuffer& buffer) const override; + virtual void load(ArchiveBuffer& buffer) override; + + Gfx::PTexture2D getTexture(UVector2 viewbox); + + private: + // workaround to make vector a map key, could be solved by either implementing + // comparison operators for vectors, or implementing a hash map + struct ViewBox { + uint32 width; + uint32 height; + constexpr std::strong_ordering operator<=>(const ViewBox& other) const = default; + }; + Array data; + Gfx::PGraphics graphics; + std::unique_ptr document; + Map cachedTextures; + friend class SVGLoader; +}; +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/UIPass.cpp b/src/Engine/Graphics/RenderPass/UIPass.cpp index bde1100..b97d99c 100644 --- a/src/Engine/Graphics/RenderPass/UIPass.cpp +++ b/src/Engine/Graphics/RenderPass/UIPass.cpp @@ -55,7 +55,7 @@ void UIPass::beginFrame(const Component::Camera& cam) { RenderPass::beginFrame(cam); glyphs.clear(); usedTextures.clear(); - for (const auto& render : renderElements) { + for (auto& render : renderElements) { float x = render.position.x; float y = render.position.y; if (render.text.empty()) { @@ -69,9 +69,9 @@ void UIPass::beginFrame(const Component::Camera& cam) { .z = render.level / 100.f, }); } else { - y = y + render.fontSize; + y = y + render.baseline; for (uint32 c : render.text) { - const FontAsset::Glyph& glyph = render.font->getGlyphData(c); + const FontAsset::Glyph& glyph = render.font->getGlyphData(c, render.fontSize); Vector2 bearing = Vector2(glyph.bearing); Vector2 size = Vector2(glyph.size); float xpos = x + glyph.bearing.x; @@ -160,7 +160,33 @@ void UIPass::createRenderPass() { .colorAttachments = {colorAttachment}, .depthAttachment = depthAttachment, }; - renderPass = graphics->createRenderPass(std::move(layout), {}, viewport, "TextPass"); + Array dependency = { + { + .srcSubpass = ~0U, + .dstSubpass = 0, + .srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + }, + { + .srcSubpass = 0, + .dstSubpass = ~0U, + .srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + }, + }; + renderPass = graphics->createRenderPass(std::move(layout), dependency, viewport, "TextPass"); graphics->beginShaderCompilation(ShaderCompilationInfo{ .name = "TextVertex", diff --git a/src/Engine/Math/Vector.h b/src/Engine/Math/Vector.h index 043aa66..4ad6cf8 100644 --- a/src/Engine/Math/Vector.h +++ b/src/Engine/Math/Vector.h @@ -45,4 +45,4 @@ void from_json(nlohmann::json& j, Vector& vec); std::ostream& operator<<(std::ostream& stream, const Seele::Vector2& vector); std::ostream& operator<<(std::ostream& stream, const Seele::Vector& vector); std::ostream& operator<<(std::ostream& stream, const Seele::Vector4& vector); -std::ostream& operator<<(std::ostream& stream, const Seele::Quaternion& vector); +std::ostream& operator<<(std::ostream& stream, const Seele::Quaternion& vector); \ No newline at end of file diff --git a/src/Engine/UI/Element.h b/src/Engine/UI/Element.h index 3f8a850..ef12cad 100644 --- a/src/Engine/UI/Element.h +++ b/src/Engine/UI/Element.h @@ -14,6 +14,7 @@ struct UIRender { Vector backgroundColor; Vector2 position; Vector2 dimensions; + uint32 baseline; uint32 z; uint32 level; }; @@ -45,14 +46,14 @@ class Element { dimensions.x = parentSize.x * style.width / 100.0f; } + for (auto& child : children) { + child->layout(maxDimensions - Vector2(style.marginLeft + style.marginRight, style.marginTop + style.marginBottom)); + } if (style.heightType == DimensionType::Pixel) { dimensions.y = style.height; } else if (style.heightType == DimensionType::Percent) { dimensions.y = parentSize.y * style.height / 100.0f; } - for (auto& child : children) { - child->layout(maxDimensions); - } switch (style.innerDisplay) { case InnerDisplayType::Flow: flowLayout(); @@ -71,15 +72,15 @@ class Element { if (child->style.position == PositionType::Static || child->style.position == PositionType::Relative) { // create a new line in case the element doesnt fit on the current one anymore, // but keep in current line in case we are still at the start, as a new line wouldnt help here - if (cursor.x + child->dimensions.x > dimensions.x - child->style.left && cursor.x != 0) { + if (cursor.x + child->dimensions.x > maxDimensions.x - child->style.left && cursor.x != 0) { cursor.x = 0; cursor.y += lineHeight; + lineHeight = 0; } // todo: border child->position.x = cursor.x + child->style.marginLeft; child->position.y = cursor.y + child->style.marginTop; cursor.x = child->position.x + child->dimensions.x; - cursor.y = child->position.y + child->dimensions.y; // apply offsets after updating the cursor for relative elements if (child->style.position == PositionType::Relative) { child->position.x += child->style.left; @@ -108,7 +109,7 @@ class Element { dimensions.x = cursor.x + style.paddingRight; } if (style.heightType == DimensionType::Auto) { - dimensions.y = cursor.y + style.paddingBottom; + dimensions.y = lineHeight + cursor.y + style.paddingBottom; } } virtual Array render(Vector2 anchor, uint32 level) { diff --git a/src/Engine/UI/Element/Div.h b/src/Engine/UI/Element/Div.h index 995ab2a..986e40e 100644 --- a/src/Engine/UI/Element/Div.h +++ b/src/Engine/UI/Element/Div.h @@ -12,8 +12,6 @@ class Div : public Element { virtual void applyStyle(Style parentStyle) override { style = parentStyle; style.outerDisplay = OuterDisplayType::Block; - style.widthType = DimensionType::Percent; - style.width = 100; (classes::apply(style), ...); } private: diff --git a/src/Engine/UI/Element/Text.h b/src/Engine/UI/Element/Text.h index abefe4b..b53cb47 100644 --- a/src/Engine/UI/Element/Text.h +++ b/src/Engine/UI/Element/Text.h @@ -15,9 +15,9 @@ template class Text : public Element { virtual void layout(UVector2 parentSize) override { size_t cursor = 0; for (uint32 i = 0; i < text.size() - 1; ++i) { - dimensions.x += style.fontFamily->getGlyphData(text[i]).advance / 64.0f; + dimensions.x += style.fontFamily->getGlyphData(text[i], style.fontSize).advance / 64.0f; } - dimensions.x += style.fontFamily->getGlyphData(text[text.size() - 1]).size.x; + dimensions.x += style.fontFamily->getGlyphData(text[text.size() - 1], style.fontSize).size.x; dimensions.y = style.fontSize; } virtual Array render(Vector2 anchor, uint32 level) override { @@ -28,6 +28,7 @@ template class Text : public Element { .fontSize = style.fontSize, .position = position + anchor, .dimensions = dimensions, + .baseline = style.fontSize * 3 / 4, // TODO: improve .z = style.z, .level = level, }, diff --git a/src/Engine/UI/Style/Class.h b/src/Engine/UI/Style/Class.h index eae7198..ea1e54f 100644 --- a/src/Engine/UI/Style/Class.h +++ b/src/Engine/UI/Style/Class.h @@ -1,7 +1,7 @@ #pragma once +#include "Asset/AssetRegistry.h" #include "MinimalEngine.h" #include "Style.h" -#include "Asset/AssetRegistry.h" namespace Seele { template @@ -36,10 +36,73 @@ template struct FontClass { }; using Font_Arial = FontClass<"arial">; +using Font_Calibri = FontClass<"Calibri">; + +template struct FontSizeClass { + static void apply(UI::Style& s) { + s.fontSize = fontSize; + s.lineHeight = lineHeight; + } +}; + +using Text_XS = FontSizeClass<12, 16>; +using Text_SM = FontSizeClass<14, 20>; +using Text_Base = FontSizeClass<16, 24>; +using Text_LG = FontSizeClass<18, 28>; +using Text_XL = FontSizeClass<20, 28>; +using Text_2XL = FontSizeClass<24, 32>; +using Text_3XL = FontSizeClass<30, 36>; +using Text_4XL = FontSizeClass<36, 40>; +using Text_5XL = FontSizeClass<48, 48>; +using Text_6XL = FontSizeClass<60, 60>; +using Text_7XL = FontSizeClass<72, 72>; +using Text_8XL = FontSizeClass<96, 96>; +using Text_9XL = FontSizeClass<128, 128>; template struct BackgroundColorClass { static void apply(UI::Style& s) { s.backgroundColor = backgroundColor; } }; using BG_Red = BackgroundColorClass; + +template struct MarginClass { + static void apply(UI::Style& s) { + if (ml != -1) + s.marginLeft = ml; + if (mr != -1) + s.marginRight = mr; + if (mt != -1) + s.marginTop = mt; + if (mb != -1) + s.marginBottom = mb; + } +}; +#define DECLARE_MARGIN_CLASSES(x) \ + using M_##x = MarginClass; \ + using M_X##x = MarginClass; \ + using M_Y##x = MarginClass<-1, -1, x, x>; \ + using M_L##x = MarginClass; \ + using M_R##x = MarginClass<-1, x, -1, -1>; \ + using M_T##x = MarginClass<-1, -1, x, -1>; \ + using M_B##x = MarginClass<-1, -1, -1, x>; + +DECLARE_MARGIN_CLASSES(0) +DECLARE_MARGIN_CLASSES(1) +DECLARE_MARGIN_CLASSES(2) +DECLARE_MARGIN_CLASSES(3) +DECLARE_MARGIN_CLASSES(4) +DECLARE_MARGIN_CLASSES(5) +DECLARE_MARGIN_CLASSES(6) +DECLARE_MARGIN_CLASSES(7) +DECLARE_MARGIN_CLASSES(8) +DECLARE_MARGIN_CLASSES(9) +DECLARE_MARGIN_CLASSES(10) +DECLARE_MARGIN_CLASSES(11) +DECLARE_MARGIN_CLASSES(12) +DECLARE_MARGIN_CLASSES(14) +DECLARE_MARGIN_CLASSES(16) +DECLARE_MARGIN_CLASSES(20) +DECLARE_MARGIN_CLASSES(24) + + } // namespace Seele \ No newline at end of file diff --git a/src/Engine/UI/Style/Style.h b/src/Engine/UI/Style/Style.h index c5b5e26..62878f2 100644 --- a/src/Engine/UI/Style/Style.h +++ b/src/Engine/UI/Style/Style.h @@ -39,10 +39,10 @@ struct Style { Vector backgroundColor = Vector(1, 1, 1); OuterDisplayType outerDisplay = OuterDisplayType::Inline; InnerDisplayType innerDisplay = InnerDisplayType::Flow; - PositionType position = PositionType::Relative; + PositionType position = PositionType::Static; PFontAsset fontFamily; - uint32 lineHeight = 48; - uint32 fontSize = 48; + uint32 lineHeight = 12; + uint32 fontSize = 12; uint32 fontWeight = 0; uint32 paddingTop = 0; uint32 paddingBottom = 0; diff --git a/vcpkg.json b/vcpkg.json index 290a6b6..9fc0b26 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,16 +1,17 @@ { - "dependencies": [ - "assimp", - "entt", - "stb", - "entt", - "freetype", - "glfw3", - "glm", - "ktx", - "nlohmann-json", - "fmt", - "gtest", - "vulkan-memory-allocator" - ] + "dependencies": [ + "assimp", + "entt", + "stb", + "entt", + "freetype", + "glfw3", + "glm", + "ktx", + "nlohmann-json", + "fmt", + "gtest", + "vulkan-memory-allocator", + "lunasvg" + ] } \ No newline at end of file