diff --git a/3rdParty/msdf/CMakeLists.txt b/3rdParty/msdf/CMakeLists.txt index 3142662..401621a 100644 --- a/3rdParty/msdf/CMakeLists.txt +++ b/3rdParty/msdf/CMakeLists.txt @@ -1,99 +1,88 @@ -if(WIN32 OR UNIX OR APPLE OR IOS) - include(FetchContent) +include(FetchContent) - if(NOT DEFINED MSDFGEN_REPO) - set(MSDFGEN_REPO https://github.com/Chlumsky/msdfgen.git) - endif () +if(NOT DEFINED MSDFGEN_REPO) + set(MSDFGEN_REPO https://github.com/Chlumsky/msdfgen.git) +endif () - if(NOT DEFINED MSDFGEN_ATRLAS_REPO) - set(MSDFGEN_ATRLAS_REPO https://github.com/Chlumsky/msdf-atlas-gen.git) - endif() - - if(NOT DEFINED VCPKG_REPO) - set(VCPKG_REPO https://github.com/microsoft/vcpkg.git) - endif() - - set(VCPKG_SRC_DIR "${CMAKE_BINARY_DIR}/_deps/vcpkg-src" CACHE INTERNAL "vcpkg source dir") - if (NOT EXISTS ${VCPKG_SRC_DIR} OR VCPKG_EXECUTABLE STREQUAL "" OR NOT DEFINED VCPKG_EXECUTABLE) - message("Cloning vcpkg...") - FetchContent_Declare( - vcpkg - EXCLUDE_FROM_ALL - GIT_REPOSITORY ${VCPKG_REPO} - GIT_TAG master - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(vcpkg) - if (WIN32) - execute_process(COMMAND "${VCPKG_SRC_DIR}/bootstrap-vcpkg.bat") - set(VCPKG_EXECUTABLE "${VCPKG_SRC_DIR}/vcpkg.exe" CACHE INTERNAL "vcpkg executable") - else() - execute_process(COMMAND bash "${VCPKG_SRC_DIR}/bootstrap-vcpkg.sh") - set(VCPKG_EXECUTABLE "${VCPKG_SRC_DIR}/vcpkg" CACHE INTERNAL "vcpkg executable") - endif() - endif() - - if (WIN32) - set(TRIPLET x64-windows-static-md-release CACHE INTERNAL "triplet") - elseif(UNIX AND NOT APPLE) - set(TRIPLET x64-linux CACHE INTERNAL "triplet") - elseif(APPLE AND NOT IOS) - set(TRIPLET arm64-osx CACHE INTERNAL "triplet") - elseif(IOS) - set(TRIPLET arm64-ios CACHE INTERNAL "triplet") - endif() - - execute_process(COMMAND ${VCPKG_EXECUTABLE} install freetype:${TRIPLET} libpng:${TRIPLET}) - set(CMAKE_TOOLCHAIN_FILE "${CMAKE_BINARY_DIR}/_deps/vcpkg-src/scripts/buildsystems/vcpkg.cmake" CACHE STRING "cmake toolchain") - include("${VCPKG_SRC_DIR}/scripts/buildsystems/vcpkg.cmake") - list(APPEND CMAKE_PREFIX_PATH "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib") - list(APPEND CMAKE_PREFIX_PATH "${VCPKG_SRC_DIR}/installed/${TRIPLET}/include") - - set(MSDFGEN_DISABLE_SVG TRUE CACHE INTERNAL "disable msdfgen svg") - set(MSDFGEN_USE_SKIA OFF CACHE BOOL "use skia" FORCE) - set(MSDF_ATLAS_USE_SKIA OFF CACHE BOOL "use skia" FORCE) - set(MSDF_ATLAS_MSDFGEN_EXTERNAL ON CACHE BOOL "do not build msdfgen submodule" FORCE) - set(MSDFGEN_DYNAMIC_RUNTIME ON CACHE BOOL "msvc dynamic runtime" FORCE) - set(MSDF_ATLAS_DYNAMIC_RUNTIME ON CACHE BOOL "msvc dynamic runtime" FORCE) - - FetchContent_Declare( - msdfgen - EXCLUDE_FROM_ALL - GIT_REPOSITORY ${MSDFGEN_REPO} - GIT_TAG v1.12 - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(msdfgen) - - FetchContent_Declare( - msdfgen_atlas - EXCLUDE_FROM_ALL - GIT_REPOSITORY ${MSDFGEN_ATRLAS_REPO} - GIT_TAG master - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(msdfgen_atlas) +if(NOT DEFINED MSDFGEN_ATRLAS_REPO) + set(MSDFGEN_ATRLAS_REPO https://github.com/Chlumsky/msdf-atlas-gen.git) endif() +if(NOT DEFINED FREETYPE_REPO) + set(FREETYPE_REPO https://github.com/freetype/freetype.git) +endif() + +unset(Freetype_FOUND) +find_package(Freetype QUIET) +if (NOT Freetype_FOUND OR NOT EXISTS "${CMAKE_BINARY_DIR}/_deps/freetype-src/build") + message("Installing freetype from sources") + FetchContent_Declare( + freetype + EXCLUDE_FROM_ALL + GIT_REPOSITORY ${FREETYPE_REPO} + GIT_TAG master + GIT_SHALLOW TRUE + ) + set(FT_DISABLE_ZLIB ON CACHE BOOL "" FORCE) + set(FT_DISABLE_BZIP2 ON CACHE BOOL "" FORCE) + set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE) + set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE) + set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(freetype) + + set(FT_SRC_DIR "${CMAKE_BINARY_DIR}/_deps/freetype-src") + set(FT_BUILD_DIR "${FT_SRC_DIR}/build") + file(MAKE_DIRECTORY ${FT_BUILD_DIR}) + execute_process( + COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} -DTOOLCHAIN_FILE=${TOOLCHAIN_FILE} -S ${FT_SRC_DIR} -B ${FT_BUILD_DIR} + -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${FT_SRC_DIR}/freetype-install + WORKING_DIRECTORY ${FT_BUILD_DIR} + ) + execute_process( + COMMAND ${CMAKE_COMMAND} --build ${FT_BUILD_DIR} --config Release --target install + WORKING_DIRECTORY ${FT_BUILD_DIR} RESULT_VARIABLE build_result + ) + if (NOT ${build_result} EQUAL "0") + message(FATAL_ERROR "Failed to build freetype!") + endif() + set(FREETYPE_INCLUDE_DIR "${FT_SRC_DIR}/freetype-install/include/freetype2" CACHE INTERNAL "ft include dir") + set(FREETYPE_BUILT_FROM_SOURCES ON CACHE BOOL "ft built from sources") + list(APPEND CMAKE_PREFIX_PATH "${FT_SRC_DIR}/freetype-install") +endif() + +set(MSDFGEN_DISABLE_SVG TRUE CACHE INTERNAL "disable msdfgen svg") +set(MSDFGEN_USE_SKIA OFF CACHE BOOL "use skia" FORCE) +set(MSDF_ATLAS_USE_SKIA OFF CACHE BOOL "use skia" FORCE) +set(MSDF_ATLAS_MSDFGEN_EXTERNAL ON CACHE BOOL "do not build msdfgen submodule" FORCE) +set(MSDFGEN_DYNAMIC_RUNTIME ON CACHE BOOL "msvc dynamic runtime" FORCE) +set(MSDF_ATLAS_DYNAMIC_RUNTIME ON CACHE BOOL "msvc dynamic runtime" FORCE) +set(MSDFGEN_DISABLE_PNG ON CACHE BOOL "disable png" FORCE) +set(MSDFGEN_USE_VCPKG OFF CACHE BOOL "do not use vcpkg" FORCE) +set(MSDF_ATLAS_USE_VCPKG OFF CACHE BOOL "do not use vcpkg" FORCE) + +FetchContent_Declare( + msdfgen + EXCLUDE_FROM_ALL + GIT_REPOSITORY ${MSDFGEN_REPO} + GIT_TAG v1.12 + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(msdfgen) + +FetchContent_Declare( + msdfgen_atlas + EXCLUDE_FROM_ALL + GIT_REPOSITORY ${MSDFGEN_ATRLAS_REPO} + GIT_TAG master + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(msdfgen_atlas) + function(LinkMsdf TARGET) - if (WIN32 OR UNIX OR APPLE OR IOS) - target_link_libraries(${TARGET} PRIVATE msdfgen::msdfgen msdfgen::msdfgen-ext msdf-atlas-gen) - if(WIN32) - set(STATIC_LIB_EXT "lib") - set(freetype_lib_name "freetype") - else() - set(STATIC_LIB_EXT "a") - set(freetype_lib_name "libfreetype") - endif() - target_include_directories(${TARGET} PUBLIC "${VCPKG_SRC_DIR}/installed/${TRIPLET}/include") - # link freetype first to fix linkage issues on linux - target_link_libraries(${TARGET} PUBLIC "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib/${freetype_lib_name}.${STATIC_LIB_EXT}") - file(GLOB installed_libs "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib/*.${STATIC_LIB_EXT}") - foreach(lib ${installed_libs}) - get_filename_component(libname ${lib} NAME_WE) - if (NOT ${libname} STREQUAL ${freetype_lib_name}) - target_link_libraries(${TARGET} PUBLIC ${lib}) - endif() - endforeach() + target_link_libraries(${TARGET} PRIVATE msdfgen::msdfgen msdfgen::msdfgen-ext msdf-atlas-gen) + if (FREETYPE_BUILT_FROM_SOURCES) + target_include_directories(${TARGET} PUBLIC ${FREETYPE_INCLUDE_DIR}) + else() + target_include_directories(${TARGET} PUBLIC ${FREETYPE_INCLUDE_DIRS}) endif() endfunction() diff --git a/examples/ExampleApps/TextExampleApp.cpp b/examples/ExampleApps/TextExampleApp.cpp index f30e1c5..4dd619b 100644 --- a/examples/ExampleApps/TextExampleApp.cpp +++ b/examples/ExampleApps/TextExampleApp.cpp @@ -75,7 +75,6 @@ namespace OpenVulkano // charset.add(c); //} m_atlasGenerator.GenerateAtlas(fontPath, charset); - m_atlasGenerator.SaveAtlasMetadataInfo("atlas_metadata", true); #endif for (int i = 0; i < texts.size(); i++) diff --git a/openVulkanoCpp/Scene/FontAtlasGenerator.cpp b/openVulkanoCpp/Scene/FontAtlasGenerator.cpp index a5ae4c6..c86884e 100644 --- a/openVulkanoCpp/Scene/FontAtlasGenerator.cpp +++ b/openVulkanoCpp/Scene/FontAtlasGenerator.cpp @@ -4,12 +4,18 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if __has_include("msdfgen.h") + #include "FontAtlasGenerator.hpp" #include "Base/Logger.hpp" #include "Scene/AtlasMetadata.hpp" +#define STBI_MSC_SECURE_CRT +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" #include #include FT_FREETYPE_H #include +#include namespace OpenVulkano::Scene { @@ -91,20 +97,20 @@ namespace OpenVulkano::Scene return; } std::string fileName = outputFile; - uint32_t packedFlag = 0; + uint32_t packedFlag = packIntoSingleFile; if (packIntoSingleFile) { size_t ext = outputFile.find_last_of('.'); - if (ext == std::string::npos) + if (ext == std::string::npos) { fileName += "_packed"; } - else + else { fileName.insert(ext - 1, "_packed"); } - savePng(m_generator.atlasStorage(), fileName.c_str()); - packedFlag = 1; + const BitmapConstRef& storage = m_generator.atlasStorage(); + SavePng(m_generator.atlasStorage(), fileName, 1); } std::fstream fs(fileName.c_str(), std::ios_base::out | std::ios_base::binary | (packedFlag ? std::ios_base::app : std::ios_base::trunc)); fs.write(reinterpret_cast(&m_meta), sizeof(AtlasMetadata)); @@ -207,10 +213,26 @@ namespace OpenVulkano::Scene } if (pngOutput && !pngOutput->empty()) - { - savePng(m_generator.atlasStorage(), pngOutput->c_str()); + { + SavePng(storage, pngOutput.value(), 1); } destroyFont(font); deinitializeFreetype(ft); } + + void FontAtlasGenerator::SavePng(const BitmapConstRef& storage, const std::string& output, int channels) const + { + stbi_flip_vertically_on_write(1); + if (std::filesystem::path(output).extension() == ".png") + { + stbi_write_png(output.c_str(), storage.width, storage.height, channels, storage.pixels, + channels * storage.width); + } + else + { + stbi_write_png((output + ".png").c_str(), storage.width, storage.height, channels, storage.pixels, + channels * storage.width); + } + } } +#endif \ No newline at end of file diff --git a/openVulkanoCpp/Scene/FontAtlasGenerator.hpp b/openVulkanoCpp/Scene/FontAtlasGenerator.hpp index 064f20e..c4ebf6d 100644 --- a/openVulkanoCpp/Scene/FontAtlasGenerator.hpp +++ b/openVulkanoCpp/Scene/FontAtlasGenerator.hpp @@ -6,6 +6,8 @@ #pragma once +#if __has_include("msdfgen.h") + #include #include #include @@ -25,6 +27,7 @@ namespace OpenVulkano::Scene class FontAtlasGenerator { public: + using SdfGenerator = ImmediateAtlasGenerator>; static Charset LoadAllGlyphs(const std::variant>& data); void GenerateAtlas(const std::string& fontFile, const Charset& charset = Charset::ASCII, const std::optional& pngOutput = std::nullopt); @@ -34,13 +37,16 @@ namespace OpenVulkano::Scene const Texture& GetAtlas() const { return m_atlasTex; } std::map& GetGlyphsInfo() { return m_symbols; } AtlasMetadata& GetAtlasMetadata() { return m_meta; } + SdfGenerator& GetFontAtlsGenerator() { return m_generator; } private: void Generate(FreetypeHandle* ft, FontHandle* font, const Charset& chset, const std::optional& pngOutput); + void SavePng(const BitmapConstRef& storage, const std::string& output, int channels) const; private: - ImmediateAtlasGenerator> m_generator; + SdfGenerator m_generator; Texture m_atlasTex; AtlasMetadata m_meta; std::map m_symbols; }; } +#endif