Merge branch 'fibref-flax-msdf-font'
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/GUI.flax
LFS
BIN
Content/Shaders/GUI.flax
LFS
Binary file not shown.
@@ -21,6 +21,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// </summary>
|
||||
private sealed class PropertiesProxy
|
||||
{
|
||||
[DefaultValue(FontRasterMode.Bitmap)]
|
||||
[EditorOrder(5), EditorDisplay("Properties"), Tooltip("The rasterization mode used when generating font atlases.")]
|
||||
public FontRasterMode RasterMode;
|
||||
|
||||
[DefaultValue(FontHinting.Default)]
|
||||
[EditorOrder(10), EditorDisplay("Properties"), Tooltip("The font hinting used when rendering characters.")]
|
||||
public FontHinting Hinting;
|
||||
@@ -41,7 +45,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
options = new FontOptions
|
||||
{
|
||||
Hinting = Hinting
|
||||
Hinting = Hinting,
|
||||
RasterMode = RasterMode,
|
||||
};
|
||||
if (AntiAliasing)
|
||||
options.Flags |= FontFlags.AntiAliasing;
|
||||
@@ -57,6 +62,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
AntiAliasing = (options.Flags & FontFlags.AntiAliasing) == FontFlags.AntiAliasing;
|
||||
Bold = (options.Flags & FontFlags.Bold) == FontFlags.Bold;
|
||||
Italic = (options.Flags & FontFlags.Italic) == FontFlags.Italic;
|
||||
RasterMode = options.RasterMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "Audio.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "AudioSettings.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Level/Level.h"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Render2D/FontAsset.h"
|
||||
|
||||
/// <summary>
|
||||
/// Font Asset Upgrader
|
||||
@@ -17,10 +18,33 @@ public:
|
||||
{
|
||||
const Upgrader upgraders[] =
|
||||
{
|
||||
{},
|
||||
{ 3, 4, &Upgrade_3_To_4 },
|
||||
};
|
||||
setup(upgraders, ARRAY_COUNT(upgraders));
|
||||
}
|
||||
|
||||
private:
|
||||
struct FontOptionsOld
|
||||
{
|
||||
FontHinting Hinting;
|
||||
FontFlags Flags;
|
||||
};
|
||||
|
||||
static bool Upgrade_3_To_4(AssetMigrationContext& context)
|
||||
{
|
||||
ASSERT(context.Input.SerializedVersion == 3 && context.Output.SerializedVersion == 4);
|
||||
|
||||
FontOptionsOld optionsOld;
|
||||
Platform::MemoryCopy(&optionsOld, context.Input.CustomData.Get(), sizeof(FontOptionsOld));
|
||||
|
||||
FontOptions options;
|
||||
options.Hinting = optionsOld.Hinting;
|
||||
options.Flags = optionsOld.Flags;
|
||||
options.RasterMode = FontRasterMode::Bitmap;
|
||||
context.Output.CustomData.Copy(&options);
|
||||
|
||||
return CopyChunk(context, 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
CreateAssetResult ImportFont::Import(CreateAssetContext& context)
|
||||
{
|
||||
// Base
|
||||
IMPORT_SETUP(FontAsset, 3);
|
||||
IMPORT_SETUP(FontAsset, 4);
|
||||
|
||||
// Setup header
|
||||
FontOptions options;
|
||||
options.Hinting = FontHinting::Default;
|
||||
options.Flags = FontFlags::AntiAliasing;
|
||||
options.RasterMode = FontRasterMode::Bitmap;
|
||||
context.Data.CustomData.Copy(&options);
|
||||
|
||||
// Open the file
|
||||
|
||||
@@ -596,7 +596,7 @@ void EngineImpl::InitLog()
|
||||
LOG(Info, "Compiled for Dev Environment");
|
||||
#endif
|
||||
#if defined(FLAXENGINE_BRANCH) && defined(FLAXENGINE_COMMIT)
|
||||
LOG(Info, "Version " FLAXENGINE_VERSION_TEXT ", " FLAXENGINE_BRANCH ", " FLAXENGINE_COMMIT);
|
||||
LOG(Info, "Version " FLAXENGINE_VERSION_TEXT ", {}, {}", StringAsUTF16<>(FLAXENGINE_BRANCH).Get(), StringAsUTF16<>(FLAXENGINE_COMMIT).Get());
|
||||
#else
|
||||
LOG(Info, "Version " FLAXENGINE_VERSION_TEXT);
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Level.h"
|
||||
#include "SceneQuery.h"
|
||||
#include "SceneObjectsFactory.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Scene/Scene.h"
|
||||
#include "Prefabs/Prefab.h"
|
||||
#include "Prefabs/PrefabManager.h"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "LargeWorlds.h"
|
||||
#include "SceneQuery.h"
|
||||
#include "SceneObjectsFactory.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Scene/Scene.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Deprecated.h"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
partial struct FontOptions
|
||||
@@ -11,7 +13,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if this object has the same value as <paramref name="other" />; otherwise, <c>false</c> </returns>
|
||||
public bool Equals(FontOptions other)
|
||||
{
|
||||
return Hinting == other.Hinting && Flags == other.Flags;
|
||||
return Hinting == other.Hinting && Flags == other.Flags && RasterMode == other.RasterMode;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -23,10 +25,7 @@ namespace FlaxEngine
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((int)Hinting * 397) ^ (int)Flags;
|
||||
}
|
||||
return HashCode.Combine((int)Hinting, (int)Flags, (int)RasterMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,7 +36,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if <paramref name="left" /> has the same value as <paramref name="right" />; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator ==(FontOptions left, FontOptions right)
|
||||
{
|
||||
return left.Hinting == right.Hinting && left.Flags == right.Flags;
|
||||
return left.Hinting == right.Hinting && left.Flags == right.Flags && left.RasterMode == right.RasterMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -48,7 +47,7 @@ namespace FlaxEngine
|
||||
/// <returns><c>true</c> if <paramref name="left" /> has a different value than <paramref name="right" />; otherwise,<c>false</c>.</returns>
|
||||
public static bool operator !=(FontOptions left, FontOptions right)
|
||||
{
|
||||
return left.Hinting != right.Hinting || left.Flags != right.Flags;
|
||||
return left.Hinting != right.Hinting || left.Flags != right.Flags || left.RasterMode != right.RasterMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,22 @@ API_ENUM(Attributes="Flags") enum class FontFlags : byte
|
||||
Italic = 4,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The font rasterization mode.
|
||||
/// </summary>
|
||||
API_ENUM() enum class FontRasterMode : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Use the default FreeType rasterizer to render font atlases.
|
||||
/// </summary>
|
||||
Bitmap,
|
||||
|
||||
/// <summary>
|
||||
/// Use the Multi-channel Signed Distance Field (MSDF) generator to render font atlases. Need to be rendered with a compatible material.
|
||||
/// </summary>
|
||||
MSDF,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(FontFlags);
|
||||
|
||||
/// <summary>
|
||||
@@ -76,7 +92,7 @@ API_STRUCT() struct FontOptions
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(FontOptions);
|
||||
|
||||
/// <summary>
|
||||
/// The hinting.
|
||||
/// The font hinting used when rendering characters.
|
||||
/// </summary>
|
||||
API_FIELD() FontHinting Hinting;
|
||||
|
||||
@@ -84,6 +100,11 @@ API_STRUCT() struct FontOptions
|
||||
/// The flags.
|
||||
/// </summary>
|
||||
API_FIELD() FontFlags Flags;
|
||||
|
||||
/// <summary>
|
||||
/// The font rasterization mode.
|
||||
/// </summary>
|
||||
API_FIELD() FontRasterMode RasterMode;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -91,7 +112,7 @@ API_STRUCT() struct FontOptions
|
||||
/// </summary>
|
||||
API_CLASS(NoSpawn) class FLAXENGINE_API FontAsset : public BinaryAsset
|
||||
{
|
||||
DECLARE_BINARY_ASSET_HEADER(FontAsset, 3);
|
||||
DECLARE_BINARY_ASSET_HEADER(FontAsset, 4);
|
||||
friend Font;
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Render2D/MSDFGenerator.h"
|
||||
#include "IncludeFreeType.h"
|
||||
#include <ThirdParty/freetype/ftsynth.h>
|
||||
#include <ThirdParty/freetype/ftbitmap.h>
|
||||
@@ -125,7 +126,11 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry)
|
||||
// Set load flags
|
||||
uint32 glyphFlags = FT_LOAD_NO_BITMAP;
|
||||
const bool useAA = EnumHasAnyFlags(options.Flags, FontFlags::AntiAliasing);
|
||||
if (useAA)
|
||||
if (options.RasterMode == FontRasterMode::MSDF)
|
||||
{
|
||||
glyphFlags |= FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
|
||||
}
|
||||
else if (useAA)
|
||||
{
|
||||
switch (options.Hinting)
|
||||
{
|
||||
@@ -185,75 +190,109 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry)
|
||||
FT_GlyphSlot_Oblique(face->glyph);
|
||||
}
|
||||
|
||||
// Render glyph to the bitmap
|
||||
FT_GlyphSlot glyph = face->glyph;
|
||||
FT_Render_Glyph(glyph, useAA ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
|
||||
|
||||
FT_Bitmap* bitmap = &glyph->bitmap;
|
||||
FT_Bitmap tmpBitmap;
|
||||
if (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
|
||||
int32 glyphWidth = 0;
|
||||
int32 glyphHeight = 0;
|
||||
if (options.RasterMode == FontRasterMode::Bitmap)
|
||||
{
|
||||
// Convert the bitmap to 8bpp grayscale
|
||||
FT_Bitmap_New(&tmpBitmap);
|
||||
FT_Bitmap_Convert(Library, bitmap, &tmpBitmap, 4);
|
||||
bitmap = &tmpBitmap;
|
||||
}
|
||||
ASSERT(bitmap && bitmap->pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
// Render glyph to the bitmap
|
||||
FT_GlyphSlot glyph = face->glyph;
|
||||
FT_Render_Glyph(glyph, useAA ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
|
||||
|
||||
// Fill the character data
|
||||
entry.AdvanceX = Convert26Dot6ToRoundedPixel<int16>(glyph->advance.x);
|
||||
entry.OffsetY = glyph->bitmap_top;
|
||||
entry.OffsetX = glyph->bitmap_left;
|
||||
entry.IsValid = true;
|
||||
entry.BearingY = Convert26Dot6ToRoundedPixel<int16>(glyph->metrics.horiBearingY);
|
||||
entry.Height = Convert26Dot6ToRoundedPixel<int16>(glyph->metrics.height);
|
||||
FT_Bitmap* bitmap = &glyph->bitmap;
|
||||
FT_Bitmap tmpBitmap;
|
||||
if (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
|
||||
{
|
||||
// Convert the bitmap to 8bpp grayscale
|
||||
FT_Bitmap_New(&tmpBitmap);
|
||||
FT_Bitmap_Convert(Library, bitmap, &tmpBitmap, 4);
|
||||
bitmap = &tmpBitmap;
|
||||
}
|
||||
ASSERT(bitmap && bitmap->pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
|
||||
// Allocate memory
|
||||
const int32 glyphWidth = bitmap->width;
|
||||
const int32 glyphHeight = bitmap->rows;
|
||||
GlyphImageData.Clear();
|
||||
GlyphImageData.Resize(glyphWidth * glyphHeight);
|
||||
// Fill the character data
|
||||
entry.AdvanceX = Convert26Dot6ToRoundedPixel<int16>(glyph->advance.x);
|
||||
entry.OffsetY = glyph->bitmap_top;
|
||||
entry.OffsetX = glyph->bitmap_left;
|
||||
entry.IsValid = true;
|
||||
entry.BearingY = Convert26Dot6ToRoundedPixel<int16>(glyph->metrics.horiBearingY);
|
||||
entry.Height = Convert26Dot6ToRoundedPixel<int16>(glyph->metrics.height);
|
||||
|
||||
// End for empty glyphs
|
||||
if (GlyphImageData.IsEmpty())
|
||||
{
|
||||
entry.TextureIndex = MAX_uint8;
|
||||
// Allocate memory
|
||||
glyphWidth = bitmap->width;
|
||||
glyphHeight = bitmap->rows;
|
||||
GlyphImageData.Clear();
|
||||
GlyphImageData.Resize(glyphWidth * glyphHeight);
|
||||
|
||||
// End for empty glyphs
|
||||
if (GlyphImageData.IsEmpty())
|
||||
{
|
||||
entry.TextureIndex = MAX_uint8;
|
||||
if (bitmap == &tmpBitmap)
|
||||
{
|
||||
FT_Bitmap_Done(Library, bitmap);
|
||||
bitmap = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy glyph data after rasterization (row by row)
|
||||
for (int32 row = 0; row < glyphHeight; row++)
|
||||
{
|
||||
Platform::MemoryCopy(&GlyphImageData[row * glyphWidth], &bitmap->buffer[row * bitmap->pitch], glyphWidth);
|
||||
}
|
||||
|
||||
// Normalize gray scale images not using 256 colors
|
||||
if (bitmap->num_grays != 256)
|
||||
{
|
||||
const int32 scale = 255 / (bitmap->num_grays - 1);
|
||||
for (byte& pixel : GlyphImageData)
|
||||
pixel *= scale;
|
||||
}
|
||||
|
||||
// Free temporary bitmap if used
|
||||
if (bitmap == &tmpBitmap)
|
||||
{
|
||||
FT_Bitmap_Done(Library, bitmap);
|
||||
bitmap = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy glyph data after rasterization (row by row)
|
||||
for (int32 row = 0; row < glyphHeight; row++)
|
||||
else
|
||||
{
|
||||
Platform::MemoryCopy(&GlyphImageData[row * glyphWidth], &bitmap->buffer[row * bitmap->pitch], glyphWidth);
|
||||
}
|
||||
// Generate bitmap for MSDF
|
||||
FT_GlyphSlot glyph = face->glyph;
|
||||
|
||||
// Normalize gray scale images not using 256 colors
|
||||
if (bitmap->num_grays != 256)
|
||||
{
|
||||
const int32 scale = 255 / (bitmap->num_grays - 1);
|
||||
for (byte& pixel : GlyphImageData)
|
||||
// Set advance in advance
|
||||
entry.AdvanceX = Convert26Dot6ToRoundedPixel<int16>(glyph->advance.x);
|
||||
|
||||
int16 msdf_top = 0;
|
||||
int16 msdf_left = 0;
|
||||
MSDFGenerator::GenerateMSDF(glyph, GlyphImageData, glyphWidth, glyphHeight, msdf_top, msdf_left);
|
||||
|
||||
// End for empty glyphs
|
||||
if (GlyphImageData.IsEmpty())
|
||||
{
|
||||
pixel *= scale;
|
||||
entry.TextureIndex = MAX_uint8;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Free temporary bitmap if used
|
||||
if (bitmap == &tmpBitmap)
|
||||
{
|
||||
FT_Bitmap_Done(Library, bitmap);
|
||||
bitmap = nullptr;
|
||||
// Fill the remaining character data
|
||||
entry.OffsetY = msdf_top;
|
||||
entry.OffsetX = msdf_left;
|
||||
entry.IsValid = true;
|
||||
entry.BearingY = Convert26Dot6ToRoundedPixel<int16>(glyph->metrics.horiBearingY);
|
||||
entry.Height = Convert26Dot6ToRoundedPixel<int16>(glyph->metrics.height);
|
||||
}
|
||||
|
||||
// Find atlas for the character texture
|
||||
PixelFormat atlasFormat = options.RasterMode == FontRasterMode::MSDF ? PixelFormat::R8G8B8A8_UNorm : PixelFormat::R8_UNorm;
|
||||
int32 atlasIndex = 0;
|
||||
const FontTextureAtlasSlot* slot = nullptr;
|
||||
for (; atlasIndex < Atlases.Count() && slot == nullptr; atlasIndex++)
|
||||
{
|
||||
if (Atlases[atlasIndex]->GetFormat() != atlasFormat)
|
||||
continue;
|
||||
slot = Atlases[atlasIndex]->AddEntry(glyphWidth, glyphHeight, GlyphImageData);
|
||||
}
|
||||
atlasIndex--;
|
||||
|
||||
// Check if there is no atlas for this character
|
||||
@@ -261,7 +300,7 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry)
|
||||
{
|
||||
// Create new atlas
|
||||
auto atlas = Content::CreateVirtualAsset<FontTextureAtlas>();
|
||||
atlas->Setup(PixelFormat::R8_UNorm, FontTextureAtlas::PaddingStyle::PadWithZero);
|
||||
atlas->Setup(atlasFormat, FontTextureAtlas::PaddingStyle::PadWithZero);
|
||||
Atlases.Add(atlas);
|
||||
atlasIndex++;
|
||||
|
||||
|
||||
@@ -105,6 +105,14 @@ public:
|
||||
return _height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the atlas pixel format.
|
||||
/// </summary>
|
||||
FORCE_INLINE PixelFormat GetFormat() const
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the atlas size.
|
||||
/// </summary>
|
||||
@@ -186,8 +194,8 @@ public:
|
||||
/// <summary>
|
||||
/// Returns glyph's bitmap data of the slot.
|
||||
/// </summary>
|
||||
/// <param name="slot">The slot in atlas.</param>
|
||||
/// <param name="width">The width of the slot.</param>
|
||||
/// <param name="slot">The slot in atlas.</param>
|
||||
/// <param name="width">The width of the slot.</param>
|
||||
/// <param name="height">The height of the slot.</param>
|
||||
/// <param name="stride">The stride of the slot.</param>
|
||||
/// <returns>The pointer to the bitmap data of the given slot.</returns>
|
||||
|
||||
142
Source/Engine/Render2D/MSDFGenerator.h
Normal file
142
Source/Engine/Render2D/MSDFGenerator.h
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include <ThirdParty/freetype/ftoutln.h>
|
||||
#include <ThirdParty/msdfgen/msdfgen.h>
|
||||
#include <ThirdParty/msdfgen/msdfgen/core/ShapeDistanceFinder.h>
|
||||
|
||||
class MSDFGenerator
|
||||
{
|
||||
using Point2 = msdfgen::Point2;
|
||||
using Shape = msdfgen::Shape;
|
||||
using Contour = msdfgen::Contour;
|
||||
using EdgeHolder = msdfgen::EdgeHolder;
|
||||
|
||||
static Point2 ftPoint2(const FT_Vector& vector, double scale)
|
||||
{
|
||||
return Point2(scale * vector.x, scale * vector.y);
|
||||
}
|
||||
|
||||
struct FtContext
|
||||
{
|
||||
double scale;
|
||||
Point2 position;
|
||||
Shape* shape;
|
||||
Contour* contour;
|
||||
};
|
||||
|
||||
static int ftMoveTo(const FT_Vector* to, void* user)
|
||||
{
|
||||
FtContext* context = reinterpret_cast<FtContext*>(user);
|
||||
if (!(context->contour && context->contour->edges.empty()))
|
||||
context->contour = &context->shape->addContour();
|
||||
context->position = ftPoint2(*to, context->scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftLineTo(const FT_Vector* to, void* user)
|
||||
{
|
||||
FtContext* context = reinterpret_cast<FtContext*>(user);
|
||||
Point2 endpoint = ftPoint2(*to, context->scale);
|
||||
if (endpoint != context->position)
|
||||
{
|
||||
context->contour->addEdge(EdgeHolder(context->position, endpoint));
|
||||
context->position = endpoint;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftConicTo(const FT_Vector* control, const FT_Vector* to, void* user)
|
||||
{
|
||||
FtContext* context = reinterpret_cast<FtContext*>(user);
|
||||
Point2 endpoint = ftPoint2(*to, context->scale);
|
||||
if (endpoint != context->position)
|
||||
{
|
||||
context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control, context->scale), endpoint));
|
||||
context->position = endpoint;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftCubicTo(const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* user)
|
||||
{
|
||||
FtContext* context = reinterpret_cast<FtContext*>(user);
|
||||
Point2 endpoint = ftPoint2(*to, context->scale);
|
||||
if (endpoint != context->position || msdfgen::crossProduct(ftPoint2(*control1, context->scale) - endpoint, ftPoint2(*control2, context->scale) - endpoint))
|
||||
{
|
||||
context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control1, context->scale), ftPoint2(*control2, context->scale), endpoint));
|
||||
context->position = endpoint;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void correctWinding(Shape& shape, Shape::Bounds& bounds)
|
||||
{
|
||||
Point2 p(bounds.l - (bounds.r - bounds.l) - 1, bounds.b - (bounds.t - bounds.b) - 1);
|
||||
double distance = msdfgen::SimpleTrueShapeDistanceFinder::oneShotDistance(shape, p);
|
||||
if (distance > 0)
|
||||
{
|
||||
for (auto& contour : shape.contours)
|
||||
contour.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static void GenerateMSDF(FT_GlyphSlot glyph, Array<byte>& output, int32& outputWidth, int32& outputHeight, int16& top, int16& left)
|
||||
{
|
||||
Shape shape;
|
||||
shape.contours.clear();
|
||||
shape.inverseYAxis = true;
|
||||
|
||||
FtContext context = { };
|
||||
context.scale = 1.0 / 64.0;
|
||||
context.shape = &shape;
|
||||
FT_Outline_Funcs ftFunctions;
|
||||
ftFunctions.move_to = &ftMoveTo;
|
||||
ftFunctions.line_to = &ftLineTo;
|
||||
ftFunctions.conic_to = &ftConicTo;
|
||||
ftFunctions.cubic_to = &ftCubicTo;
|
||||
ftFunctions.shift = 0;
|
||||
ftFunctions.delta = 0;
|
||||
FT_Outline_Decompose(&glyph->outline, &ftFunctions, &context);
|
||||
|
||||
shape.normalize();
|
||||
edgeColoringSimple(shape, 3.0);
|
||||
|
||||
// Todo: make this configurable
|
||||
// Also hard-coded in material: MSDFFontMaterial
|
||||
const double pxRange = 4.0;
|
||||
|
||||
Shape::Bounds bounds = shape.getBounds();
|
||||
int32 width = static_cast<int32>(Math::CeilToInt(bounds.r - bounds.l + pxRange));
|
||||
int32 height = static_cast<int32>(Math::CeilToInt(bounds.t - bounds.b + pxRange));
|
||||
msdfgen::Bitmap<float, 4> msdf(width, height);
|
||||
|
||||
auto transform = msdfgen::Vector2(Math::Ceil(-bounds.l + pxRange / 2.0), Math::Ceil(-bounds.b + pxRange / 2.0));
|
||||
|
||||
msdfgen::SDFTransformation t(msdfgen::Projection(1.0, transform), msdfgen::Range(pxRange));
|
||||
correctWinding(shape, bounds);
|
||||
generateMTSDF(msdf, shape, t);
|
||||
|
||||
output.Resize(width * height * 4);
|
||||
|
||||
const msdfgen::BitmapConstRef<float, 4>& bitmap = msdf;
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
output[(y * width + x) * 4] = msdfgen::pixelFloatToByte(bitmap(x, y)[0]);
|
||||
output[(y * width + x) * 4 + 1] = msdfgen::pixelFloatToByte(bitmap(x, y)[1]);
|
||||
output[(y * width + x) * 4 + 2] = msdfgen::pixelFloatToByte(bitmap(x, y)[2]);
|
||||
output[(y * width + x) * 4 + 3] = msdfgen::pixelFloatToByte(bitmap(x, y)[3]);
|
||||
}
|
||||
}
|
||||
outputWidth = width;
|
||||
outputHeight = height;
|
||||
top = height - static_cast<int16>(transform.y);
|
||||
left = -static_cast<int16>(transform.x);
|
||||
}
|
||||
};
|
||||
@@ -14,6 +14,7 @@ public class Render2D : EngineModule
|
||||
base.Setup(options);
|
||||
|
||||
options.PrivateDependencies.Add("freetype");
|
||||
options.PrivateDependencies.Add("msdfgen");
|
||||
|
||||
options.PrivateDefinitions.Add("RENDER2D_USE_LINE_AA");
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Render2D.h"
|
||||
#include "Font.h"
|
||||
#include "FontAsset.h"
|
||||
#include "FontManager.h"
|
||||
#include "FontTextureAtlas.h"
|
||||
#include "RotatedRectangle.h"
|
||||
@@ -74,6 +75,7 @@ enum class DrawCallType : byte
|
||||
FillTexture,
|
||||
FillTexturePoint,
|
||||
DrawChar,
|
||||
DrawCharMSDF,
|
||||
DrawCharMaterial,
|
||||
Custom,
|
||||
Material,
|
||||
@@ -164,6 +166,7 @@ struct CachedPSO
|
||||
GPUPipelineState* PS_Color_NoAlpha;
|
||||
|
||||
GPUPipelineState* PS_Font;
|
||||
GPUPipelineState* PS_FontMSDF;
|
||||
|
||||
GPUPipelineState* PS_BlurH;
|
||||
GPUPipelineState* PS_BlurV;
|
||||
@@ -455,6 +458,7 @@ CanDrawCallCallback CanDrawCallBatch[] =
|
||||
CanDrawCallCallbackTexture, // FillTexture,
|
||||
CanDrawCallCallbackTexture, // FillTexturePoint,
|
||||
CanDrawCallCallbackChar, // DrawChar,
|
||||
CanDrawCallCallbackChar, // DrawCharMSDF,
|
||||
CanDrawCallCallbackCharMaterial, // DrawCharMaterial,
|
||||
CanDrawCallCallbackFalse, // Custom,
|
||||
CanDrawCallCallbackMaterial, // Material,
|
||||
@@ -517,6 +521,12 @@ bool CachedPSO::Init(GPUShader* shader, bool useDepth)
|
||||
if (PS_Font->Init(desc))
|
||||
return true;
|
||||
//
|
||||
desc.BlendMode = BlendingMode::AlphaBlend;
|
||||
desc.PS = shader->GetPS("PS_FontMSDF");
|
||||
PS_FontMSDF = GPUDevice::Instance->CreatePipelineState();
|
||||
if (PS_FontMSDF->Init(desc))
|
||||
return true;
|
||||
//
|
||||
desc.PS = shader->GetPS("PS_LineAA");
|
||||
PS_LineAA = GPUDevice::Instance->CreatePipelineState();
|
||||
if (PS_LineAA->Init(desc))
|
||||
@@ -994,6 +1004,10 @@ void DrawBatch(int32 startIndex, int32 count)
|
||||
Context->BindSR(0, d.AsChar.Tex);
|
||||
Context->SetState(CurrentPso->PS_Font);
|
||||
break;
|
||||
case DrawCallType::DrawCharMSDF:
|
||||
Context->BindSR(0, d.AsChar.Tex);
|
||||
Context->SetState(CurrentPso->PS_FontMSDF);
|
||||
break;
|
||||
case DrawCallType::DrawCharMaterial:
|
||||
{
|
||||
// Apply and bind material
|
||||
@@ -1186,7 +1200,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color,
|
||||
}
|
||||
else
|
||||
{
|
||||
drawCall.Type = DrawCallType::DrawChar;
|
||||
drawCall.Type = font->GetAsset()->GetOptions().RasterMode == FontRasterMode::MSDF ? DrawCallType::DrawCharMSDF : DrawCallType::DrawChar;
|
||||
drawCall.AsChar.Mat = nullptr;
|
||||
}
|
||||
Float2 pointer = location;
|
||||
@@ -1305,7 +1319,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color,
|
||||
}
|
||||
else
|
||||
{
|
||||
drawCall.Type = DrawCallType::DrawChar;
|
||||
drawCall.Type = font->GetAsset()->GetOptions().RasterMode == FontRasterMode::MSDF ? DrawCallType::DrawCharMSDF : DrawCallType::DrawChar;
|
||||
drawCall.AsChar.Mat = nullptr;
|
||||
}
|
||||
for (int32 lineIndex = 0; lineIndex < Lines.Count(); lineIndex++)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
class GPUTexture;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
/// <summary>
|
||||
/// Object serialization modification base class. Allows to extend the serialization process by custom effects like object ids mapping.
|
||||
@@ -12,17 +11,18 @@
|
||||
class FLAXENGINE_API ISerializeModifier
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Number of engine build when data was serialized. Useful to upgrade data from the older storage format.
|
||||
/// </summary>
|
||||
uint32 EngineBuild = FLAXENGINE_VERSION_BUILD;
|
||||
uint32 EngineBuild;
|
||||
|
||||
// Utility for scene deserialization to track currently mapped in Prefab Instance object IDs into IdsMapping.
|
||||
int32 CurrentInstance = -1;
|
||||
int32 CurrentInstance;
|
||||
|
||||
/// <summary>
|
||||
/// The object IDs mapping. Key is a serialized object id, value is mapped value to use.
|
||||
/// </summary>
|
||||
Dictionary<Guid, Guid> IdsMapping;
|
||||
|
||||
ISerializeModifier();
|
||||
};
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
#include "Engine/Content/Asset.h"
|
||||
#include "Engine/Level/SceneObject.h"
|
||||
#include "Engine/Utilities/Encryption.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
ISerializeModifier::ISerializeModifier()
|
||||
{
|
||||
EngineBuild = FLAXENGINE_VERSION_BUILD;
|
||||
CurrentInstance = -1;
|
||||
}
|
||||
|
||||
void ISerializable::DeserializeIfExists(DeserializeStream& stream, const char* memberName, ISerializeModifier* modifier)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "JsonWriters.h"
|
||||
#include "JsonSerializer.h"
|
||||
#include "MemoryReadStream.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Engine/Core/Types/CommonValue.h"
|
||||
#include "Engine/Core/Types/Variant.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
|
||||
@@ -148,7 +148,6 @@ void ShadowsOfMordor::Builder::Dispose()
|
||||
#include "Engine/Serialization/FileWriteStream.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
namespace ShadowsOfMordor
|
||||
{
|
||||
|
||||
BIN
Source/Platforms/Android/Binaries/ThirdParty/ARM64/libmsdfgen-core.a
LFS
vendored
Normal file
BIN
Source/Platforms/Android/Binaries/ThirdParty/ARM64/libmsdfgen-core.a
LFS
vendored
Normal file
Binary file not shown.
BIN
Source/Platforms/Windows/Binaries/ThirdParty/x64/msdfgen-core.lib
LFS
vendored
Normal file
BIN
Source/Platforms/Windows/Binaries/ThirdParty/x64/msdfgen-core.lib
LFS
vendored
Normal file
Binary file not shown.
@@ -92,7 +92,17 @@ float4 PS_Font(VS2PS input) : SV_Target0
|
||||
PerformClipping(input);
|
||||
|
||||
float4 color = input.Color;
|
||||
color.a *= Image.Sample(SamplerLinearClamp, input.TexCoord).r;
|
||||
color.a *= SampleFont(Image, input.TexCoord);
|
||||
return color;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_FontMSDF(VS2PS input) : SV_Target0
|
||||
{
|
||||
PerformClipping(input);
|
||||
|
||||
float4 color = input.Color;
|
||||
color.a *= SampleFontMSDF(Image, input.TexCoord);
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,4 +54,52 @@ void PerformClipping(VS2PS input)
|
||||
PerformClipping(input.ClipOriginAndPos.xy, input.ClipOriginAndPos.zw, input.ClipExtents);
|
||||
}
|
||||
|
||||
float SampleFont(Texture2D font, float2 uv)
|
||||
{
|
||||
return font.Sample(SamplerLinearClamp, uv).r;
|
||||
}
|
||||
|
||||
float GetFontMSDFMedian(Texture2D font, float2 uv)
|
||||
{
|
||||
float4 msd = font.Sample(SamplerLinearClamp, uv);
|
||||
return max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
|
||||
}
|
||||
|
||||
float GetFontMSDFMedian(float4 msd)
|
||||
{
|
||||
return max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
|
||||
}
|
||||
|
||||
float GetFontMSDFPixelRange(Texture2D font, float2 uv)
|
||||
{
|
||||
uint width, height;
|
||||
font.GetDimensions(width, height);
|
||||
float pxRange = 4.0f; // Must match C++ code
|
||||
float unitRange = float2(pxRange, pxRange) / float2(width, height);
|
||||
|
||||
float2 dx = ddx(uv);
|
||||
float2 dy = ddy(uv);
|
||||
float2 screenTexSize = rsqrt(dx * dx + dy * dy);
|
||||
return max(0.5f * dot(screenTexSize, unitRange), 1.0f);
|
||||
}
|
||||
|
||||
float SampleFontMSDF(Texture2D font, float2 uv)
|
||||
{
|
||||
float sd = GetFontMSDFMedian(font, uv);
|
||||
float screenPxRange = GetFontMSDFPixelRange(font, uv);
|
||||
float screenPxDist = screenPxRange * (sd - 0.5f);
|
||||
return saturate(screenPxDist + 0.5f);
|
||||
}
|
||||
|
||||
float SampleFontMSDFOutline(Texture2D font, float2 uv, float thickness)
|
||||
{
|
||||
float4 msd = font.Sample(SamplerLinearClamp, uv);
|
||||
float sd = max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
|
||||
float screenPxRange = GetFontMSDFPixelRange(font, uv);
|
||||
float thick = clamp(thickness, 0.0, screenPxRange * 0.5 - 1.0) / screenPxRange;
|
||||
float outline = saturate((min(sd, msd.a) - 0.5 + thick) * screenPxRange + 0.5);
|
||||
outline *= 1 - saturate(screenPxRange * (sd - 0.5f) + 0.5f);
|
||||
return outline;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
21
Source/ThirdParty/msdfgen/LICENSE.txt
vendored
Normal file
21
Source/ThirdParty/msdfgen/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014 - 2025 Viktor Chlumsky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
45
Source/ThirdParty/msdfgen/msdfgen.Build.cs
vendored
Normal file
45
Source/ThirdParty/msdfgen/msdfgen.Build.cs
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.IO;
|
||||
using Flax.Build;
|
||||
using Flax.Build.NativeCpp;
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/Chlumsky/msdfgen
|
||||
/// </summary>
|
||||
public class msdfgen : DepsModule
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "LICENSE.txt";
|
||||
|
||||
// Merge third-party modules into engine binary
|
||||
BinaryModuleName = "FlaxEngine";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Setup(BuildOptions options)
|
||||
{
|
||||
base.Setup(options);
|
||||
|
||||
var depsRoot = options.DepsFolder;
|
||||
switch (options.Platform.Target)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
options.OutputFiles.Add(Path.Combine(depsRoot, "msdfgen-core.lib"));
|
||||
break;
|
||||
case TargetPlatform.Linux:
|
||||
case TargetPlatform.Mac:
|
||||
case TargetPlatform.Android:
|
||||
options.OutputFiles.Add(Path.Combine(depsRoot, "libmsdfgen-core.a"));
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||
}
|
||||
|
||||
options.PublicIncludePaths.Add(Path.Combine(Globals.EngineRoot, "Source/ThirdParty/msdfgen"));
|
||||
}
|
||||
}
|
||||
4
Source/ThirdParty/msdfgen/msdfgen.h
vendored
Normal file
4
Source/ThirdParty/msdfgen/msdfgen.h
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "msdfgen/msdfgen.h"
|
||||
60
Source/ThirdParty/msdfgen/msdfgen/core/Bitmap.h
vendored
Normal file
60
Source/ThirdParty/msdfgen/msdfgen/core/Bitmap.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "YAxisOrientation.h"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// A 2D image bitmap with N channels of type T. Pixel memory is managed by the class.
|
||||
template <typename T, int N = 1>
|
||||
class Bitmap {
|
||||
|
||||
public:
|
||||
Bitmap();
|
||||
Bitmap(int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
explicit Bitmap(const BitmapConstRef<T, N> &orig);
|
||||
explicit Bitmap(const BitmapConstSection<T, N> &orig);
|
||||
Bitmap(const Bitmap<T, N> &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
Bitmap(Bitmap<T, N> &&orig);
|
||||
#endif
|
||||
~Bitmap();
|
||||
Bitmap<T, N> &operator=(const BitmapConstRef<T, N> &orig);
|
||||
Bitmap<T, N> &operator=(const BitmapConstSection<T, N> &orig);
|
||||
Bitmap<T, N> &operator=(const Bitmap<T, N> &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
Bitmap<T, N> &operator=(Bitmap<T, N> &&orig);
|
||||
#endif
|
||||
/// Bitmap width in pixels.
|
||||
int width() const;
|
||||
/// Bitmap height in pixels.
|
||||
int height() const;
|
||||
T *operator()(int x, int y);
|
||||
const T *operator()(int x, int y) const;
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
explicit operator T *();
|
||||
explicit operator const T *() const;
|
||||
#else
|
||||
operator T *();
|
||||
operator const T *() const;
|
||||
#endif
|
||||
operator BitmapRef<T, N>();
|
||||
operator BitmapConstRef<T, N>() const;
|
||||
operator BitmapSection<T, N>();
|
||||
operator BitmapConstSection<T, N>() const;
|
||||
/// Returns a reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
BitmapSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax);
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const;
|
||||
|
||||
private:
|
||||
T *pixels;
|
||||
int w, h;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "Bitmap.hpp"
|
||||
172
Source/ThirdParty/msdfgen/msdfgen/core/Bitmap.hpp
vendored
Normal file
172
Source/ThirdParty/msdfgen/msdfgen/core/Bitmap.hpp
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
#include "Bitmap.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap() : pixels(NULL), w(0), h(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(int width, int height, YAxisOrientation yOrientation) : w(width), h(height), yOrientation(yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(const BitmapConstRef<T, N> &orig) : w(orig.width), h(orig.height), yOrientation(orig.yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(const BitmapConstSection<T, N> &orig) : w(orig.width), h(orig.height), yOrientation(orig.yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
T *dst = pixels;
|
||||
const T *src = orig.pixels;
|
||||
int rowLength = N*w;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
memcpy(dst, src, sizeof(T)*rowLength);
|
||||
dst += rowLength;
|
||||
src += orig.rowStride;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(const Bitmap<T, N> &orig) : w(orig.w), h(orig.h), yOrientation(orig.yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(Bitmap<T, N> &&orig) : pixels(orig.pixels), w(orig.w), h(orig.h), yOrientation(orig.yOrientation) {
|
||||
orig.pixels = NULL;
|
||||
orig.w = 0, orig.h = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::~Bitmap() {
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(const BitmapConstRef<T, N> &orig) {
|
||||
if (pixels != orig.pixels) {
|
||||
delete[] pixels;
|
||||
w = orig.width, h = orig.height;
|
||||
yOrientation = orig.yOrientation;
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(const BitmapConstSection<T, N> &orig) {
|
||||
if (orig.pixels && orig.pixels >= pixels && orig.pixels < pixels+N*w*h)
|
||||
return *this = Bitmap<T, N>(orig);
|
||||
delete[] pixels;
|
||||
w = orig.width, h = orig.height;
|
||||
yOrientation = orig.yOrientation;
|
||||
pixels = new T[N*w*h];
|
||||
T *dst = pixels;
|
||||
const T *src = orig.pixels;
|
||||
int rowLength = N*w;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
memcpy(dst, src, sizeof(T)*rowLength);
|
||||
dst += rowLength;
|
||||
src += orig.rowStride;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(const Bitmap<T, N> &orig) {
|
||||
if (this != &orig) {
|
||||
delete[] pixels;
|
||||
w = orig.w, h = orig.h;
|
||||
yOrientation = orig.yOrientation;
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(Bitmap<T, N> &&orig) {
|
||||
if (this != &orig) {
|
||||
delete[] pixels;
|
||||
pixels = orig.pixels;
|
||||
w = orig.w, h = orig.h;
|
||||
yOrientation = orig.yOrientation;
|
||||
orig.pixels = NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, int N>
|
||||
int Bitmap<T, N>::width() const {
|
||||
return w;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
int Bitmap<T, N>::height() const {
|
||||
return h;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
T *Bitmap<T, N>::operator()(int x, int y) {
|
||||
return pixels+N*(w*y+x);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
const T *Bitmap<T, N>::operator()(int x, int y) const {
|
||||
return pixels+N*(w*y+x);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator T *() {
|
||||
return pixels;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator const T *() const {
|
||||
return pixels;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapRef<T, N>() {
|
||||
return BitmapRef<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapConstRef<T, N>() const {
|
||||
return BitmapConstRef<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapSection<T, N>() {
|
||||
return BitmapSection<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapConstSection<T, N>() const {
|
||||
return BitmapConstSection<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapSection<T, N> Bitmap<T, N>::getSection(int xMin, int yMin, int xMax, int yMax) {
|
||||
return BitmapSection<T, N>(pixels+N*(w*yMin+xMin), xMax-xMin, yMax-yMin, N*w, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapConstSection<T, N> Bitmap<T, N>::getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+N*(w*yMin+xMin), xMax-xMin, yMax-yMin, N*w, yOrientation);
|
||||
}
|
||||
|
||||
}
|
||||
154
Source/ThirdParty/msdfgen/msdfgen/core/BitmapRef.hpp
vendored
Normal file
154
Source/ThirdParty/msdfgen/msdfgen/core/BitmapRef.hpp
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "YAxisOrientation.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object.
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapRef;
|
||||
/// Constant reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object.
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapConstRef;
|
||||
/// Reference to a 2D image bitmap with non-contiguous rows of pixels. Pixel storage not owned or managed by the object. Can represent e.g. a section of a larger bitmap, bitmap with padded rows, or vertically flipped bitmap (rowStride can be negative).
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapSection;
|
||||
/// Constant reference to a 2D image bitmap with non-contiguous rows of pixels. Pixel storage not owned or managed by the object. Can represent e.g. a section of a larger bitmap, bitmap with padded rows, or vertically flipped bitmap (rowStride can be negative).
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapConstSection;
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapRef {
|
||||
|
||||
T *pixels;
|
||||
int width, height;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapRef() : pixels(NULL), width(0), height(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapRef(T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), yOrientation(yOrientation) { }
|
||||
|
||||
inline T *operator()(int x, int y) const {
|
||||
return pixels+N*(width*y+x);
|
||||
}
|
||||
|
||||
/// Returns a reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapSection<T, N>(pixels+N*(width*yMin+xMin), xMax-xMin, yMax-yMin, N*width, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+N*(width*yMin+xMin), xMax-xMin, yMax-yMin, N*width, yOrientation);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapConstRef {
|
||||
|
||||
const T *pixels;
|
||||
int width, height;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapConstRef() : pixels(NULL), width(0), height(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapConstRef(const T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), yOrientation(yOrientation) { }
|
||||
inline BitmapConstRef(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), yOrientation(orig.yOrientation) { }
|
||||
|
||||
inline const T *operator()(int x, int y) const {
|
||||
return pixels+N*(width*y+x);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+N*(width*yMin+xMin), xMax-xMin, yMax-yMin, N*width, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return getSection(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapSection {
|
||||
|
||||
T *pixels;
|
||||
int width, height;
|
||||
/// Specifies the difference between the beginnings of adjacent pixel rows as the number of T elements, can be negative.
|
||||
int rowStride;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapSection() : pixels(NULL), width(0), height(0), rowStride(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapSection(T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(N*width), yOrientation(yOrientation) { }
|
||||
inline BitmapSection(T *pixels, int width, int height, int rowStride, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(rowStride), yOrientation(yOrientation) { }
|
||||
inline BitmapSection(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(N*orig.width), yOrientation(orig.yOrientation) { }
|
||||
|
||||
inline T *operator()(int x, int y) const {
|
||||
return pixels+rowStride*y+N*x;
|
||||
}
|
||||
|
||||
/// Returns a reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapSection<T, N>(pixels+rowStride*yMin+N*xMin, xMax-xMin, yMax-yMin, rowStride, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+rowStride*yMin+N*xMin, xMax-xMin, yMax-yMin, rowStride, yOrientation);
|
||||
}
|
||||
|
||||
/// Makes sure that the section's Y-axis orientation matches the argument by potentially reordering its rows.
|
||||
inline void reorient(YAxisOrientation newYAxisOrientation) {
|
||||
if (yOrientation != newYAxisOrientation) {
|
||||
pixels += rowStride*(height-1);
|
||||
rowStride = -rowStride;
|
||||
yOrientation = newYAxisOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapConstSection {
|
||||
|
||||
const T *pixels;
|
||||
int width, height;
|
||||
/// Specifies the difference between the beginnings of adjacent pixel rows as the number of T elements, can be negative.
|
||||
int rowStride;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapConstSection() : pixels(NULL), width(0), height(0), rowStride(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapConstSection(const T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(N*width), yOrientation(yOrientation) { }
|
||||
inline BitmapConstSection(const T *pixels, int width, int height, int rowStride, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(rowStride), yOrientation(yOrientation) { }
|
||||
inline BitmapConstSection(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(N*orig.width), yOrientation(orig.yOrientation) { }
|
||||
inline BitmapConstSection(const BitmapConstRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(N*orig.width), yOrientation(orig.yOrientation) { }
|
||||
inline BitmapConstSection(const BitmapSection<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(orig.rowStride), yOrientation(orig.yOrientation) { }
|
||||
|
||||
inline const T *operator()(int x, int y) const {
|
||||
return pixels+rowStride*y+N*x;
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+rowStride*yMin+N*xMin, xMax-xMin, yMax-yMin, rowStride, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return getSection(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
/// Makes sure that the section's Y-axis orientation matches the argument by potentially reordering its rows.
|
||||
inline void reorient(YAxisOrientation newYAxisOrientation) {
|
||||
if (yOrientation != newYAxisOrientation) {
|
||||
pixels += rowStride*(height-1);
|
||||
rowStride = -rowStride;
|
||||
yOrientation = newYAxisOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
34
Source/ThirdParty/msdfgen/msdfgen/core/Contour.h
vendored
Normal file
34
Source/ThirdParty/msdfgen/msdfgen/core/Contour.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "EdgeHolder.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// A single closed contour of a shape.
|
||||
class Contour {
|
||||
|
||||
public:
|
||||
/// The sequence of edges that make up the contour.
|
||||
std::vector<EdgeHolder> edges;
|
||||
|
||||
/// Adds an edge to the contour.
|
||||
void addEdge(const EdgeHolder &edge);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
void addEdge(EdgeHolder &&edge);
|
||||
#endif
|
||||
/// Creates a new edge in the contour and returns its reference.
|
||||
EdgeHolder &addEdge();
|
||||
/// Adjusts the bounding box to fit the contour.
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
/// Adjusts the bounding box to fit the contour border's mitered corners.
|
||||
void boundMiters(double &xMin, double &yMin, double &xMax, double &yMax, double border, double miterLimit, int polarity) const;
|
||||
/// Computes the winding of the contour. Returns 1 if positive, -1 if negative.
|
||||
int winding() const;
|
||||
/// Reverses the sequence of edges on the contour.
|
||||
void reverse();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
36
Source/ThirdParty/msdfgen/msdfgen/core/DistanceMapping.h
vendored
Normal file
36
Source/ThirdParty/msdfgen/msdfgen/core/DistanceMapping.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Range.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Linear transformation of signed distance values.
|
||||
class DistanceMapping {
|
||||
|
||||
public:
|
||||
/// Explicitly designates value as distance delta rather than an absolute distance.
|
||||
class Delta {
|
||||
public:
|
||||
double value;
|
||||
inline explicit Delta(double distanceDelta) : value(distanceDelta) { }
|
||||
inline operator double() const { return value; }
|
||||
};
|
||||
|
||||
static DistanceMapping inverse(Range range);
|
||||
|
||||
DistanceMapping();
|
||||
DistanceMapping(Range range);
|
||||
double operator()(double d) const;
|
||||
double operator()(Delta d) const;
|
||||
DistanceMapping inverse() const;
|
||||
|
||||
private:
|
||||
double scale;
|
||||
double translate;
|
||||
|
||||
inline DistanceMapping(double scale, double translate) : scale(scale), translate(translate) { }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
20
Source/ThirdParty/msdfgen/msdfgen/core/EdgeColor.h
vendored
Normal file
20
Source/ThirdParty/msdfgen/msdfgen/core/EdgeColor.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Edge color specifies which color channels an edge belongs to.
|
||||
enum EdgeColor {
|
||||
BLACK = 0,
|
||||
RED = 1,
|
||||
GREEN = 2,
|
||||
YELLOW = 3,
|
||||
BLUE = 4,
|
||||
MAGENTA = 5,
|
||||
CYAN = 6,
|
||||
WHITE = 7
|
||||
};
|
||||
|
||||
}
|
||||
41
Source/ThirdParty/msdfgen/msdfgen/core/EdgeHolder.h
vendored
Normal file
41
Source/ThirdParty/msdfgen/msdfgen/core/EdgeHolder.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "edge-segments.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Container for a single edge of dynamic type.
|
||||
class EdgeHolder {
|
||||
|
||||
public:
|
||||
/// Swaps the edges held by a and b.
|
||||
static void swap(EdgeHolder &a, EdgeHolder &b);
|
||||
|
||||
inline EdgeHolder() : edgeSegment() { }
|
||||
inline EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { }
|
||||
inline EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, edgeColor)) { }
|
||||
inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, edgeColor)) { }
|
||||
inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, p3, edgeColor)) { }
|
||||
EdgeHolder(const EdgeHolder &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
EdgeHolder(EdgeHolder &&orig);
|
||||
#endif
|
||||
~EdgeHolder();
|
||||
EdgeHolder &operator=(const EdgeHolder &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
EdgeHolder &operator=(EdgeHolder &&orig);
|
||||
#endif
|
||||
EdgeSegment &operator*();
|
||||
const EdgeSegment &operator*() const;
|
||||
EdgeSegment *operator->();
|
||||
const EdgeSegment *operator->() const;
|
||||
operator EdgeSegment *();
|
||||
operator const EdgeSegment *() const;
|
||||
|
||||
private:
|
||||
EdgeSegment *edgeSegment;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
55
Source/ThirdParty/msdfgen/msdfgen/core/MSDFErrorCorrection.h
vendored
Normal file
55
Source/ThirdParty/msdfgen/msdfgen/core/MSDFErrorCorrection.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SDFTransformation.h"
|
||||
#include "Shape.h"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Performs error correction on a computed MSDF to eliminate interpolation artifacts. This is a low-level class, you may want to use the API in msdf-error-correction.h instead.
|
||||
class MSDFErrorCorrection {
|
||||
|
||||
public:
|
||||
/// Stencil flags.
|
||||
enum Flags {
|
||||
/// Texel marked as potentially causing interpolation errors.
|
||||
ERROR = 1,
|
||||
/// Texel marked as protected. Protected texels are only given the error flag if they cause inversion artifacts.
|
||||
PROTECTED = 2
|
||||
};
|
||||
|
||||
MSDFErrorCorrection();
|
||||
explicit MSDFErrorCorrection(const BitmapSection<byte, 1> &stencil, const SDFTransformation &transformation);
|
||||
/// Sets the minimum ratio between the actual and maximum expected distance delta to be considered an error.
|
||||
void setMinDeviationRatio(double minDeviationRatio);
|
||||
/// Sets the minimum ratio between the pre-correction distance error and the post-correction distance error.
|
||||
void setMinImproveRatio(double minImproveRatio);
|
||||
/// Flags all texels that are interpolated at corners as protected.
|
||||
void protectCorners(const Shape &shape);
|
||||
/// Flags all texels that contribute to edges as protected.
|
||||
template <int N>
|
||||
void protectEdges(const BitmapConstSection<float, N> &sdf);
|
||||
/// Flags all texels as protected.
|
||||
void protectAll();
|
||||
/// Flags texels that are expected to cause interpolation artifacts based on analysis of the SDF only.
|
||||
template <int N>
|
||||
void findErrors(const BitmapConstSection<float, N> &sdf);
|
||||
/// Flags texels that are expected to cause interpolation artifacts based on analysis of the SDF and comparison with the exact shape distance.
|
||||
template <template <typename> class ContourCombiner, int N>
|
||||
void findErrors(BitmapConstSection<float, N> sdf, const Shape &shape);
|
||||
/// Modifies the MSDF so that all texels with the error flag are converted to single-channel.
|
||||
template <int N>
|
||||
void apply(BitmapSection<float, N> sdf) const;
|
||||
/// Returns the stencil in its current state (see Flags).
|
||||
BitmapConstSection<byte, 1> getStencil() const;
|
||||
|
||||
private:
|
||||
BitmapSection<byte, 1> stencil;
|
||||
SDFTransformation transformation;
|
||||
double minDeviationRatio;
|
||||
double minImproveRatio;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
37
Source/ThirdParty/msdfgen/msdfgen/core/Projection.h
vendored
Normal file
37
Source/ThirdParty/msdfgen/msdfgen/core/Projection.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// A transformation from shape coordinates to pixel coordinates.
|
||||
class Projection {
|
||||
|
||||
public:
|
||||
Projection();
|
||||
Projection(const Vector2 &scale, const Vector2 &translate);
|
||||
/// Converts the shape coordinate to pixel coordinate.
|
||||
Point2 project(const Point2 &coord) const;
|
||||
/// Converts the pixel coordinate to shape coordinate.
|
||||
Point2 unproject(const Point2 &coord) const;
|
||||
/// Converts the vector to pixel coordinate space.
|
||||
Vector2 projectVector(const Vector2 &vector) const;
|
||||
/// Converts the vector from pixel coordinate space.
|
||||
Vector2 unprojectVector(const Vector2 &vector) const;
|
||||
/// Converts the X-coordinate from shape to pixel coordinate space.
|
||||
double projectX(double x) const;
|
||||
/// Converts the Y-coordinate from shape to pixel coordinate space.
|
||||
double projectY(double y) const;
|
||||
/// Converts the X-coordinate from pixel to shape coordinate space.
|
||||
double unprojectX(double x) const;
|
||||
/// Converts the Y-coordinate from pixel to shape coordinate space.
|
||||
double unprojectY(double y) const;
|
||||
|
||||
private:
|
||||
Vector2 scale;
|
||||
Vector2 translate;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
46
Source/ThirdParty/msdfgen/msdfgen/core/Range.hpp
vendored
Normal file
46
Source/ThirdParty/msdfgen/msdfgen/core/Range.hpp
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/**
|
||||
* Represents the range between two real values.
|
||||
* For example, the range of representable signed distances.
|
||||
*/
|
||||
struct Range {
|
||||
|
||||
double lower, upper;
|
||||
|
||||
inline Range(double symmetricalWidth = 0) : lower(-.5*symmetricalWidth), upper(.5*symmetricalWidth) { }
|
||||
|
||||
inline Range(double lowerBound, double upperBound) : lower(lowerBound), upper(upperBound) { }
|
||||
|
||||
inline Range &operator*=(double factor) {
|
||||
lower *= factor;
|
||||
upper *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Range &operator/=(double divisor) {
|
||||
lower /= divisor;
|
||||
upper /= divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Range operator*(double factor) const {
|
||||
return Range(lower*factor, upper*factor);
|
||||
}
|
||||
|
||||
inline Range operator/(double divisor) const {
|
||||
return Range(lower/divisor, upper/divisor);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline Range operator*(double factor, const Range &range) {
|
||||
return Range(factor*range.lower, factor*range.upper);
|
||||
}
|
||||
|
||||
}
|
||||
24
Source/ThirdParty/msdfgen/msdfgen/core/SDFTransformation.h
vendored
Normal file
24
Source/ThirdParty/msdfgen/msdfgen/core/SDFTransformation.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Projection.h"
|
||||
#include "DistanceMapping.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/**
|
||||
* Full signed distance field transformation specifies both spatial transformation (Projection)
|
||||
* as well as distance value transformation (DistanceMapping).
|
||||
*/
|
||||
class SDFTransformation : public Projection {
|
||||
|
||||
public:
|
||||
DistanceMapping distanceMapping;
|
||||
|
||||
inline SDFTransformation() { }
|
||||
|
||||
inline SDFTransformation(const Projection &projection, const DistanceMapping &distanceMapping) : Projection(projection), distanceMapping(distanceMapping) { }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
56
Source/ThirdParty/msdfgen/msdfgen/core/Scanline.h
vendored
Normal file
56
Source/ThirdParty/msdfgen/msdfgen/core/Scanline.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Fill rule dictates how intersection total is interpreted during rasterization.
|
||||
enum FillRule {
|
||||
FILL_NONZERO,
|
||||
FILL_ODD, // "even-odd"
|
||||
FILL_POSITIVE,
|
||||
FILL_NEGATIVE
|
||||
};
|
||||
|
||||
/// Resolves the number of intersection into a binary fill value based on fill rule.
|
||||
bool interpretFillRule(int intersections, FillRule fillRule);
|
||||
|
||||
/// Represents a horizontal scanline intersecting a shape.
|
||||
class Scanline {
|
||||
|
||||
public:
|
||||
/// An intersection with the scanline.
|
||||
struct Intersection {
|
||||
/// X coordinate.
|
||||
double x;
|
||||
/// Normalized Y direction of the oriented edge at the point of intersection.
|
||||
int direction;
|
||||
};
|
||||
|
||||
static double overlap(const Scanline &a, const Scanline &b, double xFrom, double xTo, FillRule fillRule);
|
||||
|
||||
Scanline();
|
||||
/// Populates the intersection list.
|
||||
void setIntersections(const std::vector<Intersection> &intersections);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
void setIntersections(std::vector<Intersection> &&intersections);
|
||||
#endif
|
||||
/// Returns the number of intersections left of x.
|
||||
int countIntersections(double x) const;
|
||||
/// Returns the total sign of intersections left of x.
|
||||
int sumIntersections(double x) const;
|
||||
/// Decides whether the scanline is filled at x based on fill rule.
|
||||
bool filled(double x, FillRule fillRule) const;
|
||||
|
||||
private:
|
||||
std::vector<Intersection> intersections;
|
||||
mutable int lastIndex;
|
||||
|
||||
void preprocess();
|
||||
int moveTo(double x) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
60
Source/ThirdParty/msdfgen/msdfgen/core/Shape.h
vendored
Normal file
60
Source/ThirdParty/msdfgen/msdfgen/core/Shape.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Contour.h"
|
||||
#include "YAxisOrientation.h"
|
||||
#include "Scanline.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
// Threshold of the dot product of adjacent edge directions to be considered convergent.
|
||||
#define MSDFGEN_CORNER_DOT_EPSILON .000001
|
||||
|
||||
/// Vector shape representation.
|
||||
class Shape {
|
||||
|
||||
public:
|
||||
struct Bounds {
|
||||
// NOTE: b is actually the lower Y-coordinate and t the higher Y-coordinate. For Y_DOWNWARD orientation, b is actually the top and t the bottom. May be renamed in a future version.
|
||||
double l, b, r, t;
|
||||
};
|
||||
|
||||
/// The list of contours the shape consists of.
|
||||
std::vector<Contour> contours;
|
||||
/// Specifies whether the shape uses bottom-to-top (false) or top-to-bottom (true) Y coordinates.
|
||||
/// DEPRECATED - use getYAxisOrientation / setYAxisOrientation instead.
|
||||
bool inverseYAxis;
|
||||
|
||||
Shape();
|
||||
/// Adds a contour.
|
||||
void addContour(const Contour &contour);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
void addContour(Contour &&contour);
|
||||
#endif
|
||||
/// Adds a blank contour and returns its reference.
|
||||
Contour &addContour();
|
||||
/// Normalizes the shape geometry for distance field generation.
|
||||
void normalize();
|
||||
/// Performs basic checks to determine if the object represents a valid shape.
|
||||
bool validate() const;
|
||||
/// Adjusts the bounding box to fit the shape.
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
/// Adjusts the bounding box to fit the shape border's mitered corners.
|
||||
void boundMiters(double &xMin, double &yMin, double &xMax, double &yMax, double border, double miterLimit, int polarity) const;
|
||||
/// Computes the minimum bounding box that fits the shape, optionally with a (mitered) border.
|
||||
Bounds getBounds(double border = 0, double miterLimit = 0, int polarity = 0) const;
|
||||
/// Outputs the scanline that intersects the shape at y.
|
||||
void scanline(Scanline &line, double y) const;
|
||||
/// Returns the total number of edge segments
|
||||
int edgeCount() const;
|
||||
/// Assumes its contours are unoriented (even-odd fill rule). Attempts to orient them to conform to the non-zero winding rule.
|
||||
void orientContours();
|
||||
/// Returns the orientation of the axis of the shape's Y coordinates.
|
||||
YAxisOrientation getYAxisOrientation() const;
|
||||
/// Sets the orientation of the axis of the shape's Y coordinates.
|
||||
void setYAxisOrientation(YAxisOrientation yAxisOrientation);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
37
Source/ThirdParty/msdfgen/msdfgen/core/ShapeDistanceFinder.h
vendored
Normal file
37
Source/ThirdParty/msdfgen/msdfgen/core/ShapeDistanceFinder.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Vector2.hpp"
|
||||
#include "edge-selectors.h"
|
||||
#include "contour-combiners.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Finds the distance between a point and a Shape. ContourCombiner dictates the distance metric and its data type.
|
||||
template <class ContourCombiner>
|
||||
class ShapeDistanceFinder {
|
||||
|
||||
public:
|
||||
typedef typename ContourCombiner::DistanceType DistanceType;
|
||||
|
||||
// Passed shape object must persist until the distance finder is destroyed!
|
||||
explicit ShapeDistanceFinder(const Shape &shape);
|
||||
/// Finds the distance from origin. Not thread-safe! Is fastest when subsequent queries are close together.
|
||||
DistanceType distance(const Point2 &origin);
|
||||
|
||||
/// Finds the distance between shape and origin. Does not allocate result cache used to optimize performance of multiple queries.
|
||||
static DistanceType oneShotDistance(const Shape &shape, const Point2 &origin);
|
||||
|
||||
private:
|
||||
const Shape &shape;
|
||||
ContourCombiner contourCombiner;
|
||||
std::vector<typename ContourCombiner::EdgeSelectorType::EdgeCache> shapeEdgeCache;
|
||||
|
||||
};
|
||||
|
||||
typedef ShapeDistanceFinder<SimpleContourCombiner<TrueDistanceSelector> > SimpleTrueShapeDistanceFinder;
|
||||
|
||||
}
|
||||
|
||||
#include "ShapeDistanceFinder.hpp"
|
||||
60
Source/ThirdParty/msdfgen/msdfgen/core/ShapeDistanceFinder.hpp
vendored
Normal file
60
Source/ThirdParty/msdfgen/msdfgen/core/ShapeDistanceFinder.hpp
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#include "ShapeDistanceFinder.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
template <class ContourCombiner>
|
||||
ShapeDistanceFinder<ContourCombiner>::ShapeDistanceFinder(const Shape &shape) : shape(shape), contourCombiner(shape), shapeEdgeCache(shape.edgeCount()) { }
|
||||
|
||||
template <class ContourCombiner>
|
||||
typename ShapeDistanceFinder<ContourCombiner>::DistanceType ShapeDistanceFinder<ContourCombiner>::distance(const Point2 &origin) {
|
||||
contourCombiner.reset(origin);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
typename ContourCombiner::EdgeSelectorType::EdgeCache *edgeCache = shapeEdgeCache.data();
|
||||
#else
|
||||
typename ContourCombiner::EdgeSelectorType::EdgeCache *edgeCache = shapeEdgeCache.empty() ? NULL : &shapeEdgeCache[0];
|
||||
#endif
|
||||
|
||||
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||
if (!contour->edges.empty()) {
|
||||
typename ContourCombiner::EdgeSelectorType &edgeSelector = contourCombiner.edgeSelector(int(contour-shape.contours.begin()));
|
||||
|
||||
const EdgeSegment *prevEdge = contour->edges.size() >= 2 ? *(contour->edges.end()-2) : *contour->edges.begin();
|
||||
const EdgeSegment *curEdge = contour->edges.back();
|
||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||
const EdgeSegment *nextEdge = *edge;
|
||||
edgeSelector.addEdge(*edgeCache++, prevEdge, curEdge, nextEdge);
|
||||
prevEdge = curEdge;
|
||||
curEdge = nextEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return contourCombiner.distance();
|
||||
}
|
||||
|
||||
template <class ContourCombiner>
|
||||
typename ShapeDistanceFinder<ContourCombiner>::DistanceType ShapeDistanceFinder<ContourCombiner>::oneShotDistance(const Shape &shape, const Point2 &origin) {
|
||||
ContourCombiner contourCombiner(shape);
|
||||
contourCombiner.reset(origin);
|
||||
|
||||
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||
if (!contour->edges.empty()) {
|
||||
typename ContourCombiner::EdgeSelectorType &edgeSelector = contourCombiner.edgeSelector(int(contour-shape.contours.begin()));
|
||||
|
||||
const EdgeSegment *prevEdge = contour->edges.size() >= 2 ? *(contour->edges.end()-2) : *contour->edges.begin();
|
||||
const EdgeSegment *curEdge = contour->edges.back();
|
||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||
const EdgeSegment *nextEdge = *edge;
|
||||
typename ContourCombiner::EdgeSelectorType::EdgeCache dummy;
|
||||
edgeSelector.addEdge(dummy, prevEdge, curEdge, nextEdge);
|
||||
prevEdge = curEdge;
|
||||
curEdge = nextEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return contourCombiner.distance();
|
||||
}
|
||||
|
||||
}
|
||||
38
Source/ThirdParty/msdfgen/msdfgen/core/SignedDistance.hpp
vendored
Normal file
38
Source/ThirdParty/msdfgen/msdfgen/core/SignedDistance.hpp
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Represents a signed distance and alignment, which together can be compared to uniquely determine the closest edge segment.
|
||||
class SignedDistance {
|
||||
|
||||
public:
|
||||
double distance;
|
||||
double dot;
|
||||
|
||||
inline SignedDistance() : distance(-DBL_MAX), dot(0) { }
|
||||
inline SignedDistance(double dist, double d) : distance(dist), dot(d) { }
|
||||
|
||||
};
|
||||
|
||||
inline bool operator<(const SignedDistance a, const SignedDistance b) {
|
||||
return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot < b.dot);
|
||||
}
|
||||
|
||||
inline bool operator>(const SignedDistance a, const SignedDistance b) {
|
||||
return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot > b.dot);
|
||||
}
|
||||
|
||||
inline bool operator<=(const SignedDistance a, const SignedDistance b) {
|
||||
return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot <= b.dot);
|
||||
}
|
||||
|
||||
inline bool operator>=(const SignedDistance a, const SignedDistance b) {
|
||||
return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot >= b.dot);
|
||||
}
|
||||
|
||||
}
|
||||
167
Source/ThirdParty/msdfgen/msdfgen/core/Vector2.hpp
vendored
Normal file
167
Source/ThirdParty/msdfgen/msdfgen/core/Vector2.hpp
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/**
|
||||
* A 2-dimensional euclidean floating-point vector.
|
||||
* @author Viktor Chlumsky
|
||||
*/
|
||||
struct Vector2 {
|
||||
|
||||
double x, y;
|
||||
|
||||
inline Vector2(double val = 0) : x(val), y(val) { }
|
||||
|
||||
inline Vector2(double x, double y) : x(x), y(y) { }
|
||||
|
||||
/// Sets the vector to zero.
|
||||
inline void reset() {
|
||||
x = 0, y = 0;
|
||||
}
|
||||
|
||||
/// Sets individual elements of the vector.
|
||||
inline void set(double newX, double newY) {
|
||||
x = newX, y = newY;
|
||||
}
|
||||
|
||||
/// Returns the vector's squared length.
|
||||
inline double squaredLength() const {
|
||||
return x*x+y*y;
|
||||
}
|
||||
|
||||
/// Returns the vector's length.
|
||||
inline double length() const {
|
||||
return sqrt(x*x+y*y);
|
||||
}
|
||||
|
||||
/// Returns the normalized vector - one that has the same direction but unit length.
|
||||
inline Vector2 normalize(bool allowZero = false) const {
|
||||
if (double len = length())
|
||||
return Vector2(x/len, y/len);
|
||||
return Vector2(0, !allowZero);
|
||||
}
|
||||
|
||||
/// Returns a vector with the same length that is orthogonal to this one.
|
||||
inline Vector2 getOrthogonal(bool polarity = true) const {
|
||||
return polarity ? Vector2(-y, x) : Vector2(y, -x);
|
||||
}
|
||||
|
||||
/// Returns a vector with unit length that is orthogonal to this one.
|
||||
inline Vector2 getOrthonormal(bool polarity = true, bool allowZero = false) const {
|
||||
if (double len = length())
|
||||
return polarity ? Vector2(-y/len, x/len) : Vector2(y/len, -x/len);
|
||||
return polarity ? Vector2(0, !allowZero) : Vector2(0, -!allowZero);
|
||||
}
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
inline explicit operator bool() const {
|
||||
return x || y;
|
||||
}
|
||||
#else
|
||||
inline operator const void *() const {
|
||||
return x || y ? this : NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Vector2 &operator+=(const Vector2 other) {
|
||||
x += other.x, y += other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector2 &operator-=(const Vector2 other) {
|
||||
x -= other.x, y -= other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector2 &operator*=(const Vector2 other) {
|
||||
x *= other.x, y *= other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector2 &operator/=(const Vector2 other) {
|
||||
x /= other.x, y /= other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector2 &operator*=(double value) {
|
||||
x *= value, y *= value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector2 &operator/=(double value) {
|
||||
x /= value, y /= value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// A vector may also represent a point, which shall be differentiated semantically using the alias Point2.
|
||||
typedef Vector2 Point2;
|
||||
|
||||
/// Dot product of two vectors.
|
||||
inline double dotProduct(const Vector2 a, const Vector2 b) {
|
||||
return a.x*b.x+a.y*b.y;
|
||||
}
|
||||
|
||||
/// A special version of the cross product for 2D vectors (returns scalar value).
|
||||
inline double crossProduct(const Vector2 a, const Vector2 b) {
|
||||
return a.x*b.y-a.y*b.x;
|
||||
}
|
||||
|
||||
inline bool operator==(const Vector2 a, const Vector2 b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Vector2 a, const Vector2 b) {
|
||||
return a.x != b.x || a.y != b.y;
|
||||
}
|
||||
|
||||
inline Vector2 operator+(const Vector2 v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vector2 operator-(const Vector2 v) {
|
||||
return Vector2(-v.x, -v.y);
|
||||
}
|
||||
|
||||
inline bool operator!(const Vector2 v) {
|
||||
return !v.x && !v.y;
|
||||
}
|
||||
|
||||
inline Vector2 operator+(const Vector2 a, const Vector2 b) {
|
||||
return Vector2(a.x+b.x, a.y+b.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator-(const Vector2 a, const Vector2 b) {
|
||||
return Vector2(a.x-b.x, a.y-b.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator*(const Vector2 a, const Vector2 b) {
|
||||
return Vector2(a.x*b.x, a.y*b.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator/(const Vector2 a, const Vector2 b) {
|
||||
return Vector2(a.x/b.x, a.y/b.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator*(double a, const Vector2 b) {
|
||||
return Vector2(a*b.x, a*b.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator/(double a, const Vector2 b) {
|
||||
return Vector2(a/b.x, a/b.y);
|
||||
}
|
||||
|
||||
inline Vector2 operator*(const Vector2 a, double b) {
|
||||
return Vector2(a.x*b, a.y*b);
|
||||
}
|
||||
|
||||
inline Vector2 operator/(const Vector2 a, double b) {
|
||||
return Vector2(a.x/b, a.y/b);
|
||||
}
|
||||
|
||||
}
|
||||
17
Source/ThirdParty/msdfgen/msdfgen/core/YAxisOrientation.h
vendored
Normal file
17
Source/ThirdParty/msdfgen/msdfgen/core/YAxisOrientation.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Specifies whether the Y component of the coordinate system increases in the upward or downward direction.
|
||||
enum YAxisOrientation {
|
||||
Y_UPWARD,
|
||||
Y_DOWNWARD
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION msdfgen::Y_UPWARD
|
||||
#define MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION (MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION == msdfgen::Y_DOWNWARD ? msdfgen::Y_UPWARD : msdfgen::Y_DOWNWARD)
|
||||
63
Source/ThirdParty/msdfgen/msdfgen/core/arithmetics.hpp
vendored
Normal file
63
Source/ThirdParty/msdfgen/msdfgen/core/arithmetics.hpp
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Returns the smaller of the arguments.
|
||||
template <typename T>
|
||||
inline T min(T a, T b) {
|
||||
return b < a ? b : a;
|
||||
}
|
||||
|
||||
/// Returns the larger of the arguments.
|
||||
template <typename T>
|
||||
inline T max(T a, T b) {
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
/// Returns the middle out of three values
|
||||
template <typename T>
|
||||
inline T median(T a, T b, T c) {
|
||||
return max(min(a, b), min(max(a, b), c));
|
||||
}
|
||||
|
||||
/// Returns the weighted average of a and b.
|
||||
template <typename T, typename S>
|
||||
inline T mix(T a, T b, S weight) {
|
||||
return T((S(1)-weight)*a+weight*b);
|
||||
}
|
||||
|
||||
/// Clamps the number to the interval from 0 to 1.
|
||||
template <typename T>
|
||||
inline T clamp(T n) {
|
||||
return n >= T(0) && n <= T(1) ? n : T(n > T(0));
|
||||
}
|
||||
|
||||
/// Clamps the number to the interval from 0 to b.
|
||||
template <typename T>
|
||||
inline T clamp(T n, T b) {
|
||||
return n >= T(0) && n <= b ? n : T(n > T(0))*b;
|
||||
}
|
||||
|
||||
/// Clamps the number to the interval from a to b.
|
||||
template <typename T>
|
||||
inline T clamp(T n, T a, T b) {
|
||||
return n >= a && n <= b ? n : n < a ? a : b;
|
||||
}
|
||||
|
||||
/// Returns 1 for positive values, -1 for negative values, and 0 for zero.
|
||||
template <typename T>
|
||||
inline int sign(T n) {
|
||||
return (T(0) < n)-(n < T(0));
|
||||
}
|
||||
|
||||
/// Returns 1 for non-negative values and -1 for negative values.
|
||||
template <typename T>
|
||||
inline int nonZeroSign(T n) {
|
||||
return 2*(n > T(0))-1;
|
||||
}
|
||||
|
||||
}
|
||||
16
Source/ThirdParty/msdfgen/msdfgen/core/base.h
vendored
Normal file
16
Source/ThirdParty/msdfgen/msdfgen/core/base.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// This file needs to be included first for all MSDFgen sources
|
||||
|
||||
#ifndef MSDFGEN_PUBLIC
|
||||
#include <msdfgen/msdfgen-config.h>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
}
|
||||
27
Source/ThirdParty/msdfgen/msdfgen/core/bitmap-interpolation.hpp
vendored
Normal file
27
Source/ThirdParty/msdfgen/msdfgen/core/bitmap-interpolation.hpp
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arithmetics.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
template <typename T, int N>
|
||||
inline void interpolate(T *output, const BitmapConstSection<T, N> &bitmap, Point2 pos) {
|
||||
pos.x = clamp(pos.x, double(bitmap.width));
|
||||
pos.y = clamp(pos.y, double(bitmap.height));
|
||||
pos -= .5;
|
||||
int l = (int) floor(pos.x);
|
||||
int b = (int) floor(pos.y);
|
||||
int r = l+1;
|
||||
int t = b+1;
|
||||
double lr = pos.x-l;
|
||||
double bt = pos.y-b;
|
||||
l = clamp(l, bitmap.width-1), r = clamp(r, bitmap.width-1);
|
||||
b = clamp(b, bitmap.height-1), t = clamp(t, bitmap.height-1);
|
||||
for (int i = 0; i < N; ++i)
|
||||
output[i] = mix(mix(bitmap(l, b)[i], bitmap(r, b)[i], lr), mix(bitmap(l, t)[i], bitmap(r, t)[i], lr), bt);
|
||||
}
|
||||
|
||||
}
|
||||
47
Source/ThirdParty/msdfgen/msdfgen/core/contour-combiners.h
vendored
Normal file
47
Source/ThirdParty/msdfgen/msdfgen/core/contour-combiners.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Shape.h"
|
||||
#include "edge-selectors.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Simply selects the nearest contour.
|
||||
template <class EdgeSelector>
|
||||
class SimpleContourCombiner {
|
||||
|
||||
public:
|
||||
typedef EdgeSelector EdgeSelectorType;
|
||||
typedef typename EdgeSelector::DistanceType DistanceType;
|
||||
|
||||
explicit SimpleContourCombiner(const Shape &shape);
|
||||
void reset(const Point2 &p);
|
||||
EdgeSelector &edgeSelector(int i);
|
||||
DistanceType distance() const;
|
||||
|
||||
private:
|
||||
EdgeSelector shapeEdgeSelector;
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest contour that actually forms a border between filled and unfilled area.
|
||||
template <class EdgeSelector>
|
||||
class OverlappingContourCombiner {
|
||||
|
||||
public:
|
||||
typedef EdgeSelector EdgeSelectorType;
|
||||
typedef typename EdgeSelector::DistanceType DistanceType;
|
||||
|
||||
explicit OverlappingContourCombiner(const Shape &shape);
|
||||
void reset(const Point2 &p);
|
||||
EdgeSelector &edgeSelector(int i);
|
||||
DistanceType distance() const;
|
||||
|
||||
private:
|
||||
Point2 p;
|
||||
std::vector<int> windings;
|
||||
std::vector<EdgeSelector> edgeSelectors;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
11
Source/ThirdParty/msdfgen/msdfgen/core/convergent-curve-ordering.h
vendored
Normal file
11
Source/ThirdParty/msdfgen/msdfgen/core/convergent-curve-ordering.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "edge-segments.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// For curves a, b converging at P = a->point(1) = b->point(0) with the same (opposite) direction, determines the relative ordering in which they exit P (i.e. whether a is to the left or right of b at the smallest positive radius around P)
|
||||
int convergentCurveOrdering(const EdgeSegment *a, const EdgeSegment *b);
|
||||
|
||||
}
|
||||
29
Source/ThirdParty/msdfgen/msdfgen/core/edge-coloring.h
vendored
Normal file
29
Source/ThirdParty/msdfgen/msdfgen/core/edge-coloring.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
#define MSDFGEN_EDGE_LENGTH_PRECISION 4
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/** Assigns colors to edges of the shape in accordance to the multi-channel distance field technique.
|
||||
* May split some edges if necessary.
|
||||
* angleThreshold specifies the maximum angle (in radians) to be considered a corner, for example 3 (~172 degrees).
|
||||
* Values below 1/2 PI will be treated as the external angle.
|
||||
*/
|
||||
void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed = 0);
|
||||
|
||||
/** The alternative "ink trap" coloring strategy is designed for better results with typefaces
|
||||
* that use ink traps as a design feature. It guarantees that even if all edges that are shorter than
|
||||
* both their neighboring edges are removed, the coloring remains consistent with the established rules.
|
||||
*/
|
||||
void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed = 0);
|
||||
|
||||
/** The alternative coloring by distance tries to use different colors for edges that are close together.
|
||||
* This should theoretically be the best strategy on average. However, since it needs to compute the distance
|
||||
* between all pairs of edges, and perform a graph optimization task, it is much slower than the rest.
|
||||
*/
|
||||
void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long long seed = 0);
|
||||
|
||||
}
|
||||
146
Source/ThirdParty/msdfgen/msdfgen/core/edge-segments.h
vendored
Normal file
146
Source/ThirdParty/msdfgen/msdfgen/core/edge-segments.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "SignedDistance.hpp"
|
||||
#include "EdgeColor.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
// Parameters for iterative search of closest point on a cubic Bezier curve. Increase for higher precision.
|
||||
#define MSDFGEN_CUBIC_SEARCH_STARTS 4
|
||||
#define MSDFGEN_CUBIC_SEARCH_STEPS 4
|
||||
|
||||
/// An abstract edge segment.
|
||||
class EdgeSegment {
|
||||
|
||||
public:
|
||||
EdgeColor color;
|
||||
|
||||
static EdgeSegment *create(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
|
||||
static EdgeSegment *create(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
|
||||
static EdgeSegment *create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
|
||||
|
||||
EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { }
|
||||
virtual ~EdgeSegment() { }
|
||||
/// Creates a copy of the edge segment.
|
||||
virtual EdgeSegment *clone() const = 0;
|
||||
/// Returns the numeric code of the edge segment's type.
|
||||
virtual int type() const = 0;
|
||||
/// Returns the array of control points.
|
||||
virtual const Point2 *controlPoints() const = 0;
|
||||
/// Returns the point on the edge specified by the parameter (between 0 and 1).
|
||||
virtual Point2 point(double param) const = 0;
|
||||
/// Returns the direction the edge has at the point specified by the parameter.
|
||||
virtual Vector2 direction(double param) const = 0;
|
||||
/// Returns the change of direction (second derivative) at the point specified by the parameter.
|
||||
virtual Vector2 directionChange(double param) const = 0;
|
||||
/// Returns the minimum signed distance between origin and the edge.
|
||||
virtual SignedDistance signedDistance(Point2 origin, double ¶m) const = 0;
|
||||
/// Converts a previously retrieved signed distance from origin to perpendicular distance.
|
||||
virtual void distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const;
|
||||
/// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
|
||||
virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
|
||||
/// Adjusts the bounding box to fit the edge segment.
|
||||
virtual void bound(double &xMin, double &yMin, double &xMax, double &yMax) const = 0;
|
||||
|
||||
/// Reverses the edge (swaps its start point and end point).
|
||||
virtual void reverse() = 0;
|
||||
/// Moves the start point of the edge segment.
|
||||
virtual void moveStartPoint(Point2 to) = 0;
|
||||
/// Moves the end point of the edge segment.
|
||||
virtual void moveEndPoint(Point2 to) = 0;
|
||||
/// Splits the edge segments into thirds which together represent the original edge.
|
||||
virtual void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const = 0;
|
||||
|
||||
};
|
||||
|
||||
/// A line segment.
|
||||
class LinearSegment : public EdgeSegment {
|
||||
|
||||
public:
|
||||
enum EdgeType {
|
||||
EDGE_TYPE = 1
|
||||
};
|
||||
|
||||
Point2 p[2];
|
||||
|
||||
LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
|
||||
LinearSegment *clone() const;
|
||||
int type() const;
|
||||
const Point2 *controlPoints() const;
|
||||
Point2 point(double param) const;
|
||||
Vector2 direction(double param) const;
|
||||
Vector2 directionChange(double param) const;
|
||||
double length() const;
|
||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
void moveEndPoint(Point2 to);
|
||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||
|
||||
};
|
||||
|
||||
/// A quadratic Bezier curve.
|
||||
class QuadraticSegment : public EdgeSegment {
|
||||
|
||||
public:
|
||||
enum EdgeType {
|
||||
EDGE_TYPE = 2
|
||||
};
|
||||
|
||||
Point2 p[3];
|
||||
|
||||
QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
|
||||
QuadraticSegment *clone() const;
|
||||
int type() const;
|
||||
const Point2 *controlPoints() const;
|
||||
Point2 point(double param) const;
|
||||
Vector2 direction(double param) const;
|
||||
Vector2 directionChange(double param) const;
|
||||
double length() const;
|
||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
void moveEndPoint(Point2 to);
|
||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||
|
||||
EdgeSegment *convertToCubic() const;
|
||||
|
||||
};
|
||||
|
||||
/// A cubic Bezier curve.
|
||||
class CubicSegment : public EdgeSegment {
|
||||
|
||||
public:
|
||||
enum EdgeType {
|
||||
EDGE_TYPE = 3
|
||||
};
|
||||
|
||||
Point2 p[4];
|
||||
|
||||
CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
|
||||
CubicSegment *clone() const;
|
||||
int type() const;
|
||||
const Point2 *controlPoints() const;
|
||||
Point2 point(double param) const;
|
||||
Vector2 direction(double param) const;
|
||||
Vector2 directionChange(double param) const;
|
||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
void moveEndPoint(Point2 to);
|
||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
117
Source/ThirdParty/msdfgen/msdfgen/core/edge-selectors.h
vendored
Normal file
117
Source/ThirdParty/msdfgen/msdfgen/core/edge-selectors.h
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "SignedDistance.hpp"
|
||||
#include "edge-segments.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
struct MultiDistance {
|
||||
double r, g, b;
|
||||
};
|
||||
struct MultiAndTrueDistance : MultiDistance {
|
||||
double a;
|
||||
};
|
||||
|
||||
/// Selects the nearest edge by its true distance.
|
||||
class TrueDistanceSelector {
|
||||
|
||||
public:
|
||||
typedef double DistanceType;
|
||||
|
||||
struct EdgeCache {
|
||||
Point2 point;
|
||||
double absDistance;
|
||||
|
||||
EdgeCache();
|
||||
};
|
||||
|
||||
void reset(const Point2 &p);
|
||||
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
||||
void merge(const TrueDistanceSelector &other);
|
||||
DistanceType distance() const;
|
||||
|
||||
private:
|
||||
Point2 p;
|
||||
SignedDistance minDistance;
|
||||
|
||||
};
|
||||
|
||||
class PerpendicularDistanceSelectorBase {
|
||||
|
||||
public:
|
||||
struct EdgeCache {
|
||||
Point2 point;
|
||||
double absDistance;
|
||||
double aDomainDistance, bDomainDistance;
|
||||
double aPerpendicularDistance, bPerpendicularDistance;
|
||||
|
||||
EdgeCache();
|
||||
};
|
||||
|
||||
static bool getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
|
||||
|
||||
PerpendicularDistanceSelectorBase();
|
||||
void reset(double delta);
|
||||
bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
|
||||
void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
|
||||
void addEdgePerpendicularDistance(double distance);
|
||||
void merge(const PerpendicularDistanceSelectorBase &other);
|
||||
double computeDistance(const Point2 &p) const;
|
||||
SignedDistance trueDistance() const;
|
||||
|
||||
private:
|
||||
SignedDistance minTrueDistance;
|
||||
double minNegativePerpendicularDistance;
|
||||
double minPositivePerpendicularDistance;
|
||||
const EdgeSegment *nearEdge;
|
||||
double nearEdgeParam;
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest edge by its perpendicular distance.
|
||||
class PerpendicularDistanceSelector : public PerpendicularDistanceSelectorBase {
|
||||
|
||||
public:
|
||||
typedef double DistanceType;
|
||||
|
||||
void reset(const Point2 &p);
|
||||
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
||||
DistanceType distance() const;
|
||||
|
||||
private:
|
||||
Point2 p;
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest edge for each of the three channels by its perpendicular distance.
|
||||
class MultiDistanceSelector {
|
||||
|
||||
public:
|
||||
typedef MultiDistance DistanceType;
|
||||
typedef PerpendicularDistanceSelectorBase::EdgeCache EdgeCache;
|
||||
|
||||
void reset(const Point2 &p);
|
||||
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
||||
void merge(const MultiDistanceSelector &other);
|
||||
DistanceType distance() const;
|
||||
SignedDistance trueDistance() const;
|
||||
|
||||
private:
|
||||
Point2 p;
|
||||
PerpendicularDistanceSelectorBase r, g, b;
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest edge for each of the three color channels by its perpendicular distance and by true distance for the alpha channel.
|
||||
class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
|
||||
|
||||
public:
|
||||
typedef MultiAndTrueDistance DistanceType;
|
||||
|
||||
DistanceType distance() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
14
Source/ThirdParty/msdfgen/msdfgen/core/equation-solver.h
vendored
Normal file
14
Source/ThirdParty/msdfgen/msdfgen/core/equation-solver.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
// ax^2 + bx + c = 0
|
||||
int solveQuadratic(double x[2], double a, double b, double c);
|
||||
|
||||
// ax^3 + bx^2 + cx + d = 0
|
||||
int solveCubic(double x[3], double a, double b, double c, double d);
|
||||
|
||||
}
|
||||
11
Source/ThirdParty/msdfgen/msdfgen/core/export-svg.h
vendored
Normal file
11
Source/ThirdParty/msdfgen/msdfgen/core/export-svg.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
bool saveSvgShape(const Shape &shape, const char *filename);
|
||||
bool saveSvgShape(const Shape &shape, const Shape::Bounds &bounds, const char *filename);
|
||||
|
||||
}
|
||||
66
Source/ThirdParty/msdfgen/msdfgen/core/generator-config.h
vendored
Normal file
66
Source/ThirdParty/msdfgen/msdfgen/core/generator-config.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
#ifndef MSDFGEN_PUBLIC
|
||||
#define MSDFGEN_PUBLIC // for DLL import/export
|
||||
#endif
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// The configuration of the MSDF error correction pass.
|
||||
struct ErrorCorrectionConfig {
|
||||
/// The default value of minDeviationRatio.
|
||||
static MSDFGEN_PUBLIC const double defaultMinDeviationRatio;
|
||||
/// The default value of minImproveRatio.
|
||||
static MSDFGEN_PUBLIC const double defaultMinImproveRatio;
|
||||
|
||||
/// Mode of operation.
|
||||
enum Mode {
|
||||
/// Skips error correction pass.
|
||||
DISABLED,
|
||||
/// Corrects all discontinuities of the distance field regardless if edges are adversely affected.
|
||||
INDISCRIMINATE,
|
||||
/// Corrects artifacts at edges and other discontinuous distances only if it does not affect edges or corners.
|
||||
EDGE_PRIORITY,
|
||||
/// Only corrects artifacts at edges.
|
||||
EDGE_ONLY
|
||||
} mode;
|
||||
/// Configuration of whether to use an algorithm that computes the exact shape distance at the positions of suspected artifacts. This algorithm can be much slower.
|
||||
enum DistanceCheckMode {
|
||||
/// Never computes exact shape distance.
|
||||
DO_NOT_CHECK_DISTANCE,
|
||||
/// Only computes exact shape distance at edges. Provides a good balance between speed and precision.
|
||||
CHECK_DISTANCE_AT_EDGE,
|
||||
/// Computes and compares the exact shape distance for each suspected artifact.
|
||||
ALWAYS_CHECK_DISTANCE
|
||||
} distanceCheckMode;
|
||||
/// The minimum ratio between the actual and maximum expected distance delta to be considered an error.
|
||||
double minDeviationRatio;
|
||||
/// The minimum ratio between the pre-correction distance error and the post-correction distance error. Has no effect for DO_NOT_CHECK_DISTANCE.
|
||||
double minImproveRatio;
|
||||
/// An optional buffer to avoid dynamic allocation. Must have at least as many bytes as the MSDF has pixels.
|
||||
byte *buffer;
|
||||
|
||||
inline explicit ErrorCorrectionConfig(Mode mode = EDGE_PRIORITY, DistanceCheckMode distanceCheckMode = CHECK_DISTANCE_AT_EDGE, double minDeviationRatio = defaultMinDeviationRatio, double minImproveRatio = defaultMinImproveRatio, byte *buffer = NULL) : mode(mode), distanceCheckMode(distanceCheckMode), minDeviationRatio(minDeviationRatio), minImproveRatio(minImproveRatio), buffer(buffer) { }
|
||||
};
|
||||
|
||||
/// The configuration of the distance field generator algorithm.
|
||||
struct GeneratorConfig {
|
||||
/// Specifies whether to use the version of the algorithm that supports overlapping contours with the same winding. May be set to false to improve performance when no such contours are present.
|
||||
bool overlapSupport;
|
||||
|
||||
inline explicit GeneratorConfig(bool overlapSupport = true) : overlapSupport(overlapSupport) { }
|
||||
};
|
||||
|
||||
/// The configuration of the multi-channel distance field generator algorithm.
|
||||
struct MSDFGeneratorConfig : GeneratorConfig {
|
||||
/// Configuration of the error correction pass.
|
||||
ErrorCorrectionConfig errorCorrection;
|
||||
|
||||
inline MSDFGeneratorConfig() { }
|
||||
inline explicit MSDFGeneratorConfig(bool overlapSupport, const ErrorCorrectionConfig &errorCorrection = ErrorCorrectionConfig()) : GeneratorConfig(overlapSupport), errorCorrection(errorCorrection) { }
|
||||
};
|
||||
|
||||
}
|
||||
40
Source/ThirdParty/msdfgen/msdfgen/core/msdf-error-correction.h
vendored
Normal file
40
Source/ThirdParty/msdfgen/msdfgen/core/msdf-error-correction.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "Range.hpp"
|
||||
#include "Projection.h"
|
||||
#include "SDFTransformation.h"
|
||||
#include "Shape.h"
|
||||
#include "BitmapRef.hpp"
|
||||
#include "generator-config.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Predicts potential artifacts caused by the interpolation of the MSDF and corrects them by converting nearby texels to single-channel.
|
||||
void msdfErrorCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Applies the simplified error correction to all discontiunous distances (INDISCRIMINATE mode). Does not need shape or translation.
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
|
||||
/// Applies the simplified error correction to edges only (EDGE_ONLY mode). Does not need shape or translation.
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
|
||||
/// The original version of the error correction algorithm.
|
||||
void msdfErrorCorrection_legacy(const BitmapSection<float, 3> &output, const Vector2 &threshold);
|
||||
void msdfErrorCorrection_legacy(const BitmapSection<float, 4> &output, const Vector2 &threshold);
|
||||
|
||||
}
|
||||
16
Source/ThirdParty/msdfgen/msdfgen/core/pixel-conversion.hpp
vendored
Normal file
16
Source/ThirdParty/msdfgen/msdfgen/core/pixel-conversion.hpp
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arithmetics.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
inline byte pixelFloatToByte(float x) {
|
||||
return byte(~int(255.5f-255.f*clamp(x)));
|
||||
}
|
||||
|
||||
inline float pixelByteToFloat(byte x) {
|
||||
return 1.f/255.f*float(x);
|
||||
}
|
||||
|
||||
}
|
||||
28
Source/ThirdParty/msdfgen/msdfgen/core/rasterization.h
vendored
Normal file
28
Source/ThirdParty/msdfgen/msdfgen/core/rasterization.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "Shape.h"
|
||||
#include "Projection.h"
|
||||
#include "Scanline.h"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Rasterizes the shape into a monochrome bitmap.
|
||||
void rasterize(BitmapSection<float, 1> output, const Shape &shape, const Projection &projection, FillRule fillRule = FILL_NONZERO);
|
||||
/// Fixes the sign of the input signed distance field, so that it matches the shape's rasterized fill.
|
||||
void distanceSignCorrection(BitmapSection<float, 1> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue = .5f, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 3> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue = .5f, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 4> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue = .5f, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
// Old versions of the function API's kept for backwards compatibility
|
||||
void rasterize(const BitmapSection<float, 1> &output, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 1> sdf, const Shape &shape, const Projection &projection, FillRule fillRule);
|
||||
void distanceSignCorrection(BitmapSection<float, 3> sdf, const Shape &shape, const Projection &projection, FillRule fillRule);
|
||||
void distanceSignCorrection(BitmapSection<float, 4> sdf, const Shape &shape, const Projection &projection, FillRule fillRule);
|
||||
void distanceSignCorrection(const BitmapSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
}
|
||||
23
Source/ThirdParty/msdfgen/msdfgen/core/render-sdf.h
vendored
Normal file
23
Source/ThirdParty/msdfgen/msdfgen/core/render-sdf.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "Range.hpp"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Reconstructs the shape's appearance into output from the distance field sdf.
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 3> &output, const BitmapConstSection<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 3> &output, const BitmapConstSection<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 4> &output, const BitmapConstSection<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
|
||||
/// Snaps the values of the floating-point bitmaps into one of the 256 values representable in a standard 8-bit bitmap.
|
||||
void simulate8bit(const BitmapSection<float, 1> &bitmap);
|
||||
void simulate8bit(const BitmapSection<float, 3> &bitmap);
|
||||
void simulate8bit(const BitmapSection<float, 4> &bitmap);
|
||||
|
||||
}
|
||||
16
Source/ThirdParty/msdfgen/msdfgen/core/save-bmp.h
vendored
Normal file
16
Source/ThirdParty/msdfgen/msdfgen/core/save-bmp.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as a BMP file.
|
||||
bool saveBmp(BitmapConstSection<byte, 1> bitmap, const char *filename);
|
||||
bool saveBmp(BitmapConstSection<byte, 3> bitmap, const char *filename);
|
||||
bool saveBmp(BitmapConstSection<byte, 4> bitmap, const char *filename);
|
||||
bool saveBmp(BitmapConstSection<float, 1> bitmap, const char *filename);
|
||||
bool saveBmp(BitmapConstSection<float, 3> bitmap, const char *filename);
|
||||
bool saveBmp(BitmapConstSection<float, 4> bitmap, const char *filename);
|
||||
|
||||
}
|
||||
12
Source/ThirdParty/msdfgen/msdfgen/core/save-fl32.h
vendored
Normal file
12
Source/ThirdParty/msdfgen/msdfgen/core/save-fl32.h
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as an uncompressed floating-point FL32 file, which can be decoded trivially.
|
||||
template <int N>
|
||||
bool saveFl32(BitmapConstSection<float, N> bitmap, const char *filename);
|
||||
|
||||
}
|
||||
16
Source/ThirdParty/msdfgen/msdfgen/core/save-rgba.h
vendored
Normal file
16
Source/ThirdParty/msdfgen/msdfgen/core/save-rgba.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as a simple RGBA file, which can be decoded trivially.
|
||||
bool saveRgba(BitmapConstSection<byte, 1> bitmap, const char *filename);
|
||||
bool saveRgba(BitmapConstSection<byte, 3> bitmap, const char *filename);
|
||||
bool saveRgba(BitmapConstSection<byte, 4> bitmap, const char *filename);
|
||||
bool saveRgba(BitmapConstSection<float, 1> bitmap, const char *filename);
|
||||
bool saveRgba(BitmapConstSection<float, 3> bitmap, const char *filename);
|
||||
bool saveRgba(BitmapConstSection<float, 4> bitmap, const char *filename);
|
||||
|
||||
}
|
||||
13
Source/ThirdParty/msdfgen/msdfgen/core/save-tiff.h
vendored
Normal file
13
Source/ThirdParty/msdfgen/msdfgen/core/save-tiff.h
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as an uncompressed floating-point TIFF file.
|
||||
bool saveTiff(const BitmapConstSection<float, 1> &bitmap, const char *filename);
|
||||
bool saveTiff(const BitmapConstSection<float, 3> &bitmap, const char *filename);
|
||||
bool saveTiff(const BitmapConstSection<float, 4> &bitmap, const char *filename);
|
||||
|
||||
}
|
||||
33
Source/ThirdParty/msdfgen/msdfgen/core/sdf-error-estimation.h
vendored
Normal file
33
Source/ThirdParty/msdfgen/msdfgen/core/sdf-error-estimation.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "Shape.h"
|
||||
#include "Projection.h"
|
||||
#include "Scanline.h"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Analytically constructs a scanline at y evaluating fill by linear interpolation of the SDF.
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
|
||||
/// Estimates the portion of the area that will be filled incorrectly when rendering using the SDF.
|
||||
double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
}
|
||||
15
Source/ThirdParty/msdfgen/msdfgen/core/shape-description.h
vendored
Normal file
15
Source/ThirdParty/msdfgen/msdfgen/core/shape-description.h
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include "Shape.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Deserializes a text description of a vector shape into output.
|
||||
bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified = NULL);
|
||||
bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecified = NULL);
|
||||
/// Serializes a shape object into a text description.
|
||||
bool writeShapeDescription(FILE *output, const Shape &shape);
|
||||
|
||||
}
|
||||
13
Source/ThirdParty/msdfgen/msdfgen/msdfgen-config.h
vendored
Normal file
13
Source/ThirdParty/msdfgen/msdfgen/msdfgen-config.h
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MSDFGEN_PUBLIC
|
||||
#define MSDFGEN_EXT_PUBLIC
|
||||
|
||||
#define MSDFGEN_VERSION 1.13.0
|
||||
#define MSDFGEN_VERSION_MAJOR 1
|
||||
#define MSDFGEN_VERSION_MINOR 13
|
||||
#define MSDFGEN_VERSION_REVISION 0
|
||||
#define MSDFGEN_COPYRIGHT_YEAR 2026
|
||||
|
||||
#define MSDFGEN_USE_CPP11
|
||||
78
Source/ThirdParty/msdfgen/msdfgen/msdfgen.h
vendored
Normal file
78
Source/ThirdParty/msdfgen/msdfgen/msdfgen.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
|
||||
* ---------------------------------------------
|
||||
* A utility by Viktor Chlumsky, (c) 2014 - 2025
|
||||
*
|
||||
* 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 "core/base.h"
|
||||
#include "core/arithmetics.hpp"
|
||||
#include "core/Vector2.hpp"
|
||||
#include "core/Range.hpp"
|
||||
#include "core/Projection.h"
|
||||
#include "core/DistanceMapping.h"
|
||||
#include "core/SDFTransformation.h"
|
||||
#include "core/Scanline.h"
|
||||
#include "core/Shape.h"
|
||||
#include "core/BitmapRef.hpp"
|
||||
#include "core/Bitmap.h"
|
||||
#include "core/bitmap-interpolation.hpp"
|
||||
#include "core/pixel-conversion.hpp"
|
||||
#include "core/edge-coloring.h"
|
||||
#include "core/generator-config.h"
|
||||
#include "core/msdf-error-correction.h"
|
||||
#include "core/render-sdf.h"
|
||||
#include "core/rasterization.h"
|
||||
#include "core/sdf-error-estimation.h"
|
||||
#include "core/save-bmp.h"
|
||||
#include "core/save-tiff.h"
|
||||
#include "core/save-rgba.h"
|
||||
#include "core/save-fl32.h"
|
||||
#include "core/shape-description.h"
|
||||
#include "core/export-svg.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Generates a conventional single-channel signed distance field.
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
|
||||
/// Generates a single-channel signed perpendicular distance field.
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
|
||||
/// Generates a multi-channel signed distance field. Edge colors must be assigned first! (See edgeColoringSimple)
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Generates a multi-channel signed distance field with true distance in the alpha channel. Edge colors must be assigned first.
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePseudoSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePseudoSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
|
||||
// Original simpler versions of the previous functions, which work well under normal circumstances, but cannot deal with overlapping contours.
|
||||
void generateSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePseudoSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generateMSDF_legacy(BitmapSection<float, 3> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateMTSDF_legacy(BitmapSection<float, 4> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
|
||||
}
|
||||
13
Source/ThirdParty/msdfgen/msdfgen/msdfgen/msdfgen-config.h
vendored
Normal file
13
Source/ThirdParty/msdfgen/msdfgen/msdfgen/msdfgen-config.h
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MSDFGEN_PUBLIC
|
||||
#define MSDFGEN_EXT_PUBLIC
|
||||
|
||||
#define MSDFGEN_VERSION 1.13.0
|
||||
#define MSDFGEN_VERSION_MAJOR 1
|
||||
#define MSDFGEN_VERSION_MINOR 13
|
||||
#define MSDFGEN_VERSION_REVISION 0
|
||||
#define MSDFGEN_COPYRIGHT_YEAR 2026
|
||||
|
||||
#define MSDFGEN_USE_CPP11
|
||||
@@ -3290,12 +3290,16 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COMPANY \"{project.Company}\"");
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
|
||||
if (project.VersionControlBranch.Length != 0)
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_BRANCH \"{project.VersionControlBranch}\"");
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_BRANCH {binaryModuleName}Branch");
|
||||
if (project.VersionControlCommit.Length != 0)
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COMMIT \"{project.VersionControlCommit}\"");
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COMMIT {binaryModuleName}Commit");
|
||||
contents.AppendLine();
|
||||
contents.AppendLine("class BinaryModule;");
|
||||
contents.AppendLine($"extern \"C\" {binaryModuleNameUpper}_API BinaryModule* GetBinaryModule{binaryModuleName}();");
|
||||
if (project.VersionControlBranch.Length != 0)
|
||||
contents.AppendLine($"extern \"C\" {binaryModuleNameUpper}_API const char* {binaryModuleName}Branch;");
|
||||
if (project.VersionControlCommit.Length != 0)
|
||||
contents.AppendLine($"extern \"C\" {binaryModuleNameUpper}_API const char* {binaryModuleName}Commit;");
|
||||
GenerateCppBinaryModuleHeader?.Invoke(buildData, binaryModule, contents);
|
||||
Utilities.WriteFileIfChanged(binaryModuleHeaderPath, contents.ToString());
|
||||
|
||||
@@ -3321,6 +3325,10 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
contents.AppendLine(" return &module;");
|
||||
contents.AppendLine("}");
|
||||
if (project.VersionControlBranch.Length != 0)
|
||||
contents.AppendLine($"extern \"C\" const char* {binaryModuleName}Branch = \"{project.VersionControlBranch}\";");
|
||||
if (project.VersionControlCommit.Length != 0)
|
||||
contents.AppendLine($"extern \"C\" const char* {binaryModuleName}Commit = \"{project.VersionControlCommit}\";");
|
||||
GenerateCppBinaryModuleSource?.Invoke(buildData, binaryModule, contents);
|
||||
Utilities.WriteFileIfChanged(binaryModuleSourcePath, contents.ToString());
|
||||
PutStringBuilder(contents);
|
||||
|
||||
160
Source/Tools/Flax.Build/Deps/Dependencies/msdfgen.cs
Normal file
160
Source/Tools/Flax.Build/Deps/Dependencies/msdfgen.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Flax.Build;
|
||||
|
||||
namespace Flax.Deps.Dependencies
|
||||
{
|
||||
/// <summary>
|
||||
/// Multi-channel signed distance field generator. https://github.com/Chlumsky/msdfgen
|
||||
/// </summary>
|
||||
/// <seealso cref="Flax.Deps.Dependency" />
|
||||
class msdfgen : Dependency
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override TargetPlatform[] Platforms
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (BuildPlatform)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
return new[]
|
||||
{
|
||||
TargetPlatform.Windows,
|
||||
TargetPlatform.Android,
|
||||
};
|
||||
case TargetPlatform.Linux:
|
||||
return new[]
|
||||
{
|
||||
TargetPlatform.Linux,
|
||||
};
|
||||
case TargetPlatform.Mac:
|
||||
return new[]
|
||||
{
|
||||
TargetPlatform.Mac,
|
||||
};
|
||||
default: return new TargetPlatform[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TargetArchitecture[] Architectures
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (BuildPlatform)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
return new[]
|
||||
{
|
||||
TargetArchitecture.x64,
|
||||
TargetArchitecture.ARM64,
|
||||
};
|
||||
case TargetPlatform.Linux:
|
||||
return new[]
|
||||
{
|
||||
TargetArchitecture.x64,
|
||||
//TargetArchitecture.ARM64,
|
||||
};
|
||||
case TargetPlatform.Mac:
|
||||
return new[]
|
||||
{
|
||||
TargetArchitecture.x64,
|
||||
TargetArchitecture.ARM64,
|
||||
};
|
||||
default: return new TargetArchitecture[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Build(BuildOptions options)
|
||||
{
|
||||
var root = options.IntermediateFolder;
|
||||
var configuration = "Release";
|
||||
string includeDir = null;
|
||||
var filesToKeep = new[]
|
||||
{
|
||||
"msdfgen.Build.cs",
|
||||
};
|
||||
var args = new string[]
|
||||
{
|
||||
"-DMSDFGEN_USE_VCPKG=OFF",
|
||||
"-DMSDFGEN_CORE_ONLY=ON",
|
||||
"-DMSDFGEN_DYNAMIC_RUNTIME=ON",
|
||||
"-DMSDFGEN_USE_SKIA=OFF",
|
||||
"-DBUILD_SHARED_LIBS=OFF",
|
||||
"-DMSDFGEN_INSTALL=ON"
|
||||
};
|
||||
|
||||
// Get the source
|
||||
var commit = "1874bcf7d9624ccc85b4bc9a85d78116f690f35b"; // Version 1.13
|
||||
CloneGitRepoSingleBranch(root, "https://github.com/Chlumsky/msdfgen.git", "master", commit);
|
||||
|
||||
foreach (var platform in options.Platforms)
|
||||
{
|
||||
foreach (var architecture in options.Architectures)
|
||||
{
|
||||
BuildStarted(platform, architecture);
|
||||
|
||||
var buildDir = Path.Combine(root, "build-" + architecture);
|
||||
var installDir = Path.Combine(root, "install-" + architecture);
|
||||
var depsFolder = GetThirdPartyFolder(options, platform, architecture);
|
||||
includeDir = Path.Combine(installDir, "include");
|
||||
SetupDirectory(buildDir, true);
|
||||
File.Delete(Path.Combine(root, "CMakeCache.txt"));
|
||||
|
||||
Dictionary<string, string> envVars = null;
|
||||
var libName = "libmsdfgen-core.a";
|
||||
var cmakeArgs = string.Join(" ", args);
|
||||
switch (platform)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
case TargetPlatform.XboxOne:
|
||||
case TargetPlatform.XboxScarlett:
|
||||
libName = "msdfgen-core.lib";
|
||||
break;
|
||||
case TargetPlatform.Linux:
|
||||
envVars = new Dictionary<string, string>
|
||||
{
|
||||
{ "CC", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CXX", "clang++-" + Configuration.LinuxClangMinVer },
|
||||
{ "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel },
|
||||
};
|
||||
cmakeArgs += " -DCMAKE_POSITION_INDEPENDENT_CODE=ON";
|
||||
break;
|
||||
}
|
||||
|
||||
RunCmake(root, platform, architecture, $"-B\"{buildDir}\" " + cmakeArgs, envVars);
|
||||
BuildCmake(buildDir);
|
||||
Utilities.Run("cmake", $"--install {buildDir} --prefix {installDir} --config {configuration}", null, root, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.FileCopy(Path.Combine(installDir, "lib", libName), Path.Combine(depsFolder, libName));
|
||||
}
|
||||
}
|
||||
|
||||
// Backup files
|
||||
var dstIncludePath = Path.Combine(options.ThirdPartyFolder, "msdfgen");
|
||||
foreach (var filename in filesToKeep)
|
||||
{
|
||||
var src = Path.Combine(dstIncludePath, filename);
|
||||
var dst = Path.Combine(options.IntermediateFolder, filename + ".tmp");
|
||||
Utilities.FileCopy(src, dst);
|
||||
}
|
||||
|
||||
// Deploy header files and license
|
||||
SetupDirectory(dstIncludePath, true);
|
||||
Utilities.FileCopy(Path.Combine(root, "LICENSE.txt"), Path.Combine(dstIncludePath, "LICENSE.txt"));
|
||||
Utilities.DirectoryCopy(includeDir, dstIncludePath, true, true);
|
||||
foreach (var filename in filesToKeep)
|
||||
{
|
||||
var src = Path.Combine(options.IntermediateFolder, filename + ".tmp");
|
||||
var dst = Path.Combine(dstIncludePath, filename);
|
||||
Utilities.FileCopy(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user