diff --git a/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h index 89379ac3..3f79547e 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h @@ -15,29 +15,25 @@ #include #include #include "msdf-atlas-gen/msdf-atlas-gen.h" +#include "math/SHMatrix.h" namespace SHADE { struct SH_API SHFontAsset : SHAssetData { + using GlyphData = std::tuple; + /*-----------------------------------------------------------------------*/ /* MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - //! Individual glyph data - std::vector glyphData; - - //! MSDF's data structure containing the raw data of the atlas - msdfgen::Bitmap fontBitmap; - - //! Used for getting data of the font - msdf_atlas::FontGeometry fontGeometry; - - //! Handle to the font loaded. We will use this when we initialize font data. - //! This is mainly the asset part of fonts. - msdfgen::FontHandle* fontHandle; - //! Name of the shader file (without parent path) - std::string fontName; + //std::string fontName; + + //! Data containing character and uv transformation data and other misc data + std::vector glyphTransformations; + + //! The actual data of the atlas to go into the binary + std::unique_ptr bitmapData; }; diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHFontCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/Compilers/SHFontCompiler.cpp new file mode 100644 index 00000000..dc9a8c97 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHFontCompiler.cpp @@ -0,0 +1,217 @@ +#include "SHpch.h" +#include "SHFontCompiler.h" +#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" +#include "Assets/Asset Types/SHFontAsset.h" +#include "Math/Vector/SHVec2.h" + +#include +#include + +namespace SHADE +{ + /***************************************************************************/ + /*! + + \brief + Given a valid ptr to a font asset and relevant data, initialize the data + inside the font asset. See SHFontAsset for details. + + \param fontAsset + The ptr to the font asset. + + \param glyphData + Individual glyph data. + + \param fontBitmap + Actual bitmap data + + \param fontGeometry + Font geometry required to get advance + + */ + /***************************************************************************/ + void SHFontCompiler::WriteToFontAsset(SHFontAsset* fontAsset, std::vector const& glyphData, msdfgen::Bitmap const& fontBitmap, msdf_atlas::FontGeometry const& fontGeometry) noexcept + { + if (!fontAsset) + return; + + uint32_t numGlyphs = static_cast(glyphData.size()); + for (uint32_t i = 0; i < numGlyphs; ++i) + { + // bounding box of the glyph in atlas + double atlasL = 0.0, atlasR = 0.0, atlasT = 0.0, atlasB = 0.0; + + // bounding box of glyph as it should be placed on the baseline + double atlasPL = 0.0, atlasPR = 0.0, atlasPT = 0.0, atlasPB = 0.0; + + // initialize the bounding boxes + glyphData[i].getQuadAtlasBounds(atlasL, atlasB, atlasR, atlasT); + glyphData[i].getQuadPlaneBounds(atlasPL, atlasPB, atlasPR, atlasPT); + + // normalize the bounding box to (0 - 1). + atlasL /= fontBitmap.width(); + atlasR /= fontBitmap.width(); + atlasT /= fontBitmap.height(); + atlasB /= fontBitmap.height(); + + // Normalized texture dimensions + SHVec2 const NORMALIZED_TEX_DIMS{ static_cast (atlasR - atlasL), static_cast (atlasT - atlasB) }; + + // When we render the quad, it has to correctly scale depending on what letter/glyph we are rendering. This is for that scale. + SHVec2 const QUAD_SCALE { static_cast (atlasPR - atlasL), static_cast (atlasT - atlasB) }; + + // initialize a matrix for uv and quad transformation data + SHMatrix transformData + { + // For scaling the tex coords + NORMALIZED_TEX_DIMS[0], 0.0f, 0.0f, 0.0f, + 0.0f, NORMALIZED_TEX_DIMS[1], 0.0f, 0.0f, + + // For translating the tex coords + static_cast(atlasL), static_cast(atlasB), 1.0f, 0.0f, + + // Stores the transformation for a quad to correctly shape the glyph (first 2 values) and the bearing (last 2) + QUAD_SCALE[0], QUAD_SCALE[1], static_cast(atlasPL), static_cast(atlasPB) + }; + + // Initialize new data (we want the matrix transposed for shader use) + SHFontAsset::GlyphData newData = std::make_tuple(glyphData[i].getCodepoint(), SHMatrix::Transpose(transformData)); + + // Push 1 set of data for a character/glyph into the asset. + fontAsset->glyphTransformations.push_back(newData); + } + + // copy data from bitmap to asset. Each channel is a 32 bit float and there are 3 channels. + fontAsset->bitmapData = std::make_unique(fontBitmap.width() * fontBitmap.height() * 3 * sizeof (float)); + } + + /***************************************************************************/ + /*! + + \brief + Loads and compiles a font to binary format. Returns a path to the binary + data (XQ please confirm kor kor thanks <3). + + \param path + Path to the font file (truetype font file) to load. + + \return + Path to newly created binary data. + + */ + /***************************************************************************/ + std::optional SHFontCompiler::LoadAndCompileFont(AssetPath path) noexcept + { + msdfgen::FontHandle* fontHandle = nullptr; + + // XQ I need your help for path manipulation to actually load the msdfgen::FontHandle here. Am I doing this correctly? + fontHandle = msdfgen::loadFont(SHFreetypeInstance::GetFreetypeHandle(), path.string().c_str()); + + // Compile a font asset + auto* fontAsset = CompileFontToMemory(fontHandle); + + // No path to binary format + if (!fontAsset) + return {}; + + CompileFontToBinary(path, *fontAsset); + + return {}; + } + + /***************************************************************************/ + /*! + + \brief + This function takes in a font handle and generates a font asset from it. + It first geneates an atlas and all relevant data before creating the + asset. + + \param fontHandle + MSDF font handle required to initialize member variables in SHFontAsset. + + \return + A pointer to a brand new font asset. + + */ + /***************************************************************************/ + SHADE::SHFontAsset const* SHFontCompiler::CompileFontToMemory(msdfgen::FontHandle* fontHandle) noexcept + { + // Individual glyph geometry + std::vector glyphData; + + // Actual bitmap data + msdfgen::Bitmap fontBitmap; + + // Font geometry required to get advance + msdf_atlas::FontGeometry fontGeometry (&glyphData); + + // Load char set + fontGeometry.loadCharset(fontHandle, 1.0, msdf_atlas::Charset::ASCII); + + // Apply MSDF edge coloring + const double maxCornerAngle = 3.0; + for (msdf_atlas::GlyphGeometry& glyph : glyphData) + glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0); + + // configure parameters for atlas generation + msdf_atlas::TightAtlasPacker atlasPacker; + atlasPacker.setDimensionsConstraint(msdf_atlas::TightAtlasPacker::DimensionsConstraint::SQUARE); + + atlasPacker.setMinimumScale(64.0); + atlasPacker.setPixelRange(2.0); + atlasPacker.setMiterLimit(1.0); + atlasPacker.pack(glyphData.data(), static_cast(glyphData.size())); + + // Get the dimensions after applying parameters + int width = 0, height = 0; + atlasPacker.getDimensions(width, height); + + // generate the atlas + msdf_atlas::ImmediateAtlasGenerator> generator(width, height); + msdf_atlas::GeneratorAttributes genAttribs; + generator.setAttributes(genAttribs); + generator.setThreadCount(4); + generator.generate(glyphData.data(), static_cast(glyphData.size())); + + fontBitmap = std::move(((msdfgen::Bitmap&&)generator.atlasStorage())); + + // at this point we have all the required data to initialize a font asset. + + // Dynamically allocate new asset + SHFontAsset* newAsset = new SHFontAsset(); + + // Now we populate it with data + WriteToFontAsset(newAsset, glyphData, fontBitmap, fontGeometry); + + return newAsset; + } + + std::string SHFontCompiler::CompileFontToBinary(AssetPath path, SHFontAsset const& asset) noexcept + { + std::string newPath{ path.string() }; + newPath = newPath.substr(0, newPath.find_last_of('.')); + newPath += SHADER_BUILT_IN_EXTENSION.data(); + + std::ofstream file{ newPath, std::ios::binary | std::ios::out | std::ios::trunc }; + + //file.write( + // reinterpret_cast(&data.shaderType), sizeof(uint8_t) + //); + + //size_t const byteCount = sizeof(uint32_t) * data.spirvBinary.size(); + + //file.write( + // reinterpret_cast(&byteCount), sizeof(size_t) + //); + + //file.write( + // reinterpret_cast(data.spirvBinary.data()), byteCount + //); + + file.close(); + + return newPath; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHFontCompiler.h b/SHADE_Engine/src/Assets/Libraries/Compilers/SHFontCompiler.h new file mode 100644 index 00000000..c5e68aa6 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHFontCompiler.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Assets/SHAssetMacros.h" +#include "msdf-atlas-gen/msdf-atlas-gen.h" + + +namespace SHADE +{ + class SHFontAsset; + + class SHFontCompiler + { + private: + static void WriteToFontAsset (SHFontAsset* fontAsset, std::vector const& glyphData, msdfgen::Bitmap const& fontBitmap, msdf_atlas::FontGeometry const& fontGeometry) noexcept; + + public: + static std::optional LoadAndCompileFont (AssetPath path) noexcept; + static SHFontAsset const* CompileFontToMemory (msdfgen::FontHandle* fontHandle) noexcept; + static std::string CompileFontToBinary (AssetPath path, SHFontAsset const& asset) noexcept; + + }; +} diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp index da2f966a..93de789b 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp @@ -7,46 +7,18 @@ namespace SHADE { SHADE::SHAssetData* SHFontLoader::Load(AssetPath path) { - //auto result = new SHFontAsset(); - - //// save the font name - //result->fontName = path.stem().stem().string(); - - //result->fontHandle = msdfgen::loadFont(SHFreetypeInstance::GetFreetypeHandle(), path.string().c_str()); - - ////result->fontGeometry = msdf_atlas::FontGeometry(&result->glyphData); - - //result->fontGeometry.loadCharset(font, 1.0f, msdf_atlas::Charset::ASCII); - - //// Apply MSDF edge coloring - //const double maxCornerAngle = 3.0; - //for (GlyphGeometry& glyph : glyphData) - // glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0); - - //TightAtlasPacker atlasPacker; - //atlasPacker.setDimensionsConstraint(TightAtlasPacker::DimensionsConstraint::SQUARE); - - //atlasPacker.setMinimumScale(64.0); - //atlasPacker.setPixelRange(2.0); - //atlasPacker.setMiterLimit(1.0); - //atlasPacker.pack(glyphData.data(), static_cast(glyphData.size())); - - - //int width = 0, height = 0; - //atlasPacker.getDimensions(width, height); - - //ImmediateAtlasGenerator> generator(width, height); - //GeneratorAttributes genAttribs; - //generator.setAttributes(genAttribs); - //generator.setThreadCount(4); - //generator.generate(glyphData.data(), static_cast(glyphData.size())); - - return nullptr; } void SHFontLoader::Write(SHAssetData const* data, AssetPath path) { + /* + Stuff to write to binary file : + - Interleaved per character data + - codepoint (actual character) + - 4x4 Matrix data (stores UV transform + extra data) + - Actual atlas texture + */ } diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h index 92c4b69e..b89fcb07 100644 --- a/SHADE_Engine/src/Assets/SHAssetMacros.h +++ b/SHADE_Engine/src/Assets/SHAssetMacros.h @@ -79,7 +79,8 @@ constexpr std::string_view META_EXTENSION {".shmeta"}; constexpr std::string_view AUDIO_EXTENSION {".ogg"}; constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"}; constexpr std::string_view SHADER_EXTENSION{ ".shshader" }; -constexpr std::string_view SHADER_BUILT_IN_EXTENSION{".shshaderb"}; +constexpr std::string_view SHADER_BUILT_IN_EXTENSION{ ".shshaderb" }; +constexpr std::string_view FONT_EXTENSION{ ".shfont" }; constexpr std::string_view SCRIPT_EXTENSION {".cs"}; constexpr std::string_view SCENE_EXTENSION {".shade"}; constexpr std::string_view PREFAB_EXTENSION {".shprefab"}; @@ -90,7 +91,8 @@ constexpr std::string_view MODEL_EXTENSION {".shmodel"}; constexpr std::string_view EXTENSIONS[] = { AUDIO_EXTENSION, SHADER_EXTENSION, - SHADER_BUILT_IN_EXTENSION, + SHADER_BUILT_IN_EXTENSION, + FONT_EXTENSION, MATERIAL_EXTENSION, TEXTURE_EXTENSION, MODEL_EXTENSION, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index c7b864d5..26befb28 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -311,6 +311,8 @@ namespace SHADE lightingSubSystem = resourceManager.Create(); lightingSubSystem->Init(device, descPool); + + SHFreetypeInstance::Init(); } void SHGraphicsSystem::InitBuiltInResources(void)