diff --git a/CMakeLists.txt b/CMakeLists.txt index 44e8fe0..5a6c3bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ file(GLOB_RECURSE MSDFGEN_EXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "ext/ file(GLOB_RECURSE MSDFGEN_EXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "ext/*.cpp" "lib/*.cpp") # Core library -add_library(msdfgen-core "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.h" ${MSDFGEN_CORE_HEADERS} ${MSDFGEN_CORE_SOURCES}) +add_library(msdfgen-core "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.h" "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen_c.h" ${MSDFGEN_CORE_HEADERS} ${MSDFGEN_CORE_SOURCES}) add_library(msdfgen::msdfgen-core ALIAS msdfgen-core) set_target_properties(msdfgen-core PROPERTIES PUBLIC_HEADER "${MSDFGEN_CORE_HEADERS}") set_property(TARGET msdfgen-core PROPERTY MSVC_RUNTIME_LIBRARY "${MSDFGEN_MSVC_RUNTIME}") @@ -120,11 +120,16 @@ if(MSDFGEN_USE_OPENMP) target_link_libraries(msdfgen-core PUBLIC OpenMP::OpenMP_CXX) endif() -if(BUILD_SHARED_LIBS AND WIN32) - target_compile_definitions(msdfgen-core PRIVATE "MSDFGEN_PUBLIC=__declspec(dllexport)") - target_compile_definitions(msdfgen-core INTERFACE "MSDFGEN_PUBLIC=__declspec(dllimport)") +if(BUILD_SHARED_LIBS) + if(WIN32) + target_compile_definitions(msdfgen-core PRIVATE "MSDFGEN_PUBLIC=__declspec(dllexport)") + target_compile_definitions(msdfgen-core INTERFACE "MSDFGEN_PUBLIC=__declspec(dllimport)") + else() + target_compile_definitions(msdfgen-core PRIVATE "MSDFGEN_PUBLIC=__attribute__((visibility(\"default\")))") + target_compile_definitions(msdfgen-core INTERFACE "MSDFGEN_PUBLIC=") + endif() else() - target_compile_definitions(msdfgen-core PUBLIC MSDFGEN_PUBLIC=) + target_compile_definitions(msdfgen-core PUBLIC "MSDFGEN_PUBLIC=") endif() # Extensions library diff --git a/core/msdfgen_c.cpp b/core/msdfgen_c.cpp new file mode 100644 index 0000000..19f6d97 --- /dev/null +++ b/core/msdfgen_c.cpp @@ -0,0 +1,251 @@ +/* + * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR + * --------------------------------------------- + * A utility by Viktor Chlumsky, (c) 2014 - 2024 + * + * The technique used to generate multi-channel distance fields in this code + * has been 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. + * + */ + +#include "../msdfgen_c.h" +#include "../msdfgen.h" + +#include + +namespace { + msdf_allocator_t g_allocator = {malloc, realloc, free}; + + template + [[nodiscard]] auto _new(TArgs&&... args) noexcept -> T* { + auto* memory = static_cast(g_allocator.alloc_callback(sizeof(T))); + new(memory) T(std::forward(args)...); + return memory; + } + + auto _delete(void* memory) noexcept -> void { + g_allocator.free_callback(memory); + } +}// namespace + +extern "C" { + +// msdf_allocator + +MSDF_API void msdf_allocator_set(const msdf_allocator_t* allocator) { + g_allocator = *allocator; +} + +MSDF_API const msdf_allocator_t* msdf_allocator_get() { + return &g_allocator; +} + +// msdf_bitmap + +MSDF_API int msdf_bitmap_alloc(int type, int num_channels, int width, int height, msdf_bitmap_handle* bitmap) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_bitmap_get_type(msdf_bitmap_handle bitmap, int* type) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_bitmap_get_channel_count(msdf_bitmap_handle bitmap, int* channel_count) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_bitmap_get_width(msdf_bitmap_handle bitmap, int* width) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_bitmap_get_height(msdf_bitmap_handle bitmap, int* height) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_bitmap_get_pixels(msdf_bitmap_handle bitmap, void** pixels) { + return MSDF_SUCCESS; +} + +MSDF_API void msdf_bitmap_free(msdf_bitmap_handle bitmap) { +} + +// msdf_shape + +MSDF_API int msdf_shape_alloc(msdf_shape_handle* shape) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_get_bounds(msdf_shape_handle shape, msdf_bounds_t* bounds) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_add_contour(msdf_shape_handle shape, msdf_contour_handle* contour) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_get_contour_count(msdf_shape_handle shape, int* contour_count) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_get_contours(msdf_shape_handle shape, msdf_contour_handle* contours) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_get_edge_counts(msdf_shape_handle shape, int* edge_count) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_has_inverse_y_axis(msdf_shape_handle shape, int* inverse_y_axis) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_normalize(msdf_shape_handle shape) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_validate(msdf_shape_handle shape, int* result) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_bound(msdf_shape_handle shape, msdf_bounds_t* bounds) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_shape_bound_miters(msdf_shape_handle shape, msdf_bounds_t* bounds, double border, double miterLimit, int polarity) { + return MSDF_SUCCESS; +} + +MSDF_API void msdf_shape_free(msdf_shape_handle shape) { +} + +// msdf_contour + +MSDF_API int msdf_contour_alloc(msdf_contour_handle* contour) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_add_edge(msdf_contour_handle contour, msdf_edge_holder_handle* edge) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_get_edge(msdf_contour_handle contour, int index, msdf_edge_holder_handle* edge) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_get_edge_count(msdf_contour_handle contour, int* edge_count) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_get_edges(msdf_contour_handle contour, msdf_edge_holder_handle* edges) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_bound(msdf_contour_handle contour, msdf_bounds_t* bounds) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_bound_miters(msdf_contour_handle contour, msdf_bounds_t* bounds, double border, double miterLimit, int polarity) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_get_winding(msdf_contour_handle contour, int* winding) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_contour_reverse(msdf_contour_handle contour) { + return MSDF_SUCCESS; +} + +MSDF_API void msdf_contour_free(msdf_contour_handle contour) { +} + +// msdf_edge + +MSDF_API int msdf_edge_alloc(msdf_edge_holder_handle* edge) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_edge_add_segment(msdf_edge_holder_handle edge, msdf_segment_handle segment) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_edge_get_segment(msdf_edge_holder_handle edge, int index, msdf_segment_handle* segment) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_edge_get_segment_count(msdf_edge_holder_handle edge, int* segment_count) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_edge_get_segments(msdf_edge_holder_handle edge, msdf_segment_handle* segments) { + return MSDF_SUCCESS; +} + +MSDF_API void msdf_edge_free(msdf_edge_holder_handle edge) { +} + +// msdf_segment + +MSDF_API int msdf_segment_alloc(int type, msdf_segment_handle* segment) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_type(msdf_segment_handle segment, int* type) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_point_count(msdf_segment_handle segment, int* point_count) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_points(msdf_segment_handle segment, msdf_vector2_t const** points) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_point(msdf_segment_handle segment, int index, msdf_vector2_t* point) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_set_point(msdf_segment_handle segment, int index, const msdf_vector2_t* point) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_set_color(msdf_segment_handle segment, int color) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_color(msdf_segment_handle segment, int* color) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_direction(msdf_segment_handle segment, double param, msdf_vector2_t* direction) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_get_direction_change(msdf_segment_handle segment, double param, msdf_vector2_t* direction_change) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_point(msdf_segment_handle segment, double param, msdf_vector2_t* point) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_bound(msdf_segment_handle segment, msdf_bounds_t* bounds) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_move_start_point(msdf_segment_handle segment, const msdf_vector2_t* point) { + return MSDF_SUCCESS; +} + +MSDF_API int msdf_segment_move_end_point(msdf_segment_handle segment, const msdf_vector2_t* point) { + return MSDF_SUCCESS; +} + +MSDF_API void msdf_segment_free(msdf_segment_handle segment) { +} +} \ No newline at end of file diff --git a/msdfgen_c.h b/msdfgen_c.h new file mode 100644 index 0000000..7a7f6c8 --- /dev/null +++ b/msdfgen_c.h @@ -0,0 +1,208 @@ +#pragma once + +/* + * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR + * --------------------------------------------- + * A utility by Viktor Chlumsky, (c) 2014 - 2024 + * + * The technique used to generate multi-channel distance fields in this code + * has been 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. + */ + +#include // For size_t + +/* + * A C-API modeled closely after the msdfgen C++ API + * to allow C-programs and other language runtimes to + * use the msdfgen library. Originally written for LWJGL. + * + * @since 01/05/2024 + * @author Alexander Hinze + */ + +#define MSDF_API MSDFGEN_PUBLIC + +#define MSDF_FALSE 0 +#define MSDF_TRUE 1 + +#define MSDF_SUCCESS 0 +#define MSDF_ERR_INVALID_ARG 1 +#define MSDF_ERR_INVALID_FORMAT 2 + +#define MSDF_BITMAP_TYPE_FLOAT 0 +#define MSDF_BITMAP_TYPE_DOUBLE 1 +#define MSDF_BITMAP_TYPE_INT 2 +#define MSDF_BITMAP_TYPE_SHORT 3 + +#define MSDF_SEGMENT_TYPE_LINEAR 0 +#define MSDF_SEGMENT_TYPE_QUADRATIC 1 +#define MSDF_SEGMENT_TYPE_CUBIC 2 + +#define MSDF_EDGE_COLOR_BLACK 0 +#define MSDF_EDGE_COLOR_RED 1 +#define MSDF_EDGE_COLOR_GREEN 2 +#define MSDF_EDGE_COLOR_YELLOW 3 +#define MSDF_EDGE_COLOR_BLUE 4 +#define MSDF_EDGE_COLOR_MAGENTA 5 +#define MSDF_EDGE_COLOR_CYAN 6 +#define MSDF_EDGE_COLOR_WHITE 7 + +#define MSDF_DEFINE_HANDLE_TYPE(n) typedef struct n* n##_handle // NOLINT + +// Macros for allocating default MSDF bitmap types +#define MSDF_ALLOC_SDF_BITMAP(w, h) msdf_bitmap_alloc(MSDF_BITMAP_TYPE_FLOAT, 1, w, h) +#define MSDF_ALLOC_PSDF_BITMAP(w, h) msdf_bitmap_alloc(MSDF_BITMAP_TYPE_FLOAT, 1, w, h) +#define MSDF_ALLOC_MSDF_BITMAP(w, h) msdf_bitmap_alloc(MSDF_BITMAP_TYPE_FLOAT, 3, w, h) +#define MSDF_ALLOC_MTSDF_BITMAP(w, h) msdf_bitmap_alloc(MSDF_BITMAP_TYPE_FLOAT, 4, w, h) + +#ifdef __cplusplus +extern "C" { +#endif + +// Type definitions +typedef void* (*msdf_allocator_alloc_callback_t)(size_t size); +typedef void* (*msdf_allocator_realloc_callback_t)(void* memory, size_t size); +typedef void (*msdf_allocator_free_callback_t)(void* memory); + +typedef struct msdf_allocator { + msdf_allocator_alloc_callback_t alloc_callback; + msdf_allocator_realloc_callback_t realloc_callback; + msdf_allocator_free_callback_t free_callback; +} msdf_allocator_t; + +typedef struct msdf_vector2 { + double x; + double y; +} msdf_vector2_t; + +typedef struct msdf_bounds { + double l; + double b; + double r; + double t; +} msdf_bounds_t; + +typedef struct msdf_projection { + msdf_vector2_t scale; + msdf_vector2_t translation; +} msdf_projection_t; + +typedef struct msdf_distance_mapping { + double scale; + double translation; +} msdf_distance_mapping_t; + +typedef struct msdf_transform { + msdf_vector2_t scale; + msdf_vector2_t translation; + msdf_distance_mapping_t distance_mapping; +} msdf_transform_t; + +typedef struct msdf_config { + int overlap_support; +} msdf_config_t; + +typedef struct msdf_multichannel_config { + int overlap_support; + int mode; + int distance_check_mode; + double min_deviation_ratio; + double min_improve_ratio; + char* buffer; +} msdf_multichannel_config_t; + +// Opaque handle types +MSDF_DEFINE_HANDLE_TYPE(msdf_bitmap); +MSDF_DEFINE_HANDLE_TYPE(msdf_shape); +MSDF_DEFINE_HANDLE_TYPE(msdf_contour); +MSDF_DEFINE_HANDLE_TYPE(msdf_edge_holder); +MSDF_DEFINE_HANDLE_TYPE(msdf_segment); + +// Exported API functions +MSDF_API void msdf_allocator_set(const msdf_allocator_t* allocator); +MSDF_API const msdf_allocator_t* msdf_allocator_get(); + +MSDF_API int msdf_bitmap_alloc(int type, int num_channels, int width, int height, msdf_bitmap_handle* bitmap); +MSDF_API int msdf_bitmap_get_type(msdf_bitmap_handle bitmap, int* type); +MSDF_API int msdf_bitmap_get_channel_count(msdf_bitmap_handle bitmap, int* channel_count); +MSDF_API int msdf_bitmap_get_width(msdf_bitmap_handle bitmap, int* width); +MSDF_API int msdf_bitmap_get_height(msdf_bitmap_handle bitmap, int* height); +MSDF_API int msdf_bitmap_get_pixels(msdf_bitmap_handle bitmap, void** pixels); +MSDF_API void msdf_bitmap_free(msdf_bitmap_handle bitmap); + +MSDF_API int msdf_shape_alloc(msdf_shape_handle* shape); +MSDF_API int msdf_shape_get_bounds(msdf_shape_handle shape, msdf_bounds_t* bounds); +MSDF_API int msdf_shape_add_contour(msdf_shape_handle shape, msdf_contour_handle* contour); +MSDF_API int msdf_shape_get_contour_count(msdf_shape_handle shape, int* contour_count); +MSDF_API int msdf_shape_get_contours(msdf_shape_handle shape, msdf_contour_handle* contours); +MSDF_API int msdf_shape_get_edge_counts(msdf_shape_handle shape, int* edge_count); +MSDF_API int msdf_shape_has_inverse_y_axis(msdf_shape_handle shape, int* inverse_y_axis); +MSDF_API int msdf_shape_normalize(msdf_shape_handle shape); +MSDF_API int msdf_shape_validate(msdf_shape_handle shape, int* result); +MSDF_API int msdf_shape_bound(msdf_shape_handle shape, msdf_bounds_t* bounds); +MSDF_API int msdf_shape_bound_miters(msdf_shape_handle shape, msdf_bounds_t* bounds, double border, double miterLimit, int polarity); +MSDF_API void msdf_shape_free(msdf_shape_handle shape); + +MSDF_API int msdf_contour_alloc(msdf_contour_handle* contour); +MSDF_API int msdf_contour_add_edge(msdf_contour_handle contour, msdf_edge_holder_handle* edge); +MSDF_API int msdf_contour_get_edge(msdf_contour_handle contour, int index, msdf_edge_holder_handle* edge); +MSDF_API int msdf_contour_get_edge_count(msdf_contour_handle contour, int* edge_count); +MSDF_API int msdf_contour_get_edges(msdf_contour_handle contour, msdf_edge_holder_handle* edges); +MSDF_API int msdf_contour_bound(msdf_contour_handle contour, msdf_bounds_t* bounds); +MSDF_API int msdf_contour_bound_miters(msdf_contour_handle contour, msdf_bounds_t* bounds, double border, double miterLimit, int polarity); +MSDF_API int msdf_contour_get_winding(msdf_contour_handle contour, int* winding); +MSDF_API int msdf_contour_reverse(msdf_contour_handle contour); +MSDF_API void msdf_contour_free(msdf_contour_handle contour); + +MSDF_API int msdf_edge_alloc(msdf_edge_holder_handle* edge); +MSDF_API int msdf_edge_add_segment(msdf_edge_holder_handle edge, msdf_segment_handle segment); +MSDF_API int msdf_edge_get_segment(msdf_edge_holder_handle edge, int index, msdf_segment_handle* segment); +MSDF_API int msdf_edge_get_segment_count(msdf_edge_holder_handle edge, int* segment_count); +MSDF_API int msdf_edge_get_segments(msdf_edge_holder_handle edge, msdf_segment_handle* segments); +MSDF_API void msdf_edge_free(msdf_edge_holder_handle edge); + +MSDF_API int msdf_segment_alloc(int type, msdf_segment_handle* segment); +MSDF_API int msdf_segment_get_type(msdf_segment_handle segment, int* type); +MSDF_API int msdf_segment_get_point_count(msdf_segment_handle segment, int* point_count); +MSDF_API int msdf_segment_get_points(msdf_segment_handle segment, msdf_vector2_t const** points); +MSDF_API int msdf_segment_get_point(msdf_segment_handle segment, int index, msdf_vector2_t* point); +MSDF_API int msdf_segment_set_point(msdf_segment_handle segment, int index, const msdf_vector2_t* point); +MSDF_API int msdf_segment_set_color(msdf_segment_handle segment, int color); +MSDF_API int msdf_segment_get_color(msdf_segment_handle segment, int* color); +MSDF_API int msdf_segment_get_direction(msdf_segment_handle segment, double param, msdf_vector2_t* direction); +MSDF_API int msdf_segment_get_direction_change(msdf_segment_handle segment, double param, msdf_vector2_t* direction_change); +MSDF_API int msdf_segment_point(msdf_segment_handle segment, double param, msdf_vector2_t* point); +MSDF_API int msdf_segment_bound(msdf_segment_handle segment, msdf_bounds_t* bounds); +MSDF_API int msdf_segment_move_start_point(msdf_segment_handle segment, const msdf_vector2_t* point); +MSDF_API int msdf_segment_move_end_point(msdf_segment_handle segment, const msdf_vector2_t* point); +MSDF_API void msdf_segment_free(msdf_segment_handle segment); + +MSDF_API int msdf_generate_sdf(msdf_bitmap_handle output, msdf_shape_handle shape, const msdf_transform_t* transform); +MSDF_API int msdf_generate_psdf(msdf_bitmap_handle output, msdf_shape_handle shape, const msdf_transform_t* transform); +MSDF_API int msdf_generate_msdf(msdf_bitmap_handle output, msdf_shape_handle shape, const msdf_transform_t* transform); +MSDF_API int msdf_generate_mtsdf(msdf_bitmap_handle output, msdf_shape_handle shape, const msdf_transform_t* transform); + +MSDF_API int msdf_generate_sdf_with_config(msdf_bitmap_handle output, + msdf_shape_handle shape, + const msdf_transform_t* transform, + const msdf_config_t* config); +MSDF_API int msdf_generate_psdf_with_config(msdf_bitmap_handle output, + msdf_shape_handle shape, + const msdf_transform_t* transform, + const msdf_config_t* config); +MSDF_API int msdf_generate_msdf_with_config(msdf_bitmap_handle output, + msdf_shape_handle shape, + const msdf_transform_t* transform, + const msdf_multichannel_config_t* config); +MSDF_API int msdf_generate_mtsdf_with_config(msdf_bitmap_handle output, + msdf_shape_handle shape, + const msdf_transform_t* transform, + const msdf_multichannel_config_t* config); + +#ifdef __cplusplus +} +#endif \ No newline at end of file