mirror of https://github.com/Chlumsky/msdfgen.git
Created minimal C library, true SDF sampling (WIP)
This commit is contained in:
parent
e3ced1e362
commit
167be50b5f
|
|
@ -67,7 +67,7 @@ if(MSDFGEN_USE_VCPKG)
|
|||
endif()
|
||||
|
||||
# Version is specified in vcpkg.json
|
||||
project(msdfgen VERSION ${MSDFGEN_VERSION} LANGUAGES CXX)
|
||||
project(msdfgen VERSION ${MSDFGEN_VERSION} LANGUAGES C CXX)
|
||||
|
||||
if(MSDFGEN_DYNAMIC_RUNTIME)
|
||||
set(MSDFGEN_MSVC_RUNTIME "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
|
|
@ -87,11 +87,30 @@ if(MAX_WARNING_LEVEL)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE MSDFGEN_C_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "c/*.h")
|
||||
file(GLOB_RECURSE MSDFGEN_C_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "c/*.c")
|
||||
file(GLOB_RECURSE MSDFGEN_CORE_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "core/*.h" "core/*.hpp")
|
||||
file(GLOB_RECURSE MSDFGEN_CORE_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "core/*.cpp")
|
||||
file(GLOB_RECURSE MSDFGEN_EXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "ext/*.h" "ext/*.hpp")
|
||||
file(GLOB_RECURSE MSDFGEN_EXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "ext/*.cpp" "lib/*.cpp")
|
||||
|
||||
# C library
|
||||
add_library(msdfgen-c ${MSDFGEN_C_HEADERS} ${MSDFGEN_C_SOURCES})
|
||||
add_library(msdfgen::msdfgen-c ALIAS msdfgen-c)
|
||||
set_target_properties(msdfgen-c PROPERTIES PUBLIC_HEADER "${MSDFGEN_C_HEADERS}")
|
||||
set_property(TARGET msdfgen-c PROPERTY MSVC_RUNTIME_LIBRARY "${MSDFGEN_MSVC_RUNTIME}")
|
||||
target_compile_definitions(msdfgen-c PUBLIC
|
||||
MSDFGEN_VERSION=${MSDFGEN_VERSION}
|
||||
MSDFGEN_VERSION_MAJOR=${MSDFGEN_VERSION_MAJOR}
|
||||
MSDFGEN_VERSION_MINOR=${MSDFGEN_VERSION_MINOR}
|
||||
MSDFGEN_VERSION_REVISION=${MSDFGEN_VERSION_REVISION}
|
||||
MSDFGEN_COPYRIGHT_YEAR=${MSDFGEN_COPYRIGHT_YEAR}
|
||||
)
|
||||
target_include_directories(msdfgen-c INTERFACE
|
||||
$<INSTALL_INTERFACE:include/msdfgen>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/>
|
||||
)
|
||||
|
||||
# Core library
|
||||
add_library(msdfgen-core "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.h" ${MSDFGEN_CORE_HEADERS} ${MSDFGEN_CORE_SOURCES})
|
||||
add_library(msdfgen::msdfgen-core ALIAS msdfgen-core)
|
||||
|
|
@ -166,8 +185,6 @@ if(NOT MSDFGEN_CORE_ONLY)
|
|||
PUBLIC
|
||||
$<INSTALL_INTERFACE:include/msdfgen>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdfgen-ext)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
#include "CompiledShape.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static MSDFGEN_Vector2 computeCornerVec(MSDFGEN_Vector2 normalizedDirection, MSDFGEN_Vector2 adjacentEdgeDirection1) {
|
||||
return MSDFGEN_Vector2_normalizeOrZero(MSDFGEN_Vector2_sum(normalizedDirection, MSDFGEN_Vector2_normalizeOrZero(adjacentEdgeDirection1)));
|
||||
}
|
||||
|
||||
void MSDFGEN_compileLinearEdge(MSDFGEN_CompiledLinearEdge *dstEdgePtr, int colorMask, MSDFGEN_Vector2 point0, MSDFGEN_Vector2 point1, MSDFGEN_Vector2 prevEdgeDirection1, MSDFGEN_Vector2 nextEdgeDirection0) {
|
||||
MSDFGEN_Vector2 p0p1 = MSDFGEN_Vector2_difference(point1, point0);
|
||||
MSDFGEN_real p0p1SqLen = MSDFGEN_Vector2_squaredLength(p0p1);
|
||||
dstEdgePtr->colorMask = colorMask;
|
||||
dstEdgePtr->endpoint0 = point0;
|
||||
dstEdgePtr->endpoint1 = point1;
|
||||
dstEdgePtr->direction = MSDFGEN_Vector2_normalizeOrZero(p0p1);
|
||||
dstEdgePtr->cornerVec0 = computeCornerVec(dstEdgePtr->direction, prevEdgeDirection1);
|
||||
dstEdgePtr->cornerVec1 = computeCornerVec(dstEdgePtr->direction, nextEdgeDirection0);
|
||||
dstEdgePtr->invDerivative.x = 0;
|
||||
dstEdgePtr->invDerivative.y = 0;
|
||||
if (p0p1SqLen != (MSDFGEN_real) 0) {
|
||||
dstEdgePtr->invDerivative.x = -p0p1.x/p0p1SqLen;
|
||||
dstEdgePtr->invDerivative.y = -p0p1.y/p0p1SqLen;
|
||||
}
|
||||
}
|
||||
|
||||
void MSDFGEN_compileQuadraticEdge(MSDFGEN_CompiledQuadraticEdge *dstEdgePtr, int colorMask, MSDFGEN_Vector2 point0, MSDFGEN_Vector2 point1, MSDFGEN_Vector2 point2, MSDFGEN_Vector2 prevEdgeDirection1, MSDFGEN_Vector2 nextEdgeDirection0) {
|
||||
MSDFGEN_Vector2 p1p2 = MSDFGEN_Vector2_difference(point2, point1);
|
||||
dstEdgePtr->colorMask = colorMask;
|
||||
dstEdgePtr->endpoint0 = point0;
|
||||
dstEdgePtr->endpoint1 = point2;
|
||||
dstEdgePtr->derivative0 = MSDFGEN_Vector2_difference(point1, point0);
|
||||
dstEdgePtr->derivative1 = MSDFGEN_Vector2_difference(p1p2, dstEdgePtr->derivative0);
|
||||
dstEdgePtr->direction0 = dstEdgePtr->derivative0;
|
||||
dstEdgePtr->direction1 = p1p2;
|
||||
if (dstEdgePtr->direction0.x == (MSDFGEN_real) 0 && dstEdgePtr->direction0.y == (MSDFGEN_real) 0)
|
||||
dstEdgePtr->direction0 = MSDFGEN_Vector2_difference(point2, point0);
|
||||
if (dstEdgePtr->direction1.x == (MSDFGEN_real) 0 && dstEdgePtr->direction1.y == (MSDFGEN_real) 0)
|
||||
dstEdgePtr->direction1 = MSDFGEN_Vector2_difference(point2, point0);
|
||||
dstEdgePtr->direction0 = MSDFGEN_Vector2_normalizeOrZero(dstEdgePtr->direction0);
|
||||
dstEdgePtr->direction1 = MSDFGEN_Vector2_normalizeOrZero(dstEdgePtr->direction1);
|
||||
dstEdgePtr->cornerVec0 = computeCornerVec(dstEdgePtr->direction0, prevEdgeDirection1);
|
||||
dstEdgePtr->cornerVec1 = computeCornerVec(dstEdgePtr->direction1, nextEdgeDirection0);
|
||||
}
|
||||
|
||||
void MSDFGEN_compileCubicEdge(MSDFGEN_CompiledCubicEdge *dstEdgePtr, int colorMask, MSDFGEN_Vector2 point0, MSDFGEN_Vector2 point1, MSDFGEN_Vector2 point2, MSDFGEN_Vector2 point3, MSDFGEN_Vector2 prevEdgeDirection1, MSDFGEN_Vector2 nextEdgeDirection0) {
|
||||
MSDFGEN_Vector2 p1p2 = MSDFGEN_Vector2_difference(point2, point1);
|
||||
MSDFGEN_Vector2 p2p3 = MSDFGEN_Vector2_difference(point3, point2);
|
||||
dstEdgePtr->colorMask = colorMask;
|
||||
dstEdgePtr->endpoint0 = point0;
|
||||
dstEdgePtr->endpoint1 = point3;
|
||||
dstEdgePtr->derivative0 = MSDFGEN_Vector2_difference(point1, point0);
|
||||
dstEdgePtr->derivative1 = MSDFGEN_Vector2_difference(p1p2, dstEdgePtr->derivative0);
|
||||
dstEdgePtr->derivative2 = MSDFGEN_Vector2_difference(MSDFGEN_Vector2_difference(p2p3, p1p2), dstEdgePtr->derivative1);
|
||||
dstEdgePtr->direction0 = dstEdgePtr->derivative0;
|
||||
if (dstEdgePtr->direction0.x == (MSDFGEN_real) 0 && dstEdgePtr->direction0.y == (MSDFGEN_real) 0) {
|
||||
dstEdgePtr->direction0 = MSDFGEN_Vector2_difference(point2, point0);
|
||||
if (dstEdgePtr->direction0.x == (MSDFGEN_real) 0 && dstEdgePtr->direction0.y == (MSDFGEN_real) 0)
|
||||
dstEdgePtr->direction0 = MSDFGEN_Vector2_difference(point3, point0);
|
||||
}
|
||||
dstEdgePtr->direction1 = p2p3;
|
||||
if (dstEdgePtr->direction1.x == (MSDFGEN_real) 0 && dstEdgePtr->direction1.y == (MSDFGEN_real) 0) {
|
||||
dstEdgePtr->direction1 = MSDFGEN_Vector2_difference(point3, point1);
|
||||
if (dstEdgePtr->direction1.x == (MSDFGEN_real) 0 && dstEdgePtr->direction1.y == (MSDFGEN_real) 0)
|
||||
dstEdgePtr->direction1 = MSDFGEN_Vector2_difference(point3, point0);
|
||||
}
|
||||
dstEdgePtr->direction0 = MSDFGEN_Vector2_normalizeOrZero(dstEdgePtr->direction0);
|
||||
dstEdgePtr->direction1 = MSDFGEN_Vector2_normalizeOrZero(dstEdgePtr->direction1);
|
||||
dstEdgePtr->cornerVec0 = computeCornerVec(dstEdgePtr->direction0, prevEdgeDirection1);
|
||||
dstEdgePtr->cornerVec1 = computeCornerVec(dstEdgePtr->direction1, nextEdgeDirection0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include "Vector2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*typedef struct {
|
||||
void *userPtr;
|
||||
void *(*reallocPtr)(void *userPtr, void *memoryPtr, size_t memorySize);
|
||||
void *(*freePtr)(void *userPtr, void *memoryPtr);
|
||||
} MSDFGEN_Allocator;*/
|
||||
|
||||
typedef struct {
|
||||
int colorMask;
|
||||
MSDFGEN_Vector2 endpoint0, endpoint1;
|
||||
MSDFGEN_Vector2 cornerVec0, cornerVec1;
|
||||
MSDFGEN_Vector2 direction;
|
||||
MSDFGEN_Vector2 invDerivative;
|
||||
} MSDFGEN_CompiledLinearEdge;
|
||||
|
||||
typedef struct {
|
||||
int colorMask;
|
||||
MSDFGEN_Vector2 endpoint0, endpoint1;
|
||||
MSDFGEN_Vector2 cornerVec0, cornerVec1;
|
||||
MSDFGEN_Vector2 direction0, direction1;
|
||||
MSDFGEN_Vector2 derivative0, derivative1;
|
||||
} MSDFGEN_CompiledQuadraticEdge;
|
||||
|
||||
typedef struct {
|
||||
int colorMask;
|
||||
MSDFGEN_Vector2 endpoint0, endpoint1;
|
||||
MSDFGEN_Vector2 cornerVec0, cornerVec1;
|
||||
MSDFGEN_Vector2 direction0, direction1;
|
||||
MSDFGEN_Vector2 derivative0, derivative1, derivative2;
|
||||
} MSDFGEN_CompiledCubicEdge;
|
||||
|
||||
typedef struct {
|
||||
MSDFGEN_CompiledLinearEdge *linearEdges;
|
||||
MSDFGEN_CompiledQuadraticEdge *quadraticEdges;
|
||||
MSDFGEN_CompiledCubicEdge *cubicEdges;
|
||||
size_t nLinearEdges, nQuadraticEdges, nCubicEdges;
|
||||
} MSDFGEN_CompiledShape;
|
||||
|
||||
/*void MSDFGEN_Shape_initialize(MSDFGEN_Shape *shapePtr);
|
||||
void MSDFGEN_Shape_clear(MSDFGEN_Shape *shapePtr, MSDFGEN_Allocator allocator);*/
|
||||
|
||||
void MSDFGEN_compileLinearEdge(MSDFGEN_CompiledLinearEdge *dstEdgePtr, int colorMask, MSDFGEN_Vector2 point0, MSDFGEN_Vector2 point1, MSDFGEN_Vector2 prevEdgeDirection1, MSDFGEN_Vector2 nextEdgeDirection0);
|
||||
void MSDFGEN_compileQuadraticEdge(MSDFGEN_CompiledQuadraticEdge *dstEdgePtr, int colorMask, MSDFGEN_Vector2 point0, MSDFGEN_Vector2 point1, MSDFGEN_Vector2 point2, MSDFGEN_Vector2 prevEdgeDirection1, MSDFGEN_Vector2 nextEdgeDirection0);
|
||||
void MSDFGEN_compileCubicEdge(MSDFGEN_CompiledCubicEdge *dstEdgePtr, int colorMask, MSDFGEN_Vector2 point0, MSDFGEN_Vector2 point1, MSDFGEN_Vector2 point2, MSDFGEN_Vector2 point3, MSDFGEN_Vector2 prevEdgeDirection1, MSDFGEN_Vector2 nextEdgeDirection0);
|
||||
|
||||
/*void MSDFGEN_Shape_addLinearEdge(MSDFGEN_Shape *shapePtr, const MSDFGEN_Shape::LinearEdge *edgePtr, MSDFGEN_Allocator allocator);
|
||||
void MSDFGEN_Shape_addQuadraticEdge(MSDFGEN_Shape *shapePtr, const MSDFGEN_Shape::QuadraticEdge *edgePtr, MSDFGEN_Allocator allocator);
|
||||
void MSDFGEN_Shape_addCubicEdge(MSDFGEN_Shape *shapePtr, const MSDFGEN_Shape::CubicEdge *edgePtr, MSDFGEN_Allocator allocator);*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef double MSDFGEN_real;
|
||||
|
||||
typedef struct {
|
||||
MSDFGEN_real x, y;
|
||||
} MSDFGEN_Vector2;
|
||||
|
||||
inline MSDFGEN_real MSDFGEN_Vector2_squaredLength(MSDFGEN_Vector2 v) {
|
||||
return v.x*v.x+v.y*v.y;
|
||||
}
|
||||
|
||||
inline MSDFGEN_real MSDFGEN_Vector2_dot(MSDFGEN_Vector2 a, MSDFGEN_Vector2 b) {
|
||||
return a.x*b.x+a.y*b.y;
|
||||
}
|
||||
|
||||
inline MSDFGEN_real MSDFGEN_Vector2_cross(MSDFGEN_Vector2 a, MSDFGEN_Vector2 b) {
|
||||
return a.x*b.y-a.y*b.x;
|
||||
}
|
||||
|
||||
inline MSDFGEN_Vector2 MSDFGEN_Vector2_scale(MSDFGEN_real s, MSDFGEN_Vector2 v) {
|
||||
v.x *= s;
|
||||
v.y *= s;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline MSDFGEN_Vector2 MSDFGEN_Vector2_sum(MSDFGEN_Vector2 a, MSDFGEN_Vector2 b) {
|
||||
MSDFGEN_Vector2 result;
|
||||
result.x = a.x+b.x;
|
||||
result.y = a.y+b.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline MSDFGEN_Vector2 MSDFGEN_Vector2_difference(MSDFGEN_Vector2 a, MSDFGEN_Vector2 b) {
|
||||
MSDFGEN_Vector2 result;
|
||||
result.x = a.x-b.x;
|
||||
result.y = a.y-b.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline MSDFGEN_Vector2 MSDFGEN_Vector2_normalizeOrZero(MSDFGEN_Vector2 v) {
|
||||
MSDFGEN_real length = sqrt(MSDFGEN_Vector2_squaredLength(v));
|
||||
if (length != (MSDFGEN_real) 0) {
|
||||
v.x /= length;
|
||||
v.y /= length;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
#include "equation-solver.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int MSDFGEN_solveQuadratic(double x[2], double a, double b, double c) {
|
||||
// a == 0 -> linear equation
|
||||
if (a == 0 || fabs(b) > 1e12*fabs(a)) {
|
||||
// a == 0, b == 0 -> no solution
|
||||
if (b == 0) {
|
||||
if (c == 0)
|
||||
return -1; // 0 == 0
|
||||
return 0;
|
||||
}
|
||||
x[0] = -c/b;
|
||||
return 1;
|
||||
}
|
||||
double dscr = b*b-4*a*c;
|
||||
if (dscr > 0) {
|
||||
dscr = sqrt(dscr);
|
||||
x[0] = (-b+dscr)/(2*a);
|
||||
x[1] = (-b-dscr)/(2*a);
|
||||
return 2;
|
||||
} else if (dscr == 0) {
|
||||
x[0] = -b/(2*a);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int solveCubicNormed(double x[3], double a, double b, double c) {
|
||||
double a2 = a*a;
|
||||
double q = 1/9.*(a2-3*b);
|
||||
double r = 1/54.*(a*(2*a2-9*b)+27*c);
|
||||
double r2 = r*r;
|
||||
double q3 = q*q*q;
|
||||
a *= 1/3.;
|
||||
if (r2 < q3) {
|
||||
double t = r/sqrt(q3);
|
||||
if (t < -1) t = -1;
|
||||
if (t > 1) t = 1;
|
||||
t = acos(t);
|
||||
q = -2*sqrt(q);
|
||||
x[0] = q*cos(1/3.*t)-a;
|
||||
x[1] = q*cos(1/3.*(t+2*M_PI))-a;
|
||||
x[2] = q*cos(1/3.*(t-2*M_PI))-a;
|
||||
return 3;
|
||||
} else {
|
||||
double u = (r < 0 ? 1 : -1)*pow(fabs(r)+sqrt(r2-q3), 1/3.);
|
||||
double v = u == 0 ? 0 : q/u;
|
||||
x[0] = (u+v)-a;
|
||||
if (u == v || fabs(u-v) < 1e-12*fabs(u+v)) {
|
||||
x[1] = -.5*(u+v)-a;
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int MSDFGEN_solveCubic(double x[3], double a, double b, double c, double d) {
|
||||
if (a != 0) {
|
||||
double bn = b/a;
|
||||
if (fabs(bn) < 1e6) // Above this ratio, the numerical error gets larger than if we treated a as zero
|
||||
return solveCubicNormed(x, bn, c/a, d/a);
|
||||
}
|
||||
return MSDFGEN_solveQuadratic(x, b, c, d);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ax^2 + bx + c = 0
|
||||
int MSDFGEN_solveQuadratic(double x[2], double a, double b, double c);
|
||||
|
||||
// ax^3 + bx^2 + cx + d = 0
|
||||
int MSDFGEN_solveCubic(double x[3], double a, double b, double c, double d);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include "Vector2.h"
|
||||
#include "CompiledShape.h"
|
||||
|
||||
#define MSDFGEN_CUBIC_SEARCH_STARTS 4
|
||||
#define MSDFGEN_CUBIC_SEARCH_STEPS 4
|
||||
|
||||
#define MSDFGEN_ABTEST_ALT_CACHE 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
#if MSDFGEN_ABTEST_ALT_CACHE
|
||||
MSDFGEN_Vector2 origin;
|
||||
#endif
|
||||
MSDFGEN_real edgeDistance;
|
||||
} MSDFGEN_TrueDistanceEdgeCache;
|
||||
|
||||
typedef struct {
|
||||
MSDFGEN_Vector2 origin;
|
||||
MSDFGEN_real minDistance;
|
||||
MSDFGEN_TrueDistanceEdgeCache edgeData[1];
|
||||
} MSDFGEN_TrueDistanceCache;
|
||||
|
||||
typedef struct {
|
||||
MSDFGEN_Vector2 origin;
|
||||
struct EdgeData {
|
||||
MSDFGEN_real absDistance;
|
||||
MSDFGEN_real domainDistance0, domainDistance1;
|
||||
MSDFGEN_real perpendicularDistance0, perpendicularDistance1;
|
||||
} edgeData[1];
|
||||
} MSDFGEN_PerpendicularDistanceCache;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
MSDFGEN_real scale, translate;
|
||||
} distanceMapping;
|
||||
struct {
|
||||
MSDFGEN_Vector2 scale, translate;
|
||||
} projection;
|
||||
} MSDFGEN_SDFTransformation;
|
||||
|
||||
typedef struct {
|
||||
enum Mode {
|
||||
DISABLED,
|
||||
INDISCRIMINATE,
|
||||
EDGE_PRIORITY,
|
||||
EDGE_ONLY
|
||||
} mode;
|
||||
enum DistanceCheckMode {
|
||||
DO_NOT_CHECK_DISTANCE,
|
||||
CHECK_DISTANCE_AT_EDGE,
|
||||
ALWAYS_CHECK_DISTANCE
|
||||
} distanceCheckMode;
|
||||
MSDFGEN_real minDeviationRatio;
|
||||
MSDFGEN_real minImproveRatio;
|
||||
void *buffer;
|
||||
} MSDFGEN_ErrorCorrectionSettings;
|
||||
|
||||
size_t MSDFGEN_TrueDistanceCache_size(const MSDFGEN_CompiledShape *shapePtr);
|
||||
size_t MSDFGEN_PerpendicularDistanceCache_size(const MSDFGEN_CompiledShape *shapePtr);
|
||||
|
||||
void MSDFGEN_TrueDistanceCache_initialize(MSDFGEN_TrueDistanceCache *cachePtr, const MSDFGEN_CompiledShape *shapePtr);
|
||||
void MSDFGEN_PerpendicularDistanceCache_initialize(MSDFGEN_PerpendicularDistanceCache *cachePtr, const MSDFGEN_CompiledShape *shapePtr);
|
||||
|
||||
MSDFGEN_real MSDFGEN_signedDistance(const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_Vector2 origin, MSDFGEN_TrueDistanceCache *cachePtr);
|
||||
MSDFGEN_real MSDFGEN_perpendicularSignedDistance(const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_Vector2 origin, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
MSDFGEN_real MSDFGEN_multiSignedDistance(MSDFGEN_real dstMultiDistance[3], const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_Vector2 origin, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
|
||||
void MSDFGEN_generateSDF(float *dstPixels, int width, int height, size_t rowStride, const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_SDFTransformation transformation, MSDFGEN_TrueDistanceCache *cachePtr);
|
||||
void MSDFGEN_generatePSDF(float *dstPixels, int width, int height, size_t rowStride, const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_SDFTransformation transformation, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
void MSDFGEN_generateMSDF(float *dstPixels, int width, int height, size_t rowStride, const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_SDFTransformation transformation, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
void MSDFGEN_generateMTSDF(float *dstPixels, int width, int height, size_t rowStride, const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_SDFTransformation transformation, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
|
||||
void MSDFGEN_errorCorrectionMSDF(MSDFGEN_ErrorCorrectionSettings settings, float *pixels, int width, int height, size_t rowStride, const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_SDFTransformation transformation, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
void MSDFGEN_errorCorrectionMTSDF(MSDFGEN_ErrorCorrectionSettings settings, float *pixels, int width, int height, size_t rowStride, const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_SDFTransformation transformation, MSDFGEN_PerpendicularDistanceCache *cachePtr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
|
||||
#include "msdfgen-c.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include "equation-solver.h"
|
||||
|
||||
#define DISTANCE_DELTA_FACTOR 1.001
|
||||
|
||||
//#define MSDFGEN_IF_CACHE_AND(...) // disable cache
|
||||
#define MSDFGEN_IF_CACHE_AND if
|
||||
|
||||
extern long long MSDFGEN_PERFSTATS_CACHE_TESTS;
|
||||
extern long long MSDFGEN_PERFSTATS_CACHE_MISSES;
|
||||
|
||||
long long MSDFGEN_PERFSTATS_CACHE_TESTS = 0;
|
||||
long long MSDFGEN_PERFSTATS_CACHE_MISSES = 0;
|
||||
|
||||
#define MSDFGEN_PERFSTATS_CACHE_TEST() (++MSDFGEN_PERFSTATS_CACHE_TESTS)
|
||||
#define MSDFGEN_PERFSTATS_CACHE_MISS() (++MSDFGEN_PERFSTATS_CACHE_MISSES)
|
||||
|
||||
//#define NO_CACHE_AND_SQUARE_DISTANCE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static int nonZeroSign(MSDFGEN_real x) {
|
||||
return x > (MSDFGEN_real) 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
static int crossNonZeroSign(MSDFGEN_Vector2 a, MSDFGEN_Vector2 b) {
|
||||
return a.x*b.y > b.x*a.y ? 1 : -1;
|
||||
}
|
||||
|
||||
size_t MSDFGEN_TrueDistanceCache_size(const MSDFGEN_CompiledShape *shapePtr) {
|
||||
return sizeof(MSDFGEN_TrueDistanceCache) + (shapePtr->nLinearEdges+shapePtr->nQuadraticEdges+shapePtr->nCubicEdges)*sizeof(MSDFGEN_TrueDistanceEdgeCache);
|
||||
}
|
||||
|
||||
void MSDFGEN_TrueDistanceCache_initialize(MSDFGEN_TrueDistanceCache *cachePtr, const MSDFGEN_CompiledShape *shapePtr) {
|
||||
MSDFGEN_TrueDistanceEdgeCache *cur, *end;
|
||||
cachePtr->origin.x = 0;
|
||||
cachePtr->origin.y = 0;
|
||||
cachePtr->minDistance = .0625f*FLT_MAX;
|
||||
for (cur = cachePtr->edgeData, end = cachePtr->edgeData+(shapePtr->nLinearEdges+shapePtr->nQuadraticEdges+shapePtr->nCubicEdges); cur < end; ++cur) {
|
||||
#if MSDFGEN_ABTEST_ALT_CACHE
|
||||
cur->origin.x = 0;
|
||||
cur->origin.y = 0;
|
||||
#else
|
||||
cur->edgeDistance = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NO_CACHE_AND_SQUARE_DISTANCE
|
||||
|
||||
// INCOMPLETE !!!!
|
||||
|
||||
MSDFGEN_real MSDFGEN_signedDistance(const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_Vector2 origin, MSDFGEN_TrueDistanceCache *cachePtr) {
|
||||
int sign = -1;
|
||||
MSDFGEN_real sqd = FLT_MAX;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < shapePtr->nLinearEdges; ++i) {
|
||||
MSDFGEN_Vector2 originP0 = MSDFGEN_Vector2_difference(shapePtr->linearEdges[i].endpoint0, origin);
|
||||
MSDFGEN_real originP0SqD = MSDFGEN_Vector2_squaredLength(originP0);
|
||||
MSDFGEN_real t = MSDFGEN_Vector2_dot(originP0, shapePtr->linearEdges[i].invDerivative);
|
||||
if (originP0SqD < sqd) {
|
||||
sqd = originP0SqD;
|
||||
sign = crossNonZeroSign(shapePtr->linearEdges[i].cornerVec0, MSDFGEN_Vector2_sum(shapePtr->linearEdges[i].direction, originP0));
|
||||
}
|
||||
if (t > (MSDFGEN_real) 0 && t < (MSDFGEN_real) 1) {
|
||||
MSDFGEN_real pd = MSDFGEN_Vector2_cross(shapePtr->linearEdges[i].direction, originP0);
|
||||
MSDFGEN_real sqpd = pd*pd;
|
||||
if (sqpd < sqd) {
|
||||
sqd = sqpd;
|
||||
sign = nonZeroSign(pd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < shapePtr->nQuadraticEdges; ++i) {
|
||||
MSDFGEN_Vector2 originP0 = MSDFGEN_Vector2_difference(shapePtr->quadraticEdges[i].endpoint0, origin);
|
||||
MSDFGEN_real originP0SqD = MSDFGEN_Vector2_squaredLength(originP0);
|
||||
MSDFGEN_real a = MSDFGEN_Vector2_squaredLength(shapePtr->quadraticEdges[i].derivative1);
|
||||
MSDFGEN_real b = (MSDFGEN_real) 3*MSDFGEN_Vector2_dot(shapePtr->quadraticEdges[i].derivative0, shapePtr->quadraticEdges[i].derivative1);
|
||||
MSDFGEN_real c = (MSDFGEN_real) 2*MSDFGEN_Vector2_squaredLength(shapePtr->quadraticEdges[i].derivative0) + MSDFGEN_Vector2_dot(originP0, shapePtr->quadraticEdges[i].derivative1);
|
||||
MSDFGEN_real d = MSDFGEN_Vector2_dot(originP0, shapePtr->quadraticEdges[i].derivative0);
|
||||
double t[3];
|
||||
int solutions = MSDFGEN_solveCubic(t, a, b, c, d);
|
||||
if (originP0SqD < sqd) {
|
||||
sqd = originP0SqD;
|
||||
sign = crossNonZeroSign(shapePtr->quadraticEdges[i].cornerVec0, MSDFGEN_Vector2_sum(shapePtr->quadraticEdges[i].direction0, originP0));
|
||||
}
|
||||
#define MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t) if (t > 0 && t < 1) { \
|
||||
MSDFGEN_Vector2 originP = MSDFGEN_Vector2_sum(MSDFGEN_Vector2_sum(originP0, MSDFGEN_Vector2_scale((MSDFGEN_real) (2*t), shapePtr->quadraticEdges[i].derivative0)), MSDFGEN_Vector2_scale((MSDFGEN_real) (t*t), shapePtr->quadraticEdges[i].derivative1)); \
|
||||
MSDFGEN_real originPSqD = MSDFGEN_Vector2_squaredLength(originP); \
|
||||
if (originPSqD < sqd) { \
|
||||
MSDFGEN_Vector2 direction = MSDFGEN_Vector2_sum(shapePtr->quadraticEdges[i].derivative0, MSDFGEN_Vector2_scale(t, shapePtr->quadraticEdges[i].derivative1)); \
|
||||
sqd = originPSqD; \
|
||||
sign = crossNonZeroSign(direction, originP); \
|
||||
} \
|
||||
}
|
||||
if (solutions > 0) {
|
||||
MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t[0]);
|
||||
if (solutions > 1) {
|
||||
MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t[1]);
|
||||
if (solutions > 2)
|
||||
MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (MSDFGEN_real) sign*sqrt(sqd);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if MSDFGEN_ABTEST_ALT_CACHE
|
||||
#define MSDFGEN_IF_TRUE_DISTANCE_UNCACHED MSDFGEN_PERFSTATS_CACHE_TEST(); MSDFGEN_IF_CACHE_AND(++edgeCache, edgeCache[-1].edgeDistance-DISTANCE_DELTA_FACTOR*sqrt(MSDFGEN_Vector2_squaredLength(MSDFGEN_Vector2_difference(origin, edgeCache[-1].origin))) <= minDistance)
|
||||
#else
|
||||
#define MSDFGEN_IF_TRUE_DISTANCE_UNCACHED MSDFGEN_PERFSTATS_CACHE_TEST(); MSDFGEN_IF_CACHE_AND((edgeCache++->edgeDistance -= cacheDelta) <= minDistance)
|
||||
#endif
|
||||
|
||||
MSDFGEN_real MSDFGEN_signedDistance(const MSDFGEN_CompiledShape *shapePtr, MSDFGEN_Vector2 origin, MSDFGEN_TrueDistanceCache *cachePtr) {
|
||||
|
||||
MSDFGEN_real cacheDelta = DISTANCE_DELTA_FACTOR*sqrt(MSDFGEN_Vector2_squaredLength(MSDFGEN_Vector2_difference(origin, cachePtr->origin)));
|
||||
MSDFGEN_real minDistance = cachePtr->minDistance+cacheDelta;
|
||||
int distanceSign = -1;
|
||||
MSDFGEN_TrueDistanceEdgeCache *edgeCache = cachePtr->edgeData;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < shapePtr->nLinearEdges; ++i) {
|
||||
MSDFGEN_IF_TRUE_DISTANCE_UNCACHED {
|
||||
MSDFGEN_Vector2 originP0 = MSDFGEN_Vector2_difference(shapePtr->linearEdges[i].endpoint0, origin);
|
||||
MSDFGEN_real originP0Dist = sqrt(MSDFGEN_Vector2_squaredLength(originP0));
|
||||
MSDFGEN_real t = MSDFGEN_Vector2_dot(originP0, shapePtr->linearEdges[i].invDerivative);
|
||||
if (originP0Dist < minDistance) {
|
||||
minDistance = originP0Dist;
|
||||
distanceSign = crossNonZeroSign(shapePtr->linearEdges[i].cornerVec0, MSDFGEN_Vector2_sum(shapePtr->linearEdges[i].direction, originP0));
|
||||
}
|
||||
edgeCache[-1].edgeDistance = originP0Dist;
|
||||
if (t > (MSDFGEN_real) 0 && t < (MSDFGEN_real) 1) {
|
||||
MSDFGEN_real psd = MSDFGEN_Vector2_cross(shapePtr->linearEdges[i].direction, originP0);
|
||||
MSDFGEN_real pd = fabs(psd);
|
||||
if (pd < minDistance) {
|
||||
minDistance = pd;
|
||||
distanceSign = nonZeroSign(psd);
|
||||
}
|
||||
edgeCache[-1].edgeDistance = pd;
|
||||
} else {
|
||||
MSDFGEN_real originP1Dist = sqrt(MSDFGEN_Vector2_squaredLength(MSDFGEN_Vector2_difference(shapePtr->linearEdges[i].endpoint1, origin)));
|
||||
if (originP1Dist < edgeCache[-1].edgeDistance)
|
||||
edgeCache[-1].edgeDistance = originP1Dist;
|
||||
}
|
||||
MSDFGEN_PERFSTATS_CACHE_MISS();
|
||||
#if MSDFGEN_ABTEST_ALT_CACHE
|
||||
edgeCache[-1].origin = origin;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < shapePtr->nQuadraticEdges; ++i) {
|
||||
MSDFGEN_IF_TRUE_DISTANCE_UNCACHED {
|
||||
MSDFGEN_Vector2 originP0 = MSDFGEN_Vector2_difference(shapePtr->quadraticEdges[i].endpoint0, origin);
|
||||
MSDFGEN_real originP0Dist = sqrt(MSDFGEN_Vector2_squaredLength(originP0));
|
||||
MSDFGEN_real originP1Dist = sqrt(MSDFGEN_Vector2_squaredLength(MSDFGEN_Vector2_difference(shapePtr->quadraticEdges[i].endpoint1, origin)));
|
||||
MSDFGEN_real a = MSDFGEN_Vector2_squaredLength(shapePtr->quadraticEdges[i].derivative1);
|
||||
MSDFGEN_real b = (MSDFGEN_real) 3*MSDFGEN_Vector2_dot(shapePtr->quadraticEdges[i].derivative0, shapePtr->quadraticEdges[i].derivative1);
|
||||
MSDFGEN_real c = (MSDFGEN_real) 2*MSDFGEN_Vector2_squaredLength(shapePtr->quadraticEdges[i].derivative0) + MSDFGEN_Vector2_dot(originP0, shapePtr->quadraticEdges[i].derivative1);
|
||||
MSDFGEN_real d = MSDFGEN_Vector2_dot(originP0, shapePtr->quadraticEdges[i].derivative0);
|
||||
double t[3];
|
||||
int solutions = MSDFGEN_solveCubic(t, a, b, c, d);
|
||||
if (originP0Dist < minDistance) {
|
||||
minDistance = originP0Dist;
|
||||
distanceSign = crossNonZeroSign(shapePtr->quadraticEdges[i].cornerVec0, MSDFGEN_Vector2_sum(shapePtr->quadraticEdges[i].direction0, originP0));
|
||||
}
|
||||
edgeCache[-1].edgeDistance = originP0Dist;
|
||||
if (originP1Dist < edgeCache[-1].edgeDistance)
|
||||
edgeCache[-1].edgeDistance = originP1Dist;
|
||||
#define MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t) if (t > 0 && t < 1) { \
|
||||
MSDFGEN_Vector2 originP = MSDFGEN_Vector2_sum(MSDFGEN_Vector2_sum(originP0, MSDFGEN_Vector2_scale((MSDFGEN_real) (2*t), shapePtr->quadraticEdges[i].derivative0)), MSDFGEN_Vector2_scale((MSDFGEN_real) (t*t), shapePtr->quadraticEdges[i].derivative1)); \
|
||||
MSDFGEN_real originPDist = sqrt(MSDFGEN_Vector2_squaredLength(originP)); \
|
||||
if (originPDist < minDistance) { \
|
||||
MSDFGEN_Vector2 direction = MSDFGEN_Vector2_sum(shapePtr->quadraticEdges[i].derivative0, MSDFGEN_Vector2_scale(t, shapePtr->quadraticEdges[i].derivative1)); \
|
||||
minDistance = originPDist; \
|
||||
distanceSign = crossNonZeroSign(direction, originP); \
|
||||
} \
|
||||
if (originPDist < edgeCache[-1].edgeDistance) \
|
||||
edgeCache[-1].edgeDistance = originPDist; \
|
||||
}
|
||||
if (solutions > 0) {
|
||||
MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t[0]);
|
||||
if (solutions > 1) {
|
||||
MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t[1]);
|
||||
if (solutions > 2)
|
||||
MSDFGEN_SD_RESOLVE_QUADRATIC_SOLUTION(t[2]);
|
||||
}
|
||||
}
|
||||
MSDFGEN_PERFSTATS_CACHE_MISS();
|
||||
#if MSDFGEN_ABTEST_ALT_CACHE
|
||||
edgeCache[-1].origin = origin;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < shapePtr->nCubicEdges; ++i) {
|
||||
MSDFGEN_IF_TRUE_DISTANCE_UNCACHED {
|
||||
int start, step;
|
||||
MSDFGEN_Vector2 originP0 = MSDFGEN_Vector2_difference(shapePtr->cubicEdges[i].endpoint0, origin);
|
||||
MSDFGEN_real originP0Dist = sqrt(MSDFGEN_Vector2_squaredLength(originP0));
|
||||
MSDFGEN_real originP1Dist = sqrt(MSDFGEN_Vector2_squaredLength(MSDFGEN_Vector2_difference(shapePtr->cubicEdges[i].endpoint1, origin)));
|
||||
if (originP0Dist < minDistance) {
|
||||
minDistance = originP0Dist;
|
||||
distanceSign = crossNonZeroSign(shapePtr->cubicEdges[i].cornerVec0, MSDFGEN_Vector2_sum(shapePtr->cubicEdges[i].direction0, originP0));
|
||||
}
|
||||
edgeCache[-1].edgeDistance = originP0Dist;
|
||||
if (originP1Dist < edgeCache[-1].edgeDistance)
|
||||
edgeCache[-1].edgeDistance = originP1Dist;
|
||||
for (start = 0; start <= MSDFGEN_CUBIC_SEARCH_STARTS; ++start) {
|
||||
MSDFGEN_real t = (MSDFGEN_real) 1/(MSDFGEN_real) MSDFGEN_CUBIC_SEARCH_STARTS*(MSDFGEN_real) start;
|
||||
MSDFGEN_Vector2 originP = MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_sum(originP0, MSDFGEN_Vector2_scale((MSDFGEN_real) 3*t, shapePtr->cubicEdges[i].derivative0)),
|
||||
MSDFGEN_Vector2_scale((MSDFGEN_real) 3*(t*t), shapePtr->cubicEdges[i].derivative1)
|
||||
), MSDFGEN_Vector2_scale(t*t*t, shapePtr->cubicEdges[i].derivative2)
|
||||
);
|
||||
for (step = 0; step < MSDFGEN_CUBIC_SEARCH_STEPS; ++step) {
|
||||
MSDFGEN_Vector2 derivative0 = MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_scale((MSDFGEN_real) 3, shapePtr->cubicEdges[i].derivative0),
|
||||
MSDFGEN_Vector2_scale((MSDFGEN_real) 6*t, shapePtr->cubicEdges[i].derivative1)
|
||||
), MSDFGEN_Vector2_scale((MSDFGEN_real) 3*(t*t), shapePtr->cubicEdges[i].derivative2)
|
||||
);
|
||||
MSDFGEN_Vector2 derivative1 = MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_scale((MSDFGEN_real) 6, shapePtr->cubicEdges[i].derivative1),
|
||||
MSDFGEN_Vector2_scale((MSDFGEN_real) 6*t, shapePtr->cubicEdges[i].derivative2)
|
||||
);
|
||||
t -= MSDFGEN_Vector2_dot(originP, derivative0)/(MSDFGEN_Vector2_squaredLength(derivative0)+MSDFGEN_Vector2_dot(originP, derivative1));
|
||||
if (t <= (MSDFGEN_real) 0 || t >= (MSDFGEN_real) 1)
|
||||
break;
|
||||
originP = MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_sum(
|
||||
MSDFGEN_Vector2_sum(originP0, MSDFGEN_Vector2_scale((MSDFGEN_real) 3*t, shapePtr->cubicEdges[i].derivative0)),
|
||||
MSDFGEN_Vector2_scale((MSDFGEN_real) 3*(t*t), shapePtr->cubicEdges[i].derivative1)
|
||||
), MSDFGEN_Vector2_scale(t*t*t, shapePtr->cubicEdges[i].derivative2)
|
||||
);
|
||||
MSDFGEN_real originPDist = sqrt(MSDFGEN_Vector2_squaredLength(originP));
|
||||
if (originPDist < minDistance) {
|
||||
minDistance = originPDist;
|
||||
distanceSign = crossNonZeroSign(derivative0, originP);
|
||||
}
|
||||
if (originPDist < edgeCache[-1].edgeDistance)
|
||||
edgeCache[-1].edgeDistance = originPDist;
|
||||
}
|
||||
}
|
||||
MSDFGEN_PERFSTATS_CACHE_MISS();
|
||||
#if MSDFGEN_ABTEST_ALT_CACHE
|
||||
edgeCache[-1].origin = origin;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
cachePtr->origin = origin;
|
||||
cachePtr->minDistance = minDistance;
|
||||
return (MSDFGEN_real) distanceSign*minDistance;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue