Browse Source

Wrap the library into a single header + CPP file pair

Chlumsky 2 years ago
parent
commit
22b4fbb6c8
5 changed files with 261 additions and 0 deletions
  1. 3 0
      all-in-one/.gitignore
  2. 63 0
      all-in-one/CMakeLists.txt
  3. 135 0
      all-in-one/generate.py
  4. 52 0
      all-in-one/test.cpp
  5. 8 0
      all-in-one/vcpkg.json

+ 3 - 0
all-in-one/.gitignore

@@ -0,0 +1,3 @@
+msdfgen.h
+msdfgen.cpp
+build/

+ 63 - 0
all-in-one/CMakeLists.txt

@@ -0,0 +1,63 @@
+
+cmake_minimum_required(VERSION 3.15)
+
+option(MSDFGEN_USE_VCPKG "Use vcpkg package manager to link project dependencies" ON)
+option(MSDFGEN_USE_FREETYPE "Build with the FreeType library" ON)
+
+if(MSDFGEN_USE_VCPKG AND MSDFGEN_USE_FREETYPE)
+    # Make sure that vcpkg toolchain file is set
+    if(NOT CMAKE_TOOLCHAIN_FILE)
+        if(DEFINED ENV{VCPKG_ROOT})
+            set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
+        else()
+            message(SEND_ERROR "Vcpkg toolchain not configured. Either set VCPKG_ROOT environment variable or pass -DCMAKE_TOOLCHAIN_FILE=VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake to cmake")
+        endif()
+    endif()
+    # Default to statically linked vcpkg triplet on Windows
+    if(WIN32 AND NOT VCPKG_TARGET_TRIPLET AND NOT MSDFGEN_DYNAMIC_RUNTIME)
+        if(CMAKE_GENERATOR_PLATFORM MATCHES "64$" AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
+            set(VCPKG_TARGET_TRIPLET "x64-windows-static")
+        elseif(CMAKE_GENERATOR_PLATFORM MATCHES "32$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x86")
+            set(VCPKG_TARGET_TRIPLET "x86-windows-static")
+        else()
+            if(CMAKE_GENERATOR_PLATFORM)
+                message(WARNING "Vcpkg triplet not explicitly specified and could not be deduced. Recommend using -DVCPKG_TARGET_TRIPLET=x64-windows-static or similar")
+            else()
+                message(WARNING "Vcpkg triplet not explicitly specified and could not be deduced. Recommend using -A to explicitly select platform (Win32 or x64)")
+            endif()
+        endif()
+    endif()
+endif()
+
+project(msdfgen LANGUAGES CXX)
+
+if(MAX_WARNING_LEVEL)
+    if (MSVC)
+        add_compile_options(/W4)
+    else()
+        add_compile_options(-Wall -Wextra -Wpedantic)
+    endif()
+endif()
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+if(MSDFGEN_USE_FREETYPE AND NOT TARGET Freetype::Freetype)
+    find_package(Freetype REQUIRED)
+endif()
+
+execute_process(COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/generate.py")
+
+add_library(msdfgen "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.h" "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.cpp")
+set_property(TARGET msdfgen PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+target_compile_features(msdfgen PUBLIC cxx_std_11)
+if(MSDFGEN_USE_FREETYPE)
+    target_compile_definitions(msdfgen PUBLIC MSDFGEN_USE_FREETYPE)
+    target_link_libraries(msdfgen PRIVATE Freetype::Freetype)
+endif()
+
+add_executable(msdfgen-test "${CMAKE_CURRENT_SOURCE_DIR}/test.cpp")
+set_property(TARGET msdfgen-test PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+target_link_libraries(msdfgen-test PRIVATE msdfgen)
+set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdfgen-test)
+if(MSDFGEN_USE_FREETYPE)
+    target_link_libraries(msdfgen-test PRIVATE Freetype::Freetype)
+endif()

+ 135 - 0
all-in-one/generate.py

@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+
+import os
+import re
+
+rootDir = os.path.join(os.path.dirname(__file__), '..')
+
+sourceList = [
+    'core/arithmetics.hpp',
+    'core/equation-solver.h',
+    'core/equation-solver.cpp',
+    'core/Vector2.h',
+    'core/Vector2.cpp',
+    'core/pixel-conversion.hpp',
+    'core/BitmapRef.hpp',
+    'core/Bitmap.h',
+    'core/Bitmap.hpp',
+    'core/Projection.h',
+    'core/Projection.cpp',
+    'core/SignedDistance.h',
+    'core/SignedDistance.cpp',
+    'core/Scanline.h',
+    'core/Scanline.cpp',
+    'core/EdgeColor.h',
+    'core/edge-segments.h',
+    'core/edge-segments.cpp',
+    'core/EdgeHolder.h',
+    'core/EdgeHolder.cpp',
+    'core/Contour.h',
+    'core/Contour.cpp',
+    'core/Shape.h',
+    'core/Shape.cpp',
+    'core/bitmap-interpolation.hpp',
+    'core/edge-coloring.h',
+    'core/edge-coloring.cpp',
+    'core/edge-selectors.h',
+    'core/edge-selectors.cpp',
+    'core/contour-combiners.h',
+    'core/contour-combiners.cpp',
+    'core/ShapeDistanceFinder.h',
+    'core/ShapeDistanceFinder.hpp',
+    'core/generator-config.h',
+    'core/msdf-error-correction.h',
+    'core/msdf-error-correction.cpp',
+    'core/MSDFErrorCorrection.h',
+    'core/MSDFErrorCorrection.cpp',
+    'core/msdfgen.cpp',
+    'ext/import-font.h',
+    'ext/import-font.cpp',
+    'ext/resolve-shape-geometry.h',
+    'ext/resolve-shape-geometry.cpp',
+    'msdfgen.h'
+]
+
+header = """
+#pragma once
+
+#ifndef _USE_MATH_DEFINES
+#define _USE_MATH_DEFINES
+#endif
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <cmath>
+#include <vector>
+"""
+
+source = """
+#include "msdfgen.h"
+
+#include <algorithm>
+#include <queue>
+
+#ifdef MSDFGEN_USE_FREETYPE
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
+#include FT_MULTIPLE_MASTERS_H
+#endif
+#endif
+"""
+
+with open(os.path.join(rootDir, 'LICENSE.txt'), 'r') as file:
+    license = file.read()
+license = '\n'.join([' * '+line for line in license.strip().split('\n')])
+
+for filename in sourceList:
+    with open(os.path.join(rootDir, *filename.split('/')), 'r') as file:
+        src = file.read()
+    src = '\n'.join([line for line in src.split('\n') if not re.match(r'^\s*#(include\s.*|pragma\s+once)\s*$', line)])
+    if filename.startswith('ext/import-font.'):
+        src = '#ifdef MSDFGEN_USE_FREETYPE\n\n'+src+'\n\n#endif\n\n'
+    if filename.endswith('.h') or filename.endswith('.hpp'):
+        header += '\n\n'+src
+    if filename.endswith('.cpp'):
+        source += '\n\n'+src
+
+header = '\n'+re.sub(r'\n{3,}', '\n\n', re.sub(r'}\s*namespace\s+msdfgen\s*{', '', re.sub(r'\/\*[^\*].*?\*\/', '', header, flags=re.DOTALL))).strip()+'\n'
+source = '\n'+re.sub(r'\n{3,}', '\n\n', re.sub(r'}\s*namespace\s+msdfgen\s*{', '', re.sub(r'\/\*[^\*].*?\*\/', '', source, flags=re.DOTALL))).strip()+'\n'
+
+header = """
+/*
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
+ * ---------------------------------------------
+ * A utility by Viktor Chlumsky, (c) 2014 - 2023
+ * https://github.com/Chlumsky/msdfgen
+ * Published under the MIT license
+ *
+ * The technique used to generate multi-channel distance fields in this code
+ * was developed by Viktor Chlumsky in 2014 for his master's thesis,
+ * "Shape Decomposition for Multi-Channel Distance Fields". It provides improved
+ * quality of sharp corners in glyphs and other 2D shapes compared to monochrome
+ * distance fields. To reconstruct an image of the shape, apply the median of three
+ * operation on the triplet of sampled signed distance values.
+ *
+ */
+"""+header
+
+source = """
+/*
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
+ * ---------------------------------------------
+ * https://github.com/Chlumsky/msdfgen
+ *
+"""+license+"""
+ *
+ */
+"""+source
+
+with open(os.path.join(os.path.dirname(__file__), 'msdfgen.h'), 'w') as file:
+    file.write(header)
+with open(os.path.join(os.path.dirname(__file__), 'msdfgen.cpp'), 'w') as file:
+    file.write(source)

+ 52 - 0
all-in-one/test.cpp

@@ -0,0 +1,52 @@
+
+#include <cstdio>
+#include "msdfgen.h"
+
+using namespace msdfgen;
+
+static bool saveRGBA(const char *filename, const BitmapConstRef<float, 4> &bitmap) {
+    if (FILE *f = fopen(filename, "wb")) {
+        char header[12];
+        header[0] = 'R', header[1] = 'G', header[2] = 'B', header[3] = 'A';
+        header[4] = char(bitmap.width>>24);
+        header[5] = char(bitmap.width>>16);
+        header[6] = char(bitmap.width>>8);
+        header[7] = char(bitmap.width);
+        header[8] = char(bitmap.height>>24);
+        header[9] = char(bitmap.height>>16);
+        header[10] = char(bitmap.height>>8);
+        header[11] = char(bitmap.height);
+        fwrite(header, 1, 12, f);
+        Bitmap<byte, 4> byteBitmap(bitmap.width, bitmap.height);
+        byte *d = (byte *) byteBitmap;
+        for (const float *s = bitmap.pixels, *end = bitmap.pixels+4*bitmap.width*bitmap.height; s < end; ++d, ++s)
+            *d = pixelFloatToByte(*s);
+        fwrite((const byte *) byteBitmap, 1, 4*bitmap.width*bitmap.height, f);
+        fclose(f);
+        return true;
+    }
+    return false;
+}
+
+int main() {
+#ifdef MSDFGEN_USE_FREETYPE
+    bool success = false;
+    if (FreetypeHandle *ft = initializeFreetype()) {
+        if (FontHandle *font = loadFont(ft, "C:\\Windows\\Fonts\\arialbd.ttf")) {
+            Shape shape;
+            if (loadGlyph(shape, font, 'A')) {
+                shape.normalize();
+                edgeColoringByDistance(shape, 3.0);
+                Bitmap<float, 4> msdf(32, 32);
+                generateMTSDF(msdf, shape, 4.0, 1.0, Vector2(4.0, 4.0));
+                success = saveRGBA("output.rgba", msdf);
+            }
+            destroyFont(font);
+        }
+        deinitializeFreetype(ft);
+    }
+    return success ? 0 : 1;
+#else
+    return 0;
+#endif
+}

+ 8 - 0
all-in-one/vcpkg.json

@@ -0,0 +1,8 @@
+{
+    "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/master/docs/vcpkg.schema.json",
+    "name": "msdfgen-all-in-one",
+    "version": "1.10.0",
+    "dependencies": [
+        "freetype"
+    ]
+}