mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-21 20:08:40 +03:00
added msdf-atlas-gen
This commit is contained in:
BIN
Editor/resources/Fonts/RobotoMono-Regular.ttf
Normal file
BIN
Editor/resources/Fonts/RobotoMono-Regular.ttf
Normal file
Binary file not shown.
20
Nuake/src/Vendors/msdf-atlas-gen/.gitignore
vendored
Normal file
20
Nuake/src/Vendors/msdf-atlas-gen/.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Debug/
|
||||
Release/
|
||||
Debug Library/
|
||||
Release Library/
|
||||
x86/
|
||||
x64/
|
||||
*.exe
|
||||
*.user
|
||||
*.sdf
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.iobj
|
||||
*.suo
|
||||
*.VC.opendb
|
||||
*.VC.db
|
||||
bin/msdf-atlas-gen
|
||||
bin/*.lib
|
||||
output.png
|
||||
out/
|
||||
build/
|
||||
6
Nuake/src/Vendors/msdf-atlas-gen/.gitmodules
vendored
Normal file
6
Nuake/src/Vendors/msdf-atlas-gen/.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "msdfgen"]
|
||||
path = msdfgen
|
||||
url = https://github.com/Chlumsky/msdfgen
|
||||
[submodule "artery-font-format"]
|
||||
path = artery-font-format
|
||||
url = https://github.com/Chlumsky/artery-font-format
|
||||
42
Nuake/src/Vendors/msdf-atlas-gen/AtlasGenerator.h
Normal file
42
Nuake/src/Vendors/msdf-atlas-gen/AtlasGenerator.h
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "msdfgen.h"
|
||||
#include "Remap.h"
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
namespace {
|
||||
|
||||
/** Prototype of an atlas generator class.
|
||||
* An atlas generator maintains the atlas bitmap (AtlasStorage) and its layout and facilitates
|
||||
* generation of bitmap representation of glyphs. The layout of the atlas is given by the caller.
|
||||
*/
|
||||
class AtlasGenerator {
|
||||
|
||||
public:
|
||||
AtlasGenerator();
|
||||
AtlasGenerator(int width, int height);
|
||||
/// Generates bitmap representation for the supplied array of glyphs
|
||||
void generate(const GlyphGeometry *glyphs, int count);
|
||||
/// Resizes the atlas and rearranges the generated pixels according to the remapping array
|
||||
void rearrange(int width, int height, const Remap *remapping, int count);
|
||||
/// Resizes the atlas and keeps the generated pixels in place
|
||||
void resize(int width, int height);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// Configuration of signed distance field generator
|
||||
struct GeneratorAttributes {
|
||||
msdfgen::MSDFGeneratorConfig config;
|
||||
bool scanlinePass = false;
|
||||
};
|
||||
|
||||
/// A function that generates the bitmap for a single glyph
|
||||
template <typename T, int N>
|
||||
using GeneratorFunction = void (*)(const msdfgen::BitmapRef<T, N> &, const GlyphGeometry &, const GeneratorAttributes &);
|
||||
|
||||
}
|
||||
37
Nuake/src/Vendors/msdf-atlas-gen/AtlasStorage.h
Normal file
37
Nuake/src/Vendors/msdf-atlas-gen/AtlasStorage.h
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include "Remap.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
namespace {
|
||||
|
||||
/** Prototype of an atlas storage class.
|
||||
* An atlas storage physically holds the pixels of the atlas
|
||||
* and allows to read and write subsections represented as bitmaps.
|
||||
* Can be implemented using a simple bitmap (BitmapAtlasStorage),
|
||||
* as texture memory, or any other way.
|
||||
*/
|
||||
class AtlasStorage {
|
||||
|
||||
public:
|
||||
AtlasStorage();
|
||||
AtlasStorage(int width, int height);
|
||||
/// Creates a copy with different dimensions
|
||||
AtlasStorage(const AtlasStorage &orig, int width, int height);
|
||||
/// Creates a copy with different dimensions and rearranges the pixels according to the remapping array
|
||||
AtlasStorage(const AtlasStorage &orig, int width, int height, const Remap *remapping, int count);
|
||||
/// Stores a subsection at x, y into the atlas storage. May be implemented for only some T, N
|
||||
template <typename T, int N>
|
||||
void put(int x, int y, const msdfgen::BitmapConstRef<T, N> &subBitmap);
|
||||
/// Retrieves a subsection at x, y from the atlas storage. May be implemented for only some T, N
|
||||
template <typename T, int N>
|
||||
void get(int x, int y, const msdfgen::BitmapRef<T, N> &subBitmap) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
33
Nuake/src/Vendors/msdf-atlas-gen/BitmapAtlasStorage.h
Normal file
33
Nuake/src/Vendors/msdf-atlas-gen/BitmapAtlasStorage.h
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AtlasStorage.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// An implementation of AtlasStorage represented by a bitmap in memory (msdfgen::Bitmap)
|
||||
template <typename T, int N>
|
||||
class BitmapAtlasStorage {
|
||||
|
||||
public:
|
||||
BitmapAtlasStorage();
|
||||
BitmapAtlasStorage(int width, int height);
|
||||
explicit BitmapAtlasStorage(const msdfgen::BitmapConstRef<T, N> &bitmap);
|
||||
explicit BitmapAtlasStorage(msdfgen::Bitmap<T, N> &&bitmap);
|
||||
BitmapAtlasStorage(const BitmapAtlasStorage<T, N> &orig, int width, int height);
|
||||
BitmapAtlasStorage(const BitmapAtlasStorage<T, N> &orig, int width, int height, const Remap *remapping, int count);
|
||||
operator msdfgen::BitmapConstRef<T, N>() const;
|
||||
operator msdfgen::BitmapRef<T, N>();
|
||||
operator msdfgen::Bitmap<T, N>() &&;
|
||||
template <typename S>
|
||||
void put(int x, int y, const msdfgen::BitmapConstRef<S, N> &subBitmap);
|
||||
void get(int x, int y, const msdfgen::BitmapRef<T, N> &subBitmap) const;
|
||||
|
||||
private:
|
||||
msdfgen::Bitmap<T, N> bitmap;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "BitmapAtlasStorage.hpp"
|
||||
65
Nuake/src/Vendors/msdf-atlas-gen/BitmapAtlasStorage.hpp
Normal file
65
Nuake/src/Vendors/msdf-atlas-gen/BitmapAtlasStorage.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
#include "BitmapAtlasStorage.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include "bitmap-blit.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::BitmapAtlasStorage() { }
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::BitmapAtlasStorage(int width, int height) : bitmap(width, height) {
|
||||
memset((T *) bitmap, 0, sizeof(T)*N*width*height);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::BitmapAtlasStorage(const msdfgen::BitmapConstRef<T, N> &bitmap) : bitmap(bitmap) { }
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::BitmapAtlasStorage(msdfgen::Bitmap<T, N> &&bitmap) : bitmap((msdfgen::Bitmap<T, N> &&) bitmap) { }
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::BitmapAtlasStorage(const BitmapAtlasStorage<T, N> &orig, int width, int height) : bitmap(width, height) {
|
||||
memset((T *) bitmap, 0, sizeof(T)*N*width*height);
|
||||
blit(bitmap, orig.bitmap, 0, 0, 0, 0, std::min(width, orig.bitmap.width()), std::min(height, orig.bitmap.height()));
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::BitmapAtlasStorage(const BitmapAtlasStorage<T, N> &orig, int width, int height, const Remap *remapping, int count) : bitmap(width, height) {
|
||||
memset((T *) bitmap, 0, sizeof(T)*N*width*height);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const Remap &remap = remapping[i];
|
||||
blit(bitmap, orig.bitmap, remap.target.x, remap.target.y, remap.source.x, remap.source.y, remap.width, remap.height);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::operator msdfgen::BitmapConstRef<T, N>() const {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::operator msdfgen::BitmapRef<T, N>() {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapAtlasStorage<T, N>::operator msdfgen::Bitmap<T, N>() && {
|
||||
return (msdfgen::Bitmap<T, N> &&) bitmap;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
template <typename S>
|
||||
void BitmapAtlasStorage<T, N>::put(int x, int y, const msdfgen::BitmapConstRef<S, N> &subBitmap) {
|
||||
blit(bitmap, subBitmap, x, y, 0, 0, subBitmap.width, subBitmap.height);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
void BitmapAtlasStorage<T, N>::get(int x, int y, const msdfgen::BitmapRef<T, N> &subBitmap) const {
|
||||
blit(subBitmap, bitmap, 0, 0, x, y, subBitmap.width, subBitmap.height);
|
||||
}
|
||||
|
||||
}
|
||||
26
Nuake/src/Vendors/msdf-atlas-gen/CHANGELOG.md
Normal file
26
Nuake/src/Vendors/msdf-atlas-gen/CHANGELOG.md
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
## Version 1.2 (2021-05-29)
|
||||
|
||||
- Updated to MSDFgen 1.9.
|
||||
- Multiple fonts or font sizes can now be compiled into a single atlas.
|
||||
- Added `-yorigin` option to choose if Y-coordinates increase from bottom to top or from top to bottom.
|
||||
- Added `-coloringstrategy` option to select MSDF edge coloring heuristic.
|
||||
- Shadron preview now properly loads floating-point image outputs in full range mode.
|
||||
|
||||
## Version 1.1 (2020-10-18)
|
||||
|
||||
- Updated to MSDFgen 1.8.
|
||||
- Glyph geometry is now preprocessed by Skia to resolve irregularities which were previously unsupported and caused artifacts.
|
||||
- The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively.
|
||||
- The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA`.
|
||||
- Glyphs can now also be loaded by glyph index rather than Unicode values. In the standalone version, a set of glyphs can be passed by `-glyphset` in place of `-charset`.
|
||||
- Glyphs not present in the font should now be correctly skipped instead of producing a placeholder symbol.
|
||||
- Added `-threads` argument to set the number of concurrent threads used during distance field generation.
|
||||
|
||||
### Version 1.0.1 (2020-03-09)
|
||||
|
||||
- Updated to MSDFgen 1.7.1.
|
||||
|
||||
## Version 1.0 (2020-03-08)
|
||||
|
||||
- Initial release.
|
||||
39
Nuake/src/Vendors/msdf-atlas-gen/Charset.cpp
Normal file
39
Nuake/src/Vendors/msdf-atlas-gen/Charset.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
#include "Charset.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static Charset createAsciiCharset() {
|
||||
Charset ascii;
|
||||
for (unicode_t cp = 0x20; cp < 0x7f; ++cp)
|
||||
ascii.add(cp);
|
||||
return ascii;
|
||||
}
|
||||
|
||||
const Charset Charset::ASCII = createAsciiCharset();
|
||||
|
||||
void Charset::add(unicode_t cp) {
|
||||
codepoints.insert(cp);
|
||||
}
|
||||
|
||||
void Charset::remove(unicode_t cp) {
|
||||
codepoints.erase(cp);
|
||||
}
|
||||
|
||||
size_t Charset::size() const {
|
||||
return codepoints.size();
|
||||
}
|
||||
|
||||
bool Charset::empty() const {
|
||||
return codepoints.empty();
|
||||
}
|
||||
|
||||
std::set<unicode_t>::const_iterator Charset::begin() const {
|
||||
return codepoints.begin();
|
||||
}
|
||||
|
||||
std::set<unicode_t>::const_iterator Charset::end() const {
|
||||
return codepoints.end();
|
||||
}
|
||||
|
||||
}
|
||||
35
Nuake/src/Vendors/msdf-atlas-gen/Charset.h
Normal file
35
Nuake/src/Vendors/msdf-atlas-gen/Charset.h
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <set>
|
||||
#include "types.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Represents a set of Unicode codepoints (characters)
|
||||
class Charset {
|
||||
|
||||
public:
|
||||
/// The set of the 95 printable ASCII characters
|
||||
static const Charset ASCII;
|
||||
|
||||
/// Adds a codepoint
|
||||
void add(unicode_t cp);
|
||||
/// Removes a codepoint
|
||||
void remove(unicode_t cp);
|
||||
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
std::set<unicode_t>::const_iterator begin() const;
|
||||
std::set<unicode_t>::const_iterator end() const;
|
||||
|
||||
/// Load character set from a text file with the correct syntax
|
||||
bool load(const char *filename, bool disableCharLiterals = false);
|
||||
|
||||
private:
|
||||
std::set<unicode_t> codepoints;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
43
Nuake/src/Vendors/msdf-atlas-gen/DynamicAtlas.h
Normal file
43
Nuake/src/Vendors/msdf-atlas-gen/DynamicAtlas.h
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "RectanglePacker.h"
|
||||
#include "AtlasGenerator.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* This class can be used to produce a dynamic atlas to which more glyphs are added over time.
|
||||
* It takes care of laying out and enlarging the atlas as necessary and delegates the actual work
|
||||
* to the specified AtlasGenerator, which may e.g. do the work asynchronously.
|
||||
*/
|
||||
template <class AtlasGenerator>
|
||||
class DynamicAtlas {
|
||||
|
||||
public:
|
||||
DynamicAtlas();
|
||||
/// Creates with a configured generator. The generator must not contain any prior glyphs!
|
||||
explicit DynamicAtlas(AtlasGenerator &&generator);
|
||||
/// Adds a batch of glyphs. Adding more than one glyph at a time may improve packing efficiency
|
||||
void add(GlyphGeometry *glyphs, int count);
|
||||
/// Allows access to generator. Do not add glyphs to the generator directly!
|
||||
AtlasGenerator & atlasGenerator();
|
||||
const AtlasGenerator & atlasGenerator() const;
|
||||
|
||||
private:
|
||||
AtlasGenerator generator;
|
||||
RectanglePacker packer;
|
||||
int glyphCount;
|
||||
int side;
|
||||
std::vector<Rectangle> rectangles;
|
||||
std::vector<Remap> remapBuffer;
|
||||
int totalArea;
|
||||
GeneratorAttributes genAttribs;
|
||||
int padding;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "DynamicAtlas.hpp"
|
||||
69
Nuake/src/Vendors/msdf-atlas-gen/DynamicAtlas.hpp
Normal file
69
Nuake/src/Vendors/msdf-atlas-gen/DynamicAtlas.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
#include "DynamicAtlas.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
template <class AtlasGenerator>
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas() : glyphCount(0), side(0), totalArea(0), padding(0) { }
|
||||
|
||||
template <class AtlasGenerator>
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas(AtlasGenerator &&generator) : generator((AtlasGenerator &&) generator), glyphCount(0), side(0), totalArea(0), padding(0) { }
|
||||
|
||||
template <class AtlasGenerator>
|
||||
void DynamicAtlas<AtlasGenerator>::add(GlyphGeometry *glyphs, int count) {
|
||||
int start = rectangles.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!glyphs[i].isWhitespace()) {
|
||||
int w, h;
|
||||
glyphs[i].getBoxSize(w, h);
|
||||
Rectangle rect = { 0, 0, w+padding, h+padding };
|
||||
rectangles.push_back(rect);
|
||||
Remap remapEntry = { };
|
||||
remapEntry.index = glyphCount+i;
|
||||
remapEntry.width = w;
|
||||
remapEntry.height = h;
|
||||
remapBuffer.push_back(remapEntry);
|
||||
totalArea += (w+padding)*(h+padding);
|
||||
}
|
||||
}
|
||||
if ((int) rectangles.size() > start) {
|
||||
int oldSide = side;
|
||||
int packerStart = start;
|
||||
while (packer.pack(rectangles.data()+packerStart, rectangles.size()-packerStart) > 0) {
|
||||
side = side+!side<<1;
|
||||
while (side*side < totalArea)
|
||||
side <<= 1;
|
||||
packer = RectanglePacker(side+padding, side+padding);
|
||||
packerStart = 0;
|
||||
}
|
||||
if (packerStart < start) {
|
||||
for (int i = 0; i < start; ++i) {
|
||||
Remap &remap = remapBuffer[i];
|
||||
remap.source = remap.target;
|
||||
remap.target.x = rectangles[i].x;
|
||||
remap.target.y = rectangles[i].y;
|
||||
}
|
||||
generator.rearrange(side, side, remapBuffer.data(), start);
|
||||
} else if (side != oldSide)
|
||||
generator.resize(side, side);
|
||||
for (int i = start; i < (int) rectangles.size(); ++i) {
|
||||
remapBuffer[i].target.x = rectangles[i].x;
|
||||
remapBuffer[i].target.y = rectangles[i].y;
|
||||
glyphs[remapBuffer[i].index-glyphCount].placeBox(rectangles[i].x, rectangles[i].y);
|
||||
}
|
||||
}
|
||||
generator.generate(glyphs, count, genAttribs);
|
||||
glyphCount += count;
|
||||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
AtlasGenerator & DynamicAtlas<AtlasGenerator>::atlasGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
const AtlasGenerator & DynamicAtlas<AtlasGenerator>::atlasGenerator() const {
|
||||
return generator;
|
||||
}
|
||||
|
||||
}
|
||||
185
Nuake/src/Vendors/msdf-atlas-gen/FontGeometry.cpp
Normal file
185
Nuake/src/Vendors/msdf-atlas-gen/FontGeometry.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
FontGeometry::GlyphRange::GlyphRange() : glyphs(), rangeStart(), rangeEnd() { }
|
||||
|
||||
FontGeometry::GlyphRange::GlyphRange(const std::vector<GlyphGeometry> *glyphs, size_t rangeStart, size_t rangeEnd) : glyphs(glyphs), rangeStart(rangeStart), rangeEnd(rangeEnd) { }
|
||||
|
||||
size_t FontGeometry::GlyphRange::size() const {
|
||||
return glyphs->size();
|
||||
}
|
||||
|
||||
bool FontGeometry::GlyphRange::empty() const {
|
||||
return glyphs->empty();
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::GlyphRange::begin() const {
|
||||
return glyphs->data()+rangeStart;
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::GlyphRange::end() const {
|
||||
return glyphs->data()+rangeEnd;
|
||||
}
|
||||
|
||||
FontGeometry::FontGeometry() : geometryScale(1), metrics(), preferredIdentifierType(GlyphIdentifierType::UNICODE_CODEPOINT), glyphs(&ownGlyphs), rangeStart(glyphs->size()), rangeEnd(glyphs->size()) { }
|
||||
|
||||
FontGeometry::FontGeometry(std::vector<GlyphGeometry> *glyphStorage) : geometryScale(1), metrics(), preferredIdentifierType(GlyphIdentifierType::UNICODE_CODEPOINT), glyphs(glyphStorage), rangeStart(glyphs->size()), rangeEnd(glyphs->size()) { }
|
||||
|
||||
int FontGeometry::loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry, bool enableKerning) {
|
||||
if (!(glyphs->size() == rangeEnd && loadMetrics(font, fontScale)))
|
||||
return -1;
|
||||
glyphs->reserve(glyphs->size()+glyphset.size());
|
||||
int loaded = 0;
|
||||
for (unicode_t index : glyphset) {
|
||||
GlyphGeometry glyph;
|
||||
if (glyph.load(font, geometryScale, msdfgen::GlyphIndex(index), preprocessGeometry)) {
|
||||
addGlyph((GlyphGeometry &&) glyph);
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
if (enableKerning)
|
||||
loadKerning(font);
|
||||
preferredIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
int FontGeometry::loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry, bool enableKerning) {
|
||||
if (!(glyphs->size() == rangeEnd && loadMetrics(font, fontScale)))
|
||||
return -1;
|
||||
glyphs->reserve(glyphs->size()+charset.size());
|
||||
int loaded = 0;
|
||||
for (unicode_t cp : charset) {
|
||||
GlyphGeometry glyph;
|
||||
if (glyph.load(font, geometryScale, cp, preprocessGeometry)) {
|
||||
addGlyph((GlyphGeometry &&) glyph);
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
if (enableKerning)
|
||||
loadKerning(font);
|
||||
preferredIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
bool FontGeometry::loadMetrics(msdfgen::FontHandle *font, double fontScale) {
|
||||
if (!msdfgen::getFontMetrics(metrics, font))
|
||||
return false;
|
||||
if (metrics.emSize <= 0)
|
||||
metrics.emSize = MSDF_ATLAS_DEFAULT_EM_SIZE;
|
||||
geometryScale = fontScale/metrics.emSize;
|
||||
metrics.emSize *= geometryScale;
|
||||
metrics.ascenderY *= geometryScale;
|
||||
metrics.descenderY *= geometryScale;
|
||||
metrics.lineHeight *= geometryScale;
|
||||
metrics.underlineY *= geometryScale;
|
||||
metrics.underlineThickness *= geometryScale;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGeometry::addGlyph(const GlyphGeometry &glyph) {
|
||||
if (glyphs->size() != rangeEnd)
|
||||
return false;
|
||||
glyphsByIndex.insert(std::make_pair(glyph.getIndex(), rangeEnd));
|
||||
if (glyph.getCodepoint())
|
||||
glyphsByCodepoint.insert(std::make_pair(glyph.getCodepoint(), rangeEnd));
|
||||
glyphs->push_back(glyph);
|
||||
++rangeEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGeometry::addGlyph(GlyphGeometry &&glyph) {
|
||||
if (glyphs->size() != rangeEnd)
|
||||
return false;
|
||||
glyphsByIndex.insert(std::make_pair(glyph.getIndex(), rangeEnd));
|
||||
if (glyph.getCodepoint())
|
||||
glyphsByCodepoint.insert(std::make_pair(glyph.getCodepoint(), rangeEnd));
|
||||
glyphs->push_back((GlyphGeometry &&) glyph);
|
||||
++rangeEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
int FontGeometry::loadKerning(msdfgen::FontHandle *font) {
|
||||
int loaded = 0;
|
||||
for (size_t i = rangeStart; i < rangeEnd; ++i)
|
||||
for (size_t j = rangeStart; j < rangeEnd; ++j) {
|
||||
double advance;
|
||||
if (msdfgen::getKerning(advance, font, (*glyphs)[i].getGlyphIndex(), (*glyphs)[j].getGlyphIndex()) && advance) {
|
||||
kerning[std::make_pair<int, int>((*glyphs)[i].getIndex(), (*glyphs)[j].getIndex())] = geometryScale*advance;
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void FontGeometry::setName(const char *name) {
|
||||
if (name)
|
||||
this->name = name;
|
||||
else
|
||||
this->name.clear();
|
||||
}
|
||||
|
||||
double FontGeometry::getGeometryScale() const {
|
||||
return geometryScale;
|
||||
}
|
||||
|
||||
const msdfgen::FontMetrics & FontGeometry::getMetrics() const {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
GlyphIdentifierType FontGeometry::getPreferredIdentifierType() const {
|
||||
return preferredIdentifierType;
|
||||
}
|
||||
|
||||
FontGeometry::GlyphRange FontGeometry::getGlyphs() const {
|
||||
return GlyphRange(glyphs, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::getGlyph(msdfgen::GlyphIndex index) const {
|
||||
std::map<int, size_t>::const_iterator it = glyphsByIndex.find(index.getIndex());
|
||||
if (it != glyphsByIndex.end())
|
||||
return &(*glyphs)[it->second];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::getGlyph(unicode_t codepoint) const {
|
||||
std::map<unicode_t, size_t>::const_iterator it = glyphsByCodepoint.find(codepoint);
|
||||
if (it != glyphsByCodepoint.end())
|
||||
return &(*glyphs)[it->second];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FontGeometry::getAdvance(double &advance, msdfgen::GlyphIndex index1, msdfgen::GlyphIndex index2) const {
|
||||
const GlyphGeometry *glyph1 = getGlyph(index1);
|
||||
if (!glyph1)
|
||||
return false;
|
||||
advance = glyph1->getAdvance();
|
||||
std::map<std::pair<int, int>, double>::const_iterator it = kerning.find(std::make_pair<int, int>(index1.getIndex(), index2.getIndex()));
|
||||
if (it != kerning.end())
|
||||
advance += it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGeometry::getAdvance(double &advance, unicode_t codepoint1, unicode_t codepoint2) const {
|
||||
const GlyphGeometry *glyph1, *glyph2;
|
||||
if (!((glyph1 = getGlyph(codepoint1)) && (glyph2 = getGlyph(codepoint2))))
|
||||
return false;
|
||||
advance = glyph1->getAdvance();
|
||||
std::map<std::pair<int, int>, double>::const_iterator it = kerning.find(std::make_pair<int, int>(glyph1->getIndex(), glyph2->getIndex()));
|
||||
if (it != kerning.end())
|
||||
advance += it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, double> & FontGeometry::getKerning() const {
|
||||
return kerning;
|
||||
}
|
||||
|
||||
const char * FontGeometry::getName() const {
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
return name.c_str();
|
||||
}
|
||||
|
||||
}
|
||||
86
Nuake/src/Vendors/msdf-atlas-gen/FontGeometry.h
Normal file
86
Nuake/src/Vendors/msdf-atlas-gen/FontGeometry.h
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "Charset.h"
|
||||
|
||||
#define MSDF_ATLAS_DEFAULT_EM_SIZE 32.0
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Represents the geometry of all glyphs of a given font or font variant
|
||||
class FontGeometry {
|
||||
|
||||
public:
|
||||
class GlyphRange {
|
||||
public:
|
||||
GlyphRange();
|
||||
GlyphRange(const std::vector<GlyphGeometry> *glyphs, size_t rangeStart, size_t rangeEnd);
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
const GlyphGeometry * begin() const;
|
||||
const GlyphGeometry * end() const;
|
||||
private:
|
||||
const std::vector<GlyphGeometry> *glyphs;
|
||||
size_t rangeStart, rangeEnd;
|
||||
};
|
||||
|
||||
FontGeometry();
|
||||
explicit FontGeometry(std::vector<GlyphGeometry> *glyphStorage);
|
||||
|
||||
/// Loads all glyphs in a glyphset (Charset elements are glyph indices), returns the number of successfully loaded glyphs
|
||||
int loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry = true, bool enableKerning = true);
|
||||
/// Loads all glyphs in a charset (Charset elements are Unicode codepoints), returns the number of successfully loaded glyphs
|
||||
int loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry = true, bool enableKerning = true);
|
||||
|
||||
/// Only loads font metrics and geometry scale from font
|
||||
bool loadMetrics(msdfgen::FontHandle *font, double fontScale);
|
||||
/// Adds a loaded glyph
|
||||
bool addGlyph(const GlyphGeometry &glyph);
|
||||
bool addGlyph(GlyphGeometry &&glyph);
|
||||
/// Loads kerning pairs for all glyphs that are currently present, returns the number of loaded kerning pairs
|
||||
int loadKerning(msdfgen::FontHandle *font);
|
||||
/// Sets a name to be associated with the font
|
||||
void setName(const char *name);
|
||||
|
||||
/// Returns the geometry scale to be used when loading glyphs
|
||||
double getGeometryScale() const;
|
||||
/// Returns the processed font metrics
|
||||
const msdfgen::FontMetrics & getMetrics() const;
|
||||
/// Returns the type of identifier that was used to load glyphs
|
||||
GlyphIdentifierType getPreferredIdentifierType() const;
|
||||
/// Returns the list of all glyphs
|
||||
GlyphRange getGlyphs() const;
|
||||
/// Finds a glyph by glyph index or Unicode codepoint, returns null if not found
|
||||
const GlyphGeometry * getGlyph(msdfgen::GlyphIndex index) const;
|
||||
const GlyphGeometry * getGlyph(unicode_t codepoint) const;
|
||||
/// Outputs the advance between two glyphs with kerning taken into consideration, returns false on failure
|
||||
bool getAdvance(double &advance, msdfgen::GlyphIndex index1, msdfgen::GlyphIndex index2) const;
|
||||
bool getAdvance(double &advance, unicode_t codepoint1, unicode_t codepoint2) const;
|
||||
/// Returns the complete mapping of kerning pairs (by glyph indices) and their respective advance values
|
||||
const std::map<std::pair<int, int>, double> & getKerning() const;
|
||||
/// Returns the name associated with the font or null if not set
|
||||
const char * getName() const;
|
||||
|
||||
private:
|
||||
double geometryScale;
|
||||
msdfgen::FontMetrics metrics;
|
||||
GlyphIdentifierType preferredIdentifierType;
|
||||
std::vector<GlyphGeometry> *glyphs;
|
||||
size_t rangeStart, rangeEnd;
|
||||
std::map<int, size_t> glyphsByIndex;
|
||||
std::map<unicode_t, size_t> glyphsByCodepoint;
|
||||
std::map<std::pair<int, int>, double> kerning;
|
||||
std::vector<GlyphGeometry> ownGlyphs;
|
||||
std::string name;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
19
Nuake/src/Vendors/msdf-atlas-gen/GlyphBox.h
Normal file
19
Nuake/src/Vendors/msdf-atlas-gen/GlyphBox.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// The glyph box - its bounds in plane and atlas
|
||||
struct GlyphBox {
|
||||
int index;
|
||||
double advance;
|
||||
struct {
|
||||
double l, b, r, t;
|
||||
} bounds;
|
||||
struct {
|
||||
int x, y, w, h;
|
||||
} rect;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
170
Nuake/src/Vendors/msdf-atlas-gen/GlyphGeometry.cpp
Normal file
170
Nuake/src/Vendors/msdf-atlas-gen/GlyphGeometry.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <core/ShapeDistanceFinder.h>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
GlyphGeometry::GlyphGeometry() : index(), codepoint(), geometryScale(), bounds(), advance(), box() { }
|
||||
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry) {
|
||||
if (font && msdfgen::loadGlyph(shape, font, index, &advance) && shape.validate()) {
|
||||
this->index = index.getIndex();
|
||||
this->geometryScale = geometryScale;
|
||||
codepoint = 0;
|
||||
advance *= geometryScale;
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
if (preprocessGeometry)
|
||||
msdfgen::resolveShapeGeometry(shape);
|
||||
#endif
|
||||
shape.normalize();
|
||||
bounds = shape.getBounds();
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
if (!preprocessGeometry)
|
||||
#endif
|
||||
{
|
||||
// Determine if shape is winded incorrectly and reverse it in that case
|
||||
msdfgen::Point2 outerPoint(bounds.l-(bounds.r-bounds.l)-1, bounds.b-(bounds.t-bounds.b)-1);
|
||||
if (msdfgen::SimpleTrueShapeDistanceFinder::oneShotDistance(shape, outerPoint) > 0) {
|
||||
for (msdfgen::Contour &contour : shape.contours)
|
||||
contour.reverse();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry) {
|
||||
msdfgen::GlyphIndex index;
|
||||
if (msdfgen::getGlyphIndex(index, font, codepoint)) {
|
||||
if (load(font, geometryScale, index, preprocessGeometry)) {
|
||||
this->codepoint = codepoint;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GlyphGeometry::edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned long long), double angleThreshold, unsigned long long seed) {
|
||||
fn(shape, angleThreshold, seed);
|
||||
}
|
||||
|
||||
void GlyphGeometry::wrapBox(double scale, double range, double miterLimit) {
|
||||
scale *= geometryScale;
|
||||
range /= geometryScale;
|
||||
box.range = range;
|
||||
box.scale = scale;
|
||||
if (bounds.l < bounds.r && bounds.b < bounds.t) {
|
||||
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
|
||||
l -= .5*range, b -= .5*range;
|
||||
r += .5*range, t += .5*range;
|
||||
if (miterLimit > 0)
|
||||
shape.boundMiters(l, b, r, t, .5*range, miterLimit, 1);
|
||||
double w = scale*(r-l);
|
||||
double h = scale*(t-b);
|
||||
box.rect.w = (int) ceil(w)+1;
|
||||
box.rect.h = (int) ceil(h)+1;
|
||||
box.translate.x = -l+.5*(box.rect.w-w)/scale;
|
||||
box.translate.y = -b+.5*(box.rect.h-h)/scale;
|
||||
} else {
|
||||
box.rect.w = 0, box.rect.h = 0;
|
||||
box.translate = msdfgen::Vector2();
|
||||
}
|
||||
}
|
||||
|
||||
void GlyphGeometry::placeBox(int x, int y) {
|
||||
box.rect.x = x, box.rect.y = y;
|
||||
}
|
||||
|
||||
int GlyphGeometry::getIndex() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
msdfgen::GlyphIndex GlyphGeometry::getGlyphIndex() const {
|
||||
return msdfgen::GlyphIndex(index);
|
||||
}
|
||||
|
||||
unicode_t GlyphGeometry::getCodepoint() const {
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
int GlyphGeometry::getIdentifier(GlyphIdentifierType type) const {
|
||||
switch (type) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
return index;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
return (int) codepoint;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const msdfgen::Shape & GlyphGeometry::getShape() const {
|
||||
return shape;
|
||||
}
|
||||
|
||||
double GlyphGeometry::getAdvance() const {
|
||||
return advance;
|
||||
}
|
||||
|
||||
void GlyphGeometry::getBoxRect(int &x, int &y, int &w, int &h) const {
|
||||
x = box.rect.x, y = box.rect.y;
|
||||
w = box.rect.w, h = box.rect.h;
|
||||
}
|
||||
|
||||
void GlyphGeometry::getBoxSize(int &w, int &h) const {
|
||||
w = box.rect.w, h = box.rect.h;
|
||||
}
|
||||
|
||||
double GlyphGeometry::getBoxRange() const {
|
||||
return box.range;
|
||||
}
|
||||
|
||||
msdfgen::Projection GlyphGeometry::getBoxProjection() const {
|
||||
return msdfgen::Projection(msdfgen::Vector2(box.scale), box.translate);
|
||||
}
|
||||
|
||||
double GlyphGeometry::getBoxScale() const {
|
||||
return box.scale;
|
||||
}
|
||||
|
||||
msdfgen::Vector2 GlyphGeometry::getBoxTranslate() const {
|
||||
return box.translate;
|
||||
}
|
||||
|
||||
void GlyphGeometry::getQuadPlaneBounds(double &l, double &b, double &r, double &t) const {
|
||||
if (box.rect.w > 0 && box.rect.h > 0) {
|
||||
double invBoxScale = 1/box.scale;
|
||||
l = geometryScale*(-box.translate.x+.5*invBoxScale);
|
||||
b = geometryScale*(-box.translate.y+.5*invBoxScale);
|
||||
r = geometryScale*(-box.translate.x+(box.rect.w-.5)*invBoxScale);
|
||||
t = geometryScale*(-box.translate.y+(box.rect.h-.5)*invBoxScale);
|
||||
} else
|
||||
l = 0, b = 0, r = 0, t = 0;
|
||||
}
|
||||
|
||||
void GlyphGeometry::getQuadAtlasBounds(double &l, double &b, double &r, double &t) const {
|
||||
if (box.rect.w > 0 && box.rect.h > 0) {
|
||||
l = box.rect.x+.5;
|
||||
b = box.rect.y+.5;
|
||||
r = box.rect.x+box.rect.w-.5;
|
||||
t = box.rect.y+box.rect.h-.5;
|
||||
} else
|
||||
l = 0, b = 0, r = 0, t = 0;
|
||||
}
|
||||
|
||||
bool GlyphGeometry::isWhitespace() const {
|
||||
return shape.contours.empty();
|
||||
}
|
||||
|
||||
GlyphGeometry::operator GlyphBox() const {
|
||||
GlyphBox box;
|
||||
box.index = index;
|
||||
box.advance = advance;
|
||||
getQuadPlaneBounds(box.bounds.l, box.bounds.b, box.bounds.r, box.bounds.t);
|
||||
box.rect.x = this->box.rect.x, box.rect.y = this->box.rect.y, box.rect.w = this->box.rect.w, box.rect.h = this->box.rect.h;
|
||||
return box;
|
||||
}
|
||||
|
||||
}
|
||||
76
Nuake/src/Vendors/msdf-atlas-gen/GlyphGeometry.h
Normal file
76
Nuake/src/Vendors/msdf-atlas-gen/GlyphGeometry.h
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "GlyphBox.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Represents the shape geometry of a single glyph as well as its configuration
|
||||
class GlyphGeometry {
|
||||
|
||||
public:
|
||||
GlyphGeometry();
|
||||
/// Loads glyph geometry from font
|
||||
bool load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry = true);
|
||||
bool load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry = true);
|
||||
/// Applies edge coloring to glyph shape
|
||||
void edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned long long), double angleThreshold, unsigned long long seed);
|
||||
/// Computes the dimensions of the glyph's box as well as the transformation for the generator function
|
||||
void wrapBox(double scale, double range, double miterLimit);
|
||||
/// Sets the glyph's box's position in the atlas
|
||||
void placeBox(int x, int y);
|
||||
/// Returns the glyph's index within the font
|
||||
int getIndex() const;
|
||||
/// Returns the glyph's index as a msdfgen::GlyphIndex
|
||||
msdfgen::GlyphIndex getGlyphIndex() const;
|
||||
/// Returns the Unicode codepoint represented by the glyph or 0 if unknown
|
||||
unicode_t getCodepoint() const;
|
||||
/// Returns the glyph's identifier specified by the supplied identifier type
|
||||
int getIdentifier(GlyphIdentifierType type) const;
|
||||
/// Returns the glyph's shape
|
||||
const msdfgen::Shape & getShape() const;
|
||||
/// Returns the glyph's advance
|
||||
double getAdvance() const;
|
||||
/// Outputs the position and dimensions of the glyph's box in the atlas
|
||||
void getBoxRect(int &x, int &y, int &w, int &h) const;
|
||||
/// Outputs the dimensions of the glyph's box in the atlas
|
||||
void getBoxSize(int &w, int &h) const;
|
||||
/// Returns the range needed to generate the glyph's SDF
|
||||
double getBoxRange() const;
|
||||
/// Returns the projection needed to generate the glyph's bitmap
|
||||
msdfgen::Projection getBoxProjection() const;
|
||||
/// Returns the scale needed to generate the glyph's bitmap
|
||||
double getBoxScale() const;
|
||||
/// Returns the translation vector needed to generate the glyph's bitmap
|
||||
msdfgen::Vector2 getBoxTranslate() const;
|
||||
/// Outputs the bounding box of the glyph as it should be placed on the baseline
|
||||
void getQuadPlaneBounds(double &l, double &b, double &r, double &t) const;
|
||||
/// Outputs the bounding box of the glyph in the atlas
|
||||
void getQuadAtlasBounds(double &l, double &b, double &r, double &t) const;
|
||||
/// Returns true if the glyph is a whitespace and has no geometry
|
||||
bool isWhitespace() const;
|
||||
/// Simplifies to GlyphBox
|
||||
operator GlyphBox() const;
|
||||
|
||||
private:
|
||||
int index;
|
||||
unicode_t codepoint;
|
||||
double geometryScale;
|
||||
msdfgen::Shape shape;
|
||||
msdfgen::Shape::Bounds bounds;
|
||||
double advance;
|
||||
struct {
|
||||
struct {
|
||||
int x, y, w, h;
|
||||
} rect;
|
||||
double range;
|
||||
double scale;
|
||||
msdfgen::Vector2 translate;
|
||||
} box;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
45
Nuake/src/Vendors/msdf-atlas-gen/ImmediateAtlasGenerator.h
Normal file
45
Nuake/src/Vendors/msdf-atlas-gen/ImmediateAtlasGenerator.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GlyphBox.h"
|
||||
#include "Workload.h"
|
||||
#include "AtlasGenerator.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* An implementation of AtlasGenerator that uses the specified generator function
|
||||
* and AtlasStorage class and generates glyph bitmaps immediately
|
||||
* (does not return until all submitted work is finished),
|
||||
* but may use multiple threads (setThreadCount).
|
||||
*/
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
class ImmediateAtlasGenerator {
|
||||
|
||||
public:
|
||||
ImmediateAtlasGenerator();
|
||||
ImmediateAtlasGenerator(int width, int height);
|
||||
void generate(const GlyphGeometry *glyphs, int count);
|
||||
void rearrange(int width, int height, const Remap *remapping, int count);
|
||||
void resize(int width, int height);
|
||||
/// Sets attributes for the generator function
|
||||
void setAttributes(const GeneratorAttributes &attributes);
|
||||
/// Sets the number of threads to be run by generate
|
||||
void setThreadCount(int threadCount);
|
||||
/// Allows access to the underlying AtlasStorage
|
||||
const AtlasStorage & atlasStorage() const;
|
||||
|
||||
private:
|
||||
AtlasStorage storage;
|
||||
std::vector<GlyphBox> layout;
|
||||
std::vector<T> glyphBuffer;
|
||||
std::vector<byte> errorCorrectionBuffer;
|
||||
GeneratorAttributes attributes;
|
||||
int threadCount;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "ImmediateAtlasGenerator.hpp"
|
||||
77
Nuake/src/Vendors/msdf-atlas-gen/ImmediateAtlasGenerator.hpp
Normal file
77
Nuake/src/Vendors/msdf-atlas-gen/ImmediateAtlasGenerator.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
#include "ImmediateAtlasGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::ImmediateAtlasGenerator() : threadCount(1) { }
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::ImmediateAtlasGenerator(int width, int height) : storage(width, height), threadCount(1) { }
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
void ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::generate(const GlyphGeometry *glyphs, int count) {
|
||||
int maxBoxArea = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
GlyphBox box = glyphs[i];
|
||||
maxBoxArea = std::max(maxBoxArea, box.rect.w*box.rect.h);
|
||||
layout.push_back((GlyphBox &&) box);
|
||||
}
|
||||
int threadBufferSize = N*maxBoxArea;
|
||||
if (threadCount*threadBufferSize > (int) glyphBuffer.size())
|
||||
glyphBuffer.resize(threadCount*threadBufferSize);
|
||||
if (threadCount*maxBoxArea > (int) errorCorrectionBuffer.size())
|
||||
errorCorrectionBuffer.resize(threadCount*maxBoxArea);
|
||||
std::vector<GeneratorAttributes> threadAttributes(threadCount);
|
||||
for (int i = 0; i < threadCount; ++i) {
|
||||
threadAttributes[i] = attributes;
|
||||
threadAttributes[i].config.errorCorrection.buffer = errorCorrectionBuffer.data()+i*maxBoxArea;
|
||||
}
|
||||
|
||||
Workload([this, glyphs, &threadAttributes, threadBufferSize](int i, int threadNo) -> bool {
|
||||
const GlyphGeometry &glyph = glyphs[i];
|
||||
if (!glyph.isWhitespace()) {
|
||||
int l, b, w, h;
|
||||
glyph.getBoxRect(l, b, w, h);
|
||||
msdfgen::BitmapRef<T, N> glyphBitmap(glyphBuffer.data()+threadNo*threadBufferSize, w, h);
|
||||
GEN_FN(glyphBitmap, glyph, threadAttributes[threadNo]);
|
||||
storage.put(l, b, msdfgen::BitmapConstRef<T, N>(glyphBitmap));
|
||||
}
|
||||
return true;
|
||||
}, count).finish(threadCount);
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
void ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::rearrange(int width, int height, const Remap *remapping, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
layout[remapping[i].index].rect.x = remapping[i].target.x;
|
||||
layout[remapping[i].index].rect.y = remapping[i].target.y;
|
||||
}
|
||||
AtlasStorage newStorage((AtlasStorage &&) storage, width, height, remapping, count);
|
||||
storage = (AtlasStorage &&) newStorage;
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
void ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::resize(int width, int height) {
|
||||
AtlasStorage newStorage((AtlasStorage &&) storage, width, height);
|
||||
storage = (AtlasStorage &&) newStorage;
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
void ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::setAttributes(const GeneratorAttributes &attributes) {
|
||||
this->attributes = attributes;
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
void ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::setThreadCount(int threadCount) {
|
||||
this->threadCount = threadCount;
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
const AtlasStorage & ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::atlasStorage() const {
|
||||
return storage;
|
||||
}
|
||||
|
||||
}
|
||||
21
Nuake/src/Vendors/msdf-atlas-gen/LICENSE.txt
Normal file
21
Nuake/src/Vendors/msdf-atlas-gen/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 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.
|
||||
142
Nuake/src/Vendors/msdf-atlas-gen/README.md
Normal file
142
Nuake/src/Vendors/msdf-atlas-gen/README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
|
||||
# Multi-channel signed distance field atlas generator
|
||||
|
||||
This is a utility for generating compact font atlases using [MSDFgen](https://github.com/Chlumsky/msdfgen).
|
||||
|
||||
The atlas generator loads a subset of glyphs from a TTF or OTF font file, generates a distance field for each of them, and tightly packs them into an atlas bitmap (example below). The finished atlas and/or its layout metadata can be exported as an [Artery Font](https://github.com/Chlumsky/artery-font-format) file, a plain image file, a CSV sheet or a structured JSON file.
|
||||
|
||||

|
||||
|
||||
A font atlas is typically stored in texture memory and used to draw text in real-time rendering contexts such as video games.
|
||||
|
||||
- See what's new in the [changelog](CHANGELOG.md).
|
||||
|
||||
## Atlas types
|
||||
|
||||
The atlas generator can generate the following six types of atlases.
|
||||
|
||||
| |Hard mask|Soft mask|SDF|PSDF|MSDF|MTSDF|
|
||||
|-|-|-|-|-|-|-|
|
||||
| |||||||
|
||||
|Channels:|1 (1-bit)|1|1|1|3|4|
|
||||
|Anti-aliasing:|-|Yes|Yes|Yes|Yes|Yes|
|
||||
|Scalability:|-|-|Yes|Yes|Yes|Yes|
|
||||
|Sharp corners:|-|-|-|-|Yes|Yes|
|
||||
|Soft effects:|-|-|Yes|-|-|Yes|
|
||||
|Hard effects:|-|-|-|Yes|Yes|Yes|
|
||||
|
||||
Notes:
|
||||
- *Sharp corners* refers to preservation of corner sharpness when upscaled.
|
||||
- *Soft effects* refers to the support of effects that use true distance, such as glows, rounded borders, or simplified shadows.
|
||||
- *Hard effects* refers to the support of effects that use pseudo-distance, such as mitered borders or thickness adjustment.
|
||||
|
||||
## Getting started
|
||||
|
||||
This project can be used either as a library or as a standalone console program.
|
||||
To start using the program immediately, there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdf-atlas-gen/releases).
|
||||
To build the project, you may use the included [Visual Studio solution](msdf-atlas-gen.sln) or the [Unix Makefile](Makefile).
|
||||
|
||||
## Command line arguments
|
||||
|
||||
Use the following command line arguments for the standalone version of the atlas generator.
|
||||
|
||||
### Input
|
||||
|
||||
- `-font <fontfile.ttf/otf>` (required) – sets the input font file.
|
||||
- `-charset <charset.txt>` – sets the character set. The ASCII charset will be used if not specified. See [the syntax specification](#character-set-specification-syntax) of `charset.txt`.
|
||||
- `-glyphset <glyphset.txt>` – sets the set of input glyphs using their indices within the font file. See [the syntax specification](#glyph-set-specification).
|
||||
- `-fontscale <scale>` – applies a scaling transformation to the font's glyphs. Mainly to be used to generate multiple sizes in a single atlas, otherwise use [`-size`](#glyph-configuration).
|
||||
- `-fontname <name>` – sets a name for the font that will be stored in certain output files as metadata.
|
||||
- `-and` – separates multiple inputs to be combined into a single atlas.
|
||||
|
||||
### Bitmap atlas type
|
||||
|
||||
`-type <type>` – see [Atlas types](#atlas-types)
|
||||
|
||||
`<type>` can be one of:
|
||||
|
||||
- `hardmask` – a non-anti-aliased binary image
|
||||
- `softmask` – an anti-aliased image
|
||||
- `sdf` – a true signed distance field (SDF)
|
||||
- `psdf` – a pseudo-distance field
|
||||
- `msdf` (default) – a multi-channel signed distance field (MSDF)
|
||||
- `mtsdf` – a combination of MSDF and true SDF in the alpha channel
|
||||
|
||||
### Atlas image format
|
||||
|
||||
`-format <format>`
|
||||
|
||||
`<format>` can be one of:
|
||||
|
||||
- `png` – a compressed PNG image
|
||||
- `bmp` – an uncompressed BMP image
|
||||
- `tiff` – an uncompressed floating-point TIFF image
|
||||
- `text` – a sequence of pixel values in plain text
|
||||
- `textfloat` – a sequence of floating-point pixel values in plain text
|
||||
- `bin` – a sequence of pixel values encoded as raw bytes of data
|
||||
- `binfloat` – a sequence of pixel values encoded as raw 32-bit floating-point values
|
||||
|
||||
### Atlas dimensions
|
||||
|
||||
`-dimensions <width> <height>` – sets fixed atlas dimensions
|
||||
|
||||
Alternativelly, the minimum possible dimensions may be selected automatically if a dimensions constraint is set instead:
|
||||
|
||||
- `-pots` – a power-of-two square
|
||||
- `-potr` – a power-of-two square or rectangle (2:1)
|
||||
- `-square` – any square dimensions
|
||||
- `-square2` – square with even side length
|
||||
- `-square4` (default) – square with side length divisible by four
|
||||
|
||||
### Outputs
|
||||
|
||||
Any non-empty subset of the following may be specified:
|
||||
|
||||
- `-imageout <filename.*>` – saves the atlas bitmap as a plain image file. Format matches `-format`
|
||||
- `-json <filename.json>` – writes the atlas's layout data as well as other metrics into a structured JSON file
|
||||
- `-csv <filename.csv>` – writes the glyph layout data into a simple CSV file
|
||||
- `-arfont <filename.arfont>` – saves the atlas and its layout data as an [Artery Font](https://github.com/Chlumsky/artery-font-format) file
|
||||
- `-shadronpreview <filename.shadron> <sample text>` – generates a [Shadron script](https://www.arteryengine.com/shadron/) that uses the generated atlas to draw a sample text as a preview
|
||||
|
||||
### Glyph configuration
|
||||
|
||||
- `-size <EM size>` – sets the size of the glyphs in the atlas in pixels per EM
|
||||
- `-minsize <EM size>` – sets the minimum size. The largest possible size that fits the same atlas dimensions will be used
|
||||
- `-emrange <EM range>` – sets the distance field range in EM's
|
||||
- `-pxrange <pixel range>` (default = 2) – sets the distance field range in output pixels
|
||||
|
||||
### Distance field generator settings
|
||||
|
||||
- `-angle <angle>` – sets the minimum angle between adjacent edges to be considered a corner. Append D for degrees (`msdf` / `mtsdf` only)
|
||||
- `-coloringstrategy <simple / inktrap / distance>` – selects the edge coloring heuristic (`msdf` / `mtsdf` only)
|
||||
- `-errorcorrection <mode>` – selects the error correction algorithm. Use `help` as mode for more information (`msdf` / `mtsdf` only)
|
||||
- `-miterlimit <value>` – sets the miter limit that limits the extension of each glyph's bounding box due to very sharp corners (`psdf` / `msdf` / `mtsdf` only)
|
||||
- `-overlap` – switches to distance field generator with support for overlapping contours
|
||||
- `-nopreprocess` – disables path preprocessing which resolves self-intersections and overlapping contours
|
||||
- `-scanline` – performs an additional scanline pass to fix the signs of the distances
|
||||
- `-seed <N>` – sets the initial seed for the edge coloring heuristic
|
||||
- `-threads <N>` – sets the number of threads for the parallel computation (0 = auto)
|
||||
|
||||
Use `-help` for an exhaustive list of options.
|
||||
|
||||
## Character set specification syntax
|
||||
|
||||
The character set file is a text file with UTF-8 or ASCII encoding.
|
||||
The characters can be denoted in the following ways:
|
||||
|
||||
- Single character: `'A'` (UTF-8 encoded), `65` (decimal Unicode), `0x41` (hexadecimal Unicode)
|
||||
- Range of characters: `['A', 'Z']`, `[65, 90]`, `[0x41, 0x5a]`
|
||||
- String of characters: `"ABCDEFGHIJKLMNOPQRSTUVWXYZ"` (UTF-8 encoded)
|
||||
|
||||
The entries should be separated by commas or whitespace.
|
||||
In between quotation marks, backslash is used as the escape character (e.g. `'\''`, `'\\'`, `"!\"#"`).
|
||||
The order in which characters appear is not taken into consideration.
|
||||
|
||||
Additionally, the include directive can be used to include other charset files and combine character sets in a hierarchical way.
|
||||
It must be written on a separate line:
|
||||
|
||||
`@include "base-charset.txt"`
|
||||
|
||||
### Glyph set specification
|
||||
|
||||
The syntax of the glyph set specification is mostly the same as that of a character set, but only numeric values (decimal and hexadecimal) are allowed.
|
||||
14
Nuake/src/Vendors/msdf-atlas-gen/Rectangle.h
Normal file
14
Nuake/src/Vendors/msdf-atlas-gen/Rectangle.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
struct Rectangle {
|
||||
int x, y, w, h;
|
||||
};
|
||||
|
||||
struct OrientedRectangle : Rectangle {
|
||||
bool rotated;
|
||||
};
|
||||
|
||||
}
|
||||
143
Nuake/src/Vendors/msdf-atlas-gen/RectanglePacker.cpp
Normal file
143
Nuake/src/Vendors/msdf-atlas-gen/RectanglePacker.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
#include "RectanglePacker.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
#define WORST_FIT 0x7fffffff
|
||||
|
||||
template <typename T>
|
||||
static void removeFromUnorderedVector(std::vector<T> &vector, size_t index) {
|
||||
if (index != vector.size()-1)
|
||||
std::swap(vector[index], vector.back());
|
||||
vector.pop_back();
|
||||
}
|
||||
|
||||
int RectanglePacker::rateFit(int w, int h, int sw, int sh) {
|
||||
return std::min(sw-w, sh-h);
|
||||
}
|
||||
|
||||
RectanglePacker::RectanglePacker() : RectanglePacker(0, 0) { }
|
||||
|
||||
RectanglePacker::RectanglePacker(int width, int height) {
|
||||
if (width > 0 && height > 0)
|
||||
spaces.push_back(Rectangle { 0, 0, width, height });
|
||||
}
|
||||
|
||||
void RectanglePacker::splitSpace(int index, int w, int h) {
|
||||
Rectangle space = spaces[index];
|
||||
removeFromUnorderedVector(spaces, index);
|
||||
Rectangle a = { space.x, space.y+h, w, space.h-h };
|
||||
Rectangle b = { space.x+w, space.y, space.w-w, h };
|
||||
if (w*(space.h-h) <= h*(space.w-w))
|
||||
a.w = space.w;
|
||||
else
|
||||
b.h = space.h;
|
||||
if (a.w > 0 && a.h > 0)
|
||||
spaces.push_back(a);
|
||||
if (b.w > 0 && b.h > 0)
|
||||
spaces.push_back(b);
|
||||
}
|
||||
|
||||
int RectanglePacker::pack(Rectangle *rectangles, int count) {
|
||||
std::vector<int> remainingRects(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
remainingRects[i] = i;
|
||||
while (!remainingRects.empty()) {
|
||||
int bestFit = WORST_FIT;
|
||||
int bestSpace = -1;
|
||||
int bestRect = -1;
|
||||
for (size_t i = 0; i < spaces.size(); ++i) {
|
||||
const Rectangle &space = spaces[i];
|
||||
for (size_t j = 0; j < remainingRects.size(); ++j) {
|
||||
const Rectangle &rect = rectangles[remainingRects[j]];
|
||||
if (rect.w == space.w && rect.h == space.h) {
|
||||
bestSpace = i;
|
||||
bestRect = j;
|
||||
goto BEST_FIT_FOUND;
|
||||
}
|
||||
if (rect.w <= space.w && rect.h <= space.h) {
|
||||
int fit = rateFit(rect.w, rect.h, space.w, space.h);
|
||||
if (fit < bestFit) {
|
||||
bestSpace = i;
|
||||
bestRect = j;
|
||||
bestFit = fit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestSpace < 0 || bestRect < 0)
|
||||
break;
|
||||
BEST_FIT_FOUND:
|
||||
Rectangle &rect = rectangles[remainingRects[bestRect]];
|
||||
rect.x = spaces[bestSpace].x;
|
||||
rect.y = spaces[bestSpace].y;
|
||||
splitSpace(bestSpace, rect.w, rect.h);
|
||||
removeFromUnorderedVector(remainingRects, bestRect);
|
||||
}
|
||||
return (int) remainingRects.size();
|
||||
}
|
||||
|
||||
int RectanglePacker::pack(OrientedRectangle *rectangles, int count) {
|
||||
std::vector<int> remainingRects(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
remainingRects[i] = i;
|
||||
while (!remainingRects.empty()) {
|
||||
int bestFit = WORST_FIT;
|
||||
int bestSpace = -1;
|
||||
int bestRect = -1;
|
||||
bool bestRotated = false;
|
||||
for (size_t i = 0; i < spaces.size(); ++i) {
|
||||
const Rectangle &space = spaces[i];
|
||||
for (size_t j = 0; j < remainingRects.size(); ++j) {
|
||||
const OrientedRectangle &rect = rectangles[remainingRects[j]];
|
||||
if (rect.w == space.w && rect.h == space.h) {
|
||||
bestSpace = i;
|
||||
bestRect = j;
|
||||
bestRotated = false;
|
||||
goto BEST_FIT_FOUND;
|
||||
}
|
||||
if (rect.h == space.w && rect.w == space.h) {
|
||||
bestSpace = i;
|
||||
bestRect = j;
|
||||
bestRotated = true;
|
||||
goto BEST_FIT_FOUND;
|
||||
}
|
||||
if (rect.w <= space.w && rect.h <= space.h) {
|
||||
int fit = rateFit(rect.w, rect.h, space.w, space.h);
|
||||
if (fit < bestFit) {
|
||||
bestSpace = i;
|
||||
bestRect = j;
|
||||
bestRotated = false;
|
||||
bestFit = fit;
|
||||
}
|
||||
}
|
||||
if (rect.h <= space.w && rect.w <= space.h) {
|
||||
int fit = rateFit(rect.h, rect.w, space.w, space.h);
|
||||
if (fit < bestFit) {
|
||||
bestSpace = i;
|
||||
bestRect = j;
|
||||
bestRotated = true;
|
||||
bestFit = fit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestSpace < 0 || bestRect < 0)
|
||||
break;
|
||||
BEST_FIT_FOUND:
|
||||
OrientedRectangle &rect = rectangles[remainingRects[bestRect]];
|
||||
rect.x = spaces[bestSpace].x;
|
||||
rect.y = spaces[bestSpace].y;
|
||||
rect.rotated = bestRotated;
|
||||
if (bestRotated)
|
||||
splitSpace(bestSpace, rect.h, rect.w);
|
||||
else
|
||||
splitSpace(bestSpace, rect.w, rect.h);
|
||||
removeFromUnorderedVector(remainingRects, bestRect);
|
||||
}
|
||||
return (int) remainingRects.size();
|
||||
}
|
||||
|
||||
}
|
||||
28
Nuake/src/Vendors/msdf-atlas-gen/RectanglePacker.h
Normal file
28
Nuake/src/Vendors/msdf-atlas-gen/RectanglePacker.h
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Rectangle.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Guillotine 2D single bin packer
|
||||
class RectanglePacker {
|
||||
|
||||
public:
|
||||
RectanglePacker();
|
||||
RectanglePacker(int width, int height);
|
||||
/// Packs the rectangle array, returns how many didn't fit (0 on success)
|
||||
int pack(Rectangle *rectangles, int count);
|
||||
int pack(OrientedRectangle *rectangles, int count);
|
||||
|
||||
private:
|
||||
std::vector<Rectangle> spaces;
|
||||
|
||||
static int rateFit(int w, int h, int sw, int sh);
|
||||
|
||||
void splitSpace(int index, int w, int h);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
15
Nuake/src/Vendors/msdf-atlas-gen/Remap.h
Normal file
15
Nuake/src/Vendors/msdf-atlas-gen/Remap.h
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Represents the repositioning of a subsection of the atlas
|
||||
struct Remap {
|
||||
int index;
|
||||
struct {
|
||||
int x, y;
|
||||
} source, target;
|
||||
int width, height;
|
||||
};
|
||||
|
||||
}
|
||||
168
Nuake/src/Vendors/msdf-atlas-gen/TightAtlasPacker.cpp
Normal file
168
Nuake/src/Vendors/msdf-atlas-gen/TightAtlasPacker.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
|
||||
#include "TightAtlasPacker.h"
|
||||
|
||||
#include <vector>
|
||||
#include "Rectangle.h"
|
||||
#include "rectangle-packing.h"
|
||||
#include "size-selectors.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
int TightAtlasPacker::tryPack(GlyphGeometry *glyphs, int count, DimensionsConstraint dimensionsConstraint, int &width, int &height, int padding, double scale, double range, double miterLimit) {
|
||||
// Wrap glyphs into boxes
|
||||
std::vector<Rectangle> rectangles;
|
||||
std::vector<GlyphGeometry *> rectangleGlyphs;
|
||||
rectangles.reserve(count);
|
||||
rectangleGlyphs.reserve(count);
|
||||
for (GlyphGeometry *glyph = glyphs, *end = glyphs+count; glyph < end; ++glyph) {
|
||||
if (!glyph->isWhitespace()) {
|
||||
Rectangle rect = { };
|
||||
glyph->wrapBox(scale, range, miterLimit);
|
||||
glyph->getBoxSize(rect.w, rect.h);
|
||||
if (rect.w > 0 && rect.h > 0) {
|
||||
rectangles.push_back(rect);
|
||||
rectangleGlyphs.push_back(glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
// No non-zero size boxes?
|
||||
if (rectangles.empty()) {
|
||||
if (width < 0 || height < 0)
|
||||
width = 0, height = 0;
|
||||
return 0;
|
||||
}
|
||||
// Box rectangle packing
|
||||
if (width < 0 || height < 0) {
|
||||
std::pair<int, int> dimensions = std::make_pair(width, height);
|
||||
switch (dimensionsConstraint) {
|
||||
case DimensionsConstraint::POWER_OF_TWO_SQUARE:
|
||||
dimensions = packRectangles<SquarePowerOfTwoSizeSelector>(rectangles.data(), rectangles.size(), padding);
|
||||
break;
|
||||
case DimensionsConstraint::POWER_OF_TWO_RECTANGLE:
|
||||
dimensions = packRectangles<PowerOfTwoSizeSelector>(rectangles.data(), rectangles.size(), padding);
|
||||
break;
|
||||
case DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE:
|
||||
dimensions = packRectangles<SquareSizeSelector<4> >(rectangles.data(), rectangles.size(), padding);
|
||||
break;
|
||||
case DimensionsConstraint::EVEN_SQUARE:
|
||||
dimensions = packRectangles<SquareSizeSelector<2> >(rectangles.data(), rectangles.size(), padding);
|
||||
break;
|
||||
case DimensionsConstraint::SQUARE:
|
||||
dimensions = packRectangles<SquareSizeSelector<> >(rectangles.data(), rectangles.size(), padding);
|
||||
break;
|
||||
}
|
||||
if (!(dimensions.first > 0 && dimensions.second > 0))
|
||||
return -1;
|
||||
width = dimensions.first, height = dimensions.second;
|
||||
} else {
|
||||
if (int result = packRectangles(rectangles.data(), rectangles.size(), width, height, padding))
|
||||
return result;
|
||||
}
|
||||
// Set glyph box placement
|
||||
for (size_t i = 0; i < rectangles.size(); ++i)
|
||||
rectangleGlyphs[i]->placeBox(rectangles[i].x, height-(rectangles[i].y+rectangles[i].h));
|
||||
return 0;
|
||||
}
|
||||
|
||||
double TightAtlasPacker::packAndScale(GlyphGeometry *glyphs, int count, int width, int height, int padding, double unitRange, double pxRange, double miterLimit, double tolerance) {
|
||||
bool lastResult = false;
|
||||
#define TRY_PACK(scale) (lastResult = !tryPack(glyphs, count, DimensionsConstraint(), width, height, padding, (scale), unitRange+pxRange/(scale), miterLimit))
|
||||
double minScale = 1, maxScale = 1;
|
||||
if (TRY_PACK(1)) {
|
||||
while (maxScale < 1e+32 && ((maxScale = 2*minScale), TRY_PACK(maxScale)))
|
||||
minScale = maxScale;
|
||||
} else {
|
||||
while (minScale > 1e-32 && ((minScale = .5*maxScale), !TRY_PACK(minScale)))
|
||||
maxScale = minScale;
|
||||
}
|
||||
if (minScale == maxScale)
|
||||
return 0;
|
||||
while (minScale/maxScale < 1-tolerance) {
|
||||
double midScale = .5*(minScale+maxScale);
|
||||
if (TRY_PACK(midScale))
|
||||
minScale = midScale;
|
||||
else
|
||||
maxScale = midScale;
|
||||
}
|
||||
if (!lastResult)
|
||||
TRY_PACK(minScale);
|
||||
return minScale;
|
||||
}
|
||||
|
||||
TightAtlasPacker::TightAtlasPacker() :
|
||||
width(-1), height(-1),
|
||||
padding(0),
|
||||
dimensionsConstraint(DimensionsConstraint::POWER_OF_TWO_SQUARE),
|
||||
scale(-1),
|
||||
minScale(1),
|
||||
unitRange(0),
|
||||
pxRange(0),
|
||||
miterLimit(0),
|
||||
scaleMaximizationTolerance(.001)
|
||||
{ }
|
||||
|
||||
int TightAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
||||
double initialScale = scale > 0 ? scale : minScale;
|
||||
if (initialScale > 0) {
|
||||
if (int remaining = tryPack(glyphs, count, dimensionsConstraint, width, height, padding, initialScale, unitRange+pxRange/initialScale, miterLimit))
|
||||
return remaining;
|
||||
} else if (width < 0 || height < 0)
|
||||
return -1;
|
||||
if (scale <= 0)
|
||||
scale = packAndScale(glyphs, count, width, height, padding, unitRange, pxRange, miterLimit, scaleMaximizationTolerance);
|
||||
if (scale <= 0)
|
||||
return -1;
|
||||
pxRange += scale*unitRange;
|
||||
unitRange = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setDimensions(int width, int height) {
|
||||
this->width = width, this->height = height;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::unsetDimensions() {
|
||||
width = -1, height = -1;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setDimensionsConstraint(DimensionsConstraint dimensionsConstraint) {
|
||||
this->dimensionsConstraint = dimensionsConstraint;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setPadding(int padding) {
|
||||
this->padding = padding;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setScale(double scale) {
|
||||
this->scale = scale;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setMinimumScale(double minScale) {
|
||||
this->minScale = minScale;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setUnitRange(double unitRange) {
|
||||
this->unitRange = unitRange;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setPixelRange(double pxRange) {
|
||||
this->pxRange = pxRange;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setMiterLimit(double miterLimit) {
|
||||
this->miterLimit = miterLimit;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::getDimensions(int &width, int &height) const {
|
||||
width = this->width, height = this->height;
|
||||
}
|
||||
|
||||
double TightAtlasPacker::getScale() const {
|
||||
return scale;
|
||||
}
|
||||
|
||||
double TightAtlasPacker::getPixelRange() const {
|
||||
return pxRange;
|
||||
}
|
||||
|
||||
}
|
||||
71
Nuake/src/Vendors/msdf-atlas-gen/TightAtlasPacker.h
Normal file
71
Nuake/src/Vendors/msdf-atlas-gen/TightAtlasPacker.h
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* This class computes the layout of a static atlas and may optionally
|
||||
* also find the minimum required dimensions and/or the maximum glyph scale
|
||||
*/
|
||||
class TightAtlasPacker {
|
||||
|
||||
public:
|
||||
/// Constraints for the atlas's dimensions - see size selectors for more info
|
||||
enum class DimensionsConstraint {
|
||||
POWER_OF_TWO_SQUARE,
|
||||
POWER_OF_TWO_RECTANGLE,
|
||||
MULTIPLE_OF_FOUR_SQUARE,
|
||||
EVEN_SQUARE,
|
||||
SQUARE
|
||||
};
|
||||
|
||||
TightAtlasPacker();
|
||||
|
||||
/// Computes the layout for the array of glyphs. Returns 0 on success
|
||||
int pack(GlyphGeometry *glyphs, int count);
|
||||
|
||||
/// Sets the atlas's dimensions to be fixed
|
||||
void setDimensions(int width, int height);
|
||||
/// Sets the atlas's dimensions to be determined during pack
|
||||
void unsetDimensions();
|
||||
/// Sets the constraint to be used when determining dimensions
|
||||
void setDimensionsConstraint(DimensionsConstraint dimensionsConstraint);
|
||||
/// Sets the padding between glyph boxes
|
||||
void setPadding(int padding);
|
||||
/// Sets fixed glyph scale
|
||||
void setScale(double scale);
|
||||
/// Sets the minimum glyph scale
|
||||
void setMinimumScale(double minScale);
|
||||
/// Sets the unit component of the total distance range
|
||||
void setUnitRange(double unitRange);
|
||||
/// Sets the pixel component of the total distance range
|
||||
void setPixelRange(double pxRange);
|
||||
/// Sets the miter limit for bounds computation
|
||||
void setMiterLimit(double miterLimit);
|
||||
|
||||
/// Outputs the atlas's final dimensions
|
||||
void getDimensions(int &width, int &height) const;
|
||||
/// Returns the final glyph scale
|
||||
double getScale() const;
|
||||
/// Returns the final combined pixel range (including converted unit range)
|
||||
double getPixelRange() const;
|
||||
|
||||
private:
|
||||
int width, height;
|
||||
int padding;
|
||||
DimensionsConstraint dimensionsConstraint;
|
||||
double scale;
|
||||
double minScale;
|
||||
double unitRange;
|
||||
double pxRange;
|
||||
double miterLimit;
|
||||
double scaleMaximizationTolerance;
|
||||
|
||||
static int tryPack(GlyphGeometry *glyphs, int count, DimensionsConstraint dimensionsConstraint, int &width, int &height, int padding, double scale, double range, double miterLimit);
|
||||
static double packAndScale(GlyphGeometry *glyphs, int count, int width, int height, int padding, double unitRange, double pxRange, double miterLimit, double tolerance);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
50
Nuake/src/Vendors/msdf-atlas-gen/Workload.cpp
Normal file
50
Nuake/src/Vendors/msdf-atlas-gen/Workload.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
#include "Workload.h"
|
||||
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
Workload::Workload() : chunks(0) { }
|
||||
|
||||
Workload::Workload(const std::function<bool(int, int)> &workerFunction, int chunks) : workerFunction(workerFunction), chunks(chunks) { }
|
||||
|
||||
bool Workload::finishSequential() {
|
||||
for (int i = 0; i < chunks; ++i)
|
||||
if (!workerFunction(i, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Workload::finishParallel(int threadCount) {
|
||||
bool result = true;
|
||||
std::atomic<int> next(0);
|
||||
std::function<void(int)> threadWorker = [this, &result, &next](int threadNo) {
|
||||
for (int i = next++; result && i < chunks; i = next++) {
|
||||
if (!workerFunction(i, threadNo))
|
||||
result = false;
|
||||
}
|
||||
};
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(threadCount);
|
||||
for (int i = 0; i < threadCount; ++i)
|
||||
threads.emplace_back(threadWorker, i);
|
||||
for (std::thread &thread : threads)
|
||||
thread.join();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Workload::finish(int threadCount) {
|
||||
if (!chunks)
|
||||
return true;
|
||||
if (threadCount == 1 || chunks == 1)
|
||||
return finishSequential();
|
||||
if (threadCount > 1)
|
||||
return finishParallel(std::min(threadCount, chunks));
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
32
Nuake/src/Vendors/msdf-atlas-gen/Workload.h
Normal file
32
Nuake/src/Vendors/msdf-atlas-gen/Workload.h
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* This function allows to split a workload into multiple threads.
|
||||
* The worker function:
|
||||
* bool FN(int chunk, int threadNo);
|
||||
* should process the given chunk (out of chunks) and return true.
|
||||
* If false is returned, the process is interrupted.
|
||||
*/
|
||||
class Workload {
|
||||
|
||||
public:
|
||||
Workload();
|
||||
Workload(const std::function<bool(int, int)> &workerFunction, int chunks);
|
||||
/// Runs the process and returns true if all chunks have been processed
|
||||
bool finish(int threadCount);
|
||||
|
||||
private:
|
||||
std::function<bool(int, int)> workerFunction;
|
||||
int chunks;
|
||||
|
||||
bool finishSequential();
|
||||
bool finishParallel(int threadCount);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
191
Nuake/src/Vendors/msdf-atlas-gen/artery-font-export.cpp
Normal file
191
Nuake/src/Vendors/msdf-atlas-gen/artery-font-export.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
#include "artery-font-export.h"
|
||||
|
||||
/*#include <std-artery-font.h>
|
||||
#include <artery-font/stdio-serialization.h>
|
||||
#include "GlyphGeometry.h"
|
||||
#include "image-encode.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static artery_font::ImageType convertImageType(ImageType imageType) {
|
||||
switch (imageType) {
|
||||
case ImageType::HARD_MASK:
|
||||
case ImageType::SOFT_MASK:
|
||||
return artery_font::IMAGE_LINEAR_MASK;
|
||||
case ImageType::SDF:
|
||||
return artery_font::IMAGE_SDF;
|
||||
case ImageType::PSDF:
|
||||
return artery_font::IMAGE_PSDF;
|
||||
case ImageType::MSDF:
|
||||
return artery_font::IMAGE_MSDF;
|
||||
case ImageType::MTSDF:
|
||||
return artery_font::IMAGE_MTSDF;
|
||||
}
|
||||
return artery_font::IMAGE_NONE;
|
||||
}
|
||||
|
||||
static artery_font::CodepointType convertCodepointType(GlyphIdentifierType glyphIdentifierType) {
|
||||
switch (glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
return artery_font::CP_INDEXED;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
return artery_font::CP_UNICODE;
|
||||
}
|
||||
return artery_font::CP_UNSPECIFIED;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
static bool encodeTiff(std::vector<byte> &output, const msdfgen::BitmapConstRef<T, N> &atlas) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static artery_font::PixelFormat getPixelFormat();
|
||||
|
||||
template <>
|
||||
artery_font::PixelFormat getPixelFormat<byte>() {
|
||||
return artery_font::PIXEL_UNSIGNED8;
|
||||
}
|
||||
template <>
|
||||
artery_font::PixelFormat getPixelFormat<float>() {
|
||||
return artery_font::PIXEL_FLOAT32;
|
||||
}
|
||||
|
||||
template <typename REAL, typename T, int N>
|
||||
bool exportArteryFont(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties) {
|
||||
artery_font::StdArteryFont<REAL> arfont = { };
|
||||
arfont.metadataFormat = artery_font::METADATA_NONE;
|
||||
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
const FontGeometry &font = fonts[i];
|
||||
GlyphIdentifierType identifierType = font.getPreferredIdentifierType();
|
||||
const msdfgen::FontMetrics &fontMetrics = font.getMetrics();
|
||||
artery_font::StdFontVariant<REAL> fontVariant = { };
|
||||
fontVariant.codepointType = convertCodepointType(identifierType);
|
||||
fontVariant.imageType = convertImageType(properties.imageType);
|
||||
fontVariant.metrics.fontSize = REAL(properties.fontSize*fontMetrics.emSize);
|
||||
if (properties.imageType != ImageType::HARD_MASK)
|
||||
fontVariant.metrics.distanceRange = REAL(properties.pxRange);
|
||||
fontVariant.metrics.emSize = REAL(fontMetrics.emSize);
|
||||
fontVariant.metrics.ascender = REAL(fontMetrics.ascenderY);
|
||||
fontVariant.metrics.descender = REAL(fontMetrics.descenderY);
|
||||
fontVariant.metrics.lineHeight = REAL(fontMetrics.lineHeight);
|
||||
fontVariant.metrics.underlineY = REAL(fontMetrics.underlineY);
|
||||
fontVariant.metrics.underlineThickness = REAL(fontMetrics.underlineThickness);
|
||||
const char *name = font.getName();
|
||||
if (name)
|
||||
fontVariant.name.string = name;
|
||||
fontVariant.glyphs = artery_font::StdList<artery_font::Glyph<REAL> >(font.getGlyphs().size());
|
||||
int j = 0;
|
||||
for (const GlyphGeometry &glyphGeom : font.getGlyphs()) {
|
||||
artery_font::Glyph<REAL> &glyph = fontVariant.glyphs[j++];
|
||||
glyph.codepoint = glyphGeom.getIdentifier(identifierType);
|
||||
glyph.image = 0;
|
||||
double l, b, r, t;
|
||||
glyphGeom.getQuadPlaneBounds(l, b, r, t);
|
||||
glyph.planeBounds.l = REAL(l);
|
||||
glyph.planeBounds.b = REAL(b);
|
||||
glyph.planeBounds.r = REAL(r);
|
||||
glyph.planeBounds.t = REAL(t);
|
||||
glyphGeom.getQuadAtlasBounds(l, b, r, t);
|
||||
glyph.imageBounds.l = REAL(l);
|
||||
glyph.imageBounds.b = REAL(b);
|
||||
glyph.imageBounds.r = REAL(r);
|
||||
glyph.imageBounds.t = REAL(t);
|
||||
glyph.advance.h = REAL(glyphGeom.getAdvance());
|
||||
glyph.advance.v = REAL(0);
|
||||
}
|
||||
switch (identifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
for (const std::pair<std::pair<int, int>, double> &elem : font.getKerning()) {
|
||||
artery_font::KernPair<REAL> kernPair = { };
|
||||
kernPair.codepoint1 = elem.first.first;
|
||||
kernPair.codepoint2 = elem.first.second;
|
||||
kernPair.advance.h = REAL(elem.second);
|
||||
fontVariant.kernPairs.vector.push_back((artery_font::KernPair<REAL> &&) kernPair);
|
||||
}
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
for (const std::pair<std::pair<int, int>, double> &elem : font.getKerning()) {
|
||||
const GlyphGeometry *glyph1 = font.getGlyph(msdfgen::GlyphIndex(elem.first.first));
|
||||
const GlyphGeometry *glyph2 = font.getGlyph(msdfgen::GlyphIndex(elem.first.second));
|
||||
if (glyph1 && glyph2 && glyph1->getCodepoint() && glyph2->getCodepoint()) {
|
||||
artery_font::KernPair<REAL> kernPair = { };
|
||||
kernPair.codepoint1 = glyph1->getCodepoint();
|
||||
kernPair.codepoint2 = glyph2->getCodepoint();
|
||||
kernPair.advance.h = REAL(elem.second);
|
||||
fontVariant.kernPairs.vector.push_back((artery_font::KernPair<REAL> &&) kernPair);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
arfont.variants.vector.push_back((artery_font::StdFontVariant<REAL> &&) fontVariant);
|
||||
}
|
||||
|
||||
{
|
||||
artery_font::StdImage image = { };
|
||||
image.width = atlas.width;
|
||||
image.height = atlas.height;
|
||||
image.channels = N;
|
||||
image.imageType = convertImageType(properties.imageType);
|
||||
switch (properties.imageFormat) {
|
||||
case ImageFormat::PNG:
|
||||
image.encoding = artery_font::IMAGE_PNG;
|
||||
image.pixelFormat = artery_font::PIXEL_UNSIGNED8;
|
||||
if (!encodePng(image.data.vector, atlas))
|
||||
return false;
|
||||
break;
|
||||
case ImageFormat::TIFF:
|
||||
image.encoding = artery_font::IMAGE_TIFF;
|
||||
image.pixelFormat = artery_font::PIXEL_FLOAT32;
|
||||
if (!encodeTiff(image.data.vector, atlas))
|
||||
return false;
|
||||
break;
|
||||
case ImageFormat::BINARY:
|
||||
image.pixelFormat = artery_font::PIXEL_UNSIGNED8;
|
||||
goto BINARY_EITHER;
|
||||
case ImageFormat::BINARY_FLOAT:
|
||||
image.pixelFormat = artery_font::PIXEL_FLOAT32;
|
||||
goto BINARY_EITHER;
|
||||
BINARY_EITHER:
|
||||
if (image.pixelFormat != getPixelFormat<T>())
|
||||
return false;
|
||||
image.encoding = artery_font::IMAGE_RAW_BINARY;
|
||||
image.rawBinaryFormat.rowLength = N*sizeof(T)*atlas.width;
|
||||
image.data = artery_font::StdByteArray(N*sizeof(T)*atlas.width*atlas.height);
|
||||
switch (properties.yDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
image.rawBinaryFormat.orientation = artery_font::ORIENTATION_BOTTOM_UP;
|
||||
memcpy((byte *) image.data, atlas.pixels, N*sizeof(T)*atlas.width*atlas.height);
|
||||
break;
|
||||
case YDirection::TOP_DOWN: {
|
||||
image.rawBinaryFormat.orientation = artery_font::ORIENTATION_TOP_DOWN;
|
||||
byte *imageData = (byte *) image.data;
|
||||
for (int y = atlas.height-1; y >= 0; --y) {
|
||||
memcpy(imageData, atlas.pixels+N*atlas.width*y, N*sizeof(T)*atlas.width);
|
||||
imageData += N*sizeof(T)*atlas.width;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
arfont.images.vector.push_back((artery_font::StdImage &&) image);
|
||||
}
|
||||
|
||||
return artery_font::writeFile(arfont, filename);
|
||||
}
|
||||
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
|
||||
}
|
||||
*/
|
||||
23
Nuake/src/Vendors/msdf-atlas-gen/artery-font-export.h
Normal file
23
Nuake/src/Vendors/msdf-atlas-gen/artery-font-export.h
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
struct ArteryFontExportProperties {
|
||||
double fontSize;
|
||||
double pxRange;
|
||||
ImageType imageType;
|
||||
ImageFormat imageFormat;
|
||||
YDirection yDirection;
|
||||
};
|
||||
|
||||
/// Encodes the atlas bitmap and its layout into an Artery Atlas Font file
|
||||
template <typename REAL, typename T, int N>
|
||||
bool exportArteryFont(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
|
||||
}
|
||||
58
Nuake/src/Vendors/msdf-atlas-gen/bitmap-blit.cpp
Normal file
58
Nuake/src/Vendors/msdf-atlas-gen/bitmap-blit.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
#include "bitmap-blit.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
template <typename T, int N>
|
||||
void blitSameType(const msdfgen::BitmapRef<T, N> &dst, const msdfgen::BitmapConstRef<T, N> &src, int dx, int dy, int sx, int sy, int w, int h) {
|
||||
for (int y = 0; y < h; ++y)
|
||||
memcpy(dst(dx, dy+y), src(sx, sy+y), sizeof(T)*N*w);
|
||||
}
|
||||
|
||||
#define BLIT_SAME_TYPE_IMPL(T, N) void blit(const msdfgen::BitmapRef<T, N> &dst, const msdfgen::BitmapConstRef<T, N> &src, int dx, int dy, int sx, int sy, int w, int h) { blitSameType(dst, src, dx, dy, sx, sy, w, h); }
|
||||
|
||||
BLIT_SAME_TYPE_IMPL(byte, 1)
|
||||
BLIT_SAME_TYPE_IMPL(byte, 3)
|
||||
BLIT_SAME_TYPE_IMPL(byte, 4)
|
||||
BLIT_SAME_TYPE_IMPL(float, 1)
|
||||
BLIT_SAME_TYPE_IMPL(float, 3)
|
||||
BLIT_SAME_TYPE_IMPL(float, 4)
|
||||
|
||||
void blit(const msdfgen::BitmapRef<byte, 1> &dst, const msdfgen::BitmapConstRef<float, 1> &src, int dx, int dy, int sx, int sy, int w, int h) {
|
||||
for (int y = 0; y < h; ++y) {
|
||||
byte *dstPixel = dst(dx, dy+y);
|
||||
for (int x = 0; x < w; ++x) {
|
||||
const float *srcPixel = src(sx+x, sy+y);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(*srcPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blit(const msdfgen::BitmapRef<byte, 3> &dst, const msdfgen::BitmapConstRef<float, 3> &src, int dx, int dy, int sx, int sy, int w, int h) {
|
||||
for (int y = 0; y < h; ++y) {
|
||||
byte *dstPixel = dst(dx, dy+y);
|
||||
for (int x = 0; x < w; ++x) {
|
||||
const float *srcPixel = src(sx+x, sy+y);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[0]);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[1]);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blit(const msdfgen::BitmapRef<byte, 4> &dst, const msdfgen::BitmapConstRef<float, 4> &src, int dx, int dy, int sx, int sy, int w, int h) {
|
||||
for (int y = 0; y < h; ++y) {
|
||||
byte *dstPixel = dst(dx, dy+y);
|
||||
for (int x = 0; x < w; ++x) {
|
||||
const float *srcPixel = src(sx+x, sy+y);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[0]);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[1]);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[2]);
|
||||
*dstPixel++ = msdfgen::pixelFloatToByte(srcPixel[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
26
Nuake/src/Vendors/msdf-atlas-gen/bitmap-blit.h
Normal file
26
Nuake/src/Vendors/msdf-atlas-gen/bitmap-blit.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include "types.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/*
|
||||
* Copies a rectangular section from source bitmap to destination bitmap.
|
||||
* Width and height are not checked and must not exceed bitmap bounds!
|
||||
*/
|
||||
|
||||
void blit(const msdfgen::BitmapRef<byte, 1> &dst, const msdfgen::BitmapConstRef<byte, 1> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
void blit(const msdfgen::BitmapRef<byte, 3> &dst, const msdfgen::BitmapConstRef<byte, 3> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
void blit(const msdfgen::BitmapRef<byte, 4> &dst, const msdfgen::BitmapConstRef<byte, 4> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
|
||||
void blit(const msdfgen::BitmapRef<float, 1> &dst, const msdfgen::BitmapConstRef<float, 1> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
void blit(const msdfgen::BitmapRef<float, 3> &dst, const msdfgen::BitmapConstRef<float, 3> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
void blit(const msdfgen::BitmapRef<float, 4> &dst, const msdfgen::BitmapConstRef<float, 4> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
|
||||
void blit(const msdfgen::BitmapRef<byte, 1> &dst, const msdfgen::BitmapConstRef<float, 1> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
void blit(const msdfgen::BitmapRef<byte, 3> &dst, const msdfgen::BitmapConstRef<float, 3> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
void blit(const msdfgen::BitmapRef<byte, 4> &dst, const msdfgen::BitmapConstRef<float, 4> &src, int dx, int dy, int sx, int sy, int w, int h);
|
||||
|
||||
}
|
||||
250
Nuake/src/Vendors/msdf-atlas-gen/charset-parser.cpp
Normal file
250
Nuake/src/Vendors/msdf-atlas-gen/charset-parser.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
|
||||
#include "Charset.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "utf8.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static char escapedChar(char c) {
|
||||
switch (c) {
|
||||
case '0':
|
||||
return '\0';
|
||||
case 'n': case 'N':
|
||||
return '\n';
|
||||
case 'r': case 'R':
|
||||
return '\r';
|
||||
case 's': case 'S':
|
||||
return ' ';
|
||||
case 't': case 'T':
|
||||
return '\t';
|
||||
case '\\': case '"': case '\'':
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
static int readWord(std::string &str, FILE *f) {
|
||||
while (true) {
|
||||
int c = fgetc(f);
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')
|
||||
str.push_back((char) c);
|
||||
else
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
static bool readString(std::string &str, FILE *f, char terminator) {
|
||||
bool escape = false;
|
||||
while (true) {
|
||||
int c = fgetc(f);
|
||||
if (c < 0)
|
||||
return false;
|
||||
if (escape) {
|
||||
str.push_back(escapedChar((char) c));
|
||||
escape = false;
|
||||
} else {
|
||||
if (c == terminator)
|
||||
return true;
|
||||
else if (c == '\\')
|
||||
escape = true;
|
||||
else
|
||||
str.push_back((char) c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool parseInt(int &i, const char *str) {
|
||||
i = 0;
|
||||
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { // hex
|
||||
str += 2;
|
||||
for (; *str; ++str) {
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
i <<= 4;
|
||||
i += *str-'0';
|
||||
} else if (*str >= 'A' && *str <= 'F') {
|
||||
i <<= 4;
|
||||
i += *str-'A'+10;
|
||||
} else if (*str >= 'a' && *str <= 'f') {
|
||||
i <<= 4;
|
||||
i += *str-'a'+10;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
} else { // dec
|
||||
for (; *str; ++str) {
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
i *= 10;
|
||||
i += *str-'0';
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string combinePath(const char *basePath, const char *relPath) {
|
||||
if (relPath[0] == '/' || (relPath[0] && relPath[1] == ':')) // absolute path?
|
||||
return relPath;
|
||||
int lastSlash = -1;
|
||||
for (int i = 0; basePath[i]; ++i)
|
||||
if (basePath[i] == '/' || basePath[i] == '\\')
|
||||
lastSlash = i;
|
||||
if (lastSlash < 0)
|
||||
return relPath;
|
||||
return std::string(basePath, lastSlash+1)+relPath;
|
||||
}
|
||||
|
||||
bool Charset::load(const char *filename, bool disableCharLiterals) {
|
||||
|
||||
if (FILE *f = fopen(filename, "rb")) {
|
||||
|
||||
enum {
|
||||
CLEAR,
|
||||
TIGHT,
|
||||
RANGE_BRACKET,
|
||||
RANGE_START,
|
||||
RANGE_SEPARATOR,
|
||||
RANGE_END
|
||||
} state = CLEAR;
|
||||
|
||||
std::string buffer;
|
||||
std::vector<unicode_t> unicodeBuffer;
|
||||
unicode_t rangeStart = 0;
|
||||
for (int c = fgetc(f), start = true; c >= 0; start = false) {
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // number
|
||||
if (!(state == CLEAR || state == RANGE_BRACKET || state == RANGE_SEPARATOR))
|
||||
goto FAIL;
|
||||
buffer.push_back((char) c);
|
||||
c = readWord(buffer, f);
|
||||
{
|
||||
int cp;
|
||||
if (!parseInt(cp, buffer.c_str()))
|
||||
goto FAIL;
|
||||
switch (state) {
|
||||
case CLEAR:
|
||||
if (cp >= 0)
|
||||
add((unicode_t) cp);
|
||||
state = TIGHT;
|
||||
break;
|
||||
case RANGE_BRACKET:
|
||||
rangeStart = (unicode_t) cp;
|
||||
state = RANGE_START;
|
||||
break;
|
||||
case RANGE_SEPARATOR:
|
||||
for (unicode_t u = rangeStart; (int) u <= cp; ++u)
|
||||
add(u);
|
||||
state = RANGE_END;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
buffer.clear();
|
||||
continue; // next character already read
|
||||
case '\'': // single UTF-8 character
|
||||
if (!(state == CLEAR || state == RANGE_BRACKET || state == RANGE_SEPARATOR) || disableCharLiterals)
|
||||
goto FAIL;
|
||||
if (!readString(buffer, f, '\''))
|
||||
goto FAIL;
|
||||
utf8Decode(unicodeBuffer, buffer.c_str());
|
||||
if (unicodeBuffer.size() == 1) {
|
||||
switch (state) {
|
||||
case CLEAR:
|
||||
if (unicodeBuffer[0] > 0)
|
||||
add(unicodeBuffer[0]);
|
||||
state = TIGHT;
|
||||
break;
|
||||
case RANGE_BRACKET:
|
||||
rangeStart = unicodeBuffer[0];
|
||||
state = RANGE_START;
|
||||
break;
|
||||
case RANGE_SEPARATOR:
|
||||
for (unicode_t u = rangeStart; u <= unicodeBuffer[0]; ++u)
|
||||
add(u);
|
||||
state = RANGE_END;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
} else
|
||||
goto FAIL;
|
||||
unicodeBuffer.clear();
|
||||
buffer.clear();
|
||||
break;
|
||||
case '"': // string of UTF-8 characters
|
||||
if (state != CLEAR || disableCharLiterals)
|
||||
goto FAIL;
|
||||
if (!readString(buffer, f, '"'))
|
||||
goto FAIL;
|
||||
utf8Decode(unicodeBuffer, buffer.c_str());
|
||||
for (unicode_t cp : unicodeBuffer)
|
||||
add(cp);
|
||||
unicodeBuffer.clear();
|
||||
buffer.clear();
|
||||
state = TIGHT;
|
||||
break;
|
||||
case '[': // character range start
|
||||
if (state != CLEAR)
|
||||
goto FAIL;
|
||||
state = RANGE_BRACKET;
|
||||
break;
|
||||
case ']': // character range end
|
||||
if (state == RANGE_END)
|
||||
state = TIGHT;
|
||||
else
|
||||
goto FAIL;
|
||||
break;
|
||||
case '@': // annotation
|
||||
if (state != CLEAR)
|
||||
goto FAIL;
|
||||
c = readWord(buffer, f);
|
||||
if (buffer == "include") {
|
||||
while (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
c = fgetc(f);
|
||||
if (c != '"')
|
||||
goto FAIL;
|
||||
buffer.clear();
|
||||
if (!readString(buffer, f, '"'))
|
||||
goto FAIL;
|
||||
load(combinePath(filename, buffer.c_str()).c_str());
|
||||
state = TIGHT;
|
||||
} else
|
||||
goto FAIL;
|
||||
buffer.clear();
|
||||
break;
|
||||
case ',': case ';': // separator
|
||||
if (!(state == CLEAR || state == TIGHT)) {
|
||||
if (state == RANGE_START)
|
||||
state = RANGE_SEPARATOR;
|
||||
else
|
||||
goto FAIL;
|
||||
} // else treat as whitespace
|
||||
case ' ': case '\n': case '\r': case '\t': // whitespace
|
||||
if (state == TIGHT)
|
||||
state = CLEAR;
|
||||
break;
|
||||
case 0xef: // UTF-8 byte order mark
|
||||
if (start) {
|
||||
if (!(fgetc(f) == 0xbb && fgetc(f) == 0xbf))
|
||||
goto FAIL;
|
||||
break;
|
||||
}
|
||||
default: // unexpected character
|
||||
goto FAIL;
|
||||
}
|
||||
c = fgetc(f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return state == CLEAR || state == TIGHT;
|
||||
|
||||
FAIL:
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
45
Nuake/src/Vendors/msdf-atlas-gen/csv-export.cpp
Normal file
45
Nuake/src/Vendors/msdf-atlas-gen/csv-export.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#include "csv-export.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
bool exportCSV(const FontGeometry *fonts, int fontCount, int atlasWidth, int atlasHeight, YDirection yDirection, const char *filename) {
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
for (const GlyphGeometry &glyph : fonts[i].getGlyphs()) {
|
||||
double l, b, r, t;
|
||||
if (fontCount > 1)
|
||||
fprintf(f, "%d,", i);
|
||||
fprintf(f, "%d,%.17g,", glyph.getIdentifier(fonts[i].getPreferredIdentifierType()), glyph.getAdvance());
|
||||
glyph.getQuadPlaneBounds(l, b, r, t);
|
||||
switch (yDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g,", l, b, r, t);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g,", l, -t, r, -b);
|
||||
break;
|
||||
}
|
||||
glyph.getQuadAtlasBounds(l, b, r, t);
|
||||
switch (yDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g\n", l, b, r, t);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g\n", l, atlasHeight-t, r, atlasHeight-b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
14
Nuake/src/Vendors/msdf-atlas-gen/csv-export.h
Normal file
14
Nuake/src/Vendors/msdf-atlas-gen/csv-export.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* Writes the positioning data and atlas layout of the glyphs into a CSV file
|
||||
* The columns are: font variant index (if fontCount > 1), glyph identifier (index or Unicode), horizontal advance, plane bounds (l, b, r, t), atlas bounds (l, b, r, t)
|
||||
*/
|
||||
bool exportCSV(const FontGeometry *fonts, int fontCount, int atlasWidth, int atlasHeight, YDirection yDirection, const char *filename);
|
||||
|
||||
}
|
||||
52
Nuake/src/Vendors/msdf-atlas-gen/glyph-generators.cpp
Normal file
52
Nuake/src/Vendors/msdf-atlas-gen/glyph-generators.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
#include "glyph-generators.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
void scanlineGenerator(const msdfgen::BitmapRef<float, 1> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs) {
|
||||
msdfgen::rasterize(output, glyph.getShape(), glyph.getBoxScale(), glyph.getBoxTranslate(), MSDF_ATLAS_GLYPH_FILL_RULE);
|
||||
}
|
||||
|
||||
void sdfGenerator(const msdfgen::BitmapRef<float, 1> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs) {
|
||||
msdfgen::generateSDF(output, glyph.getShape(), glyph.getBoxProjection(), glyph.getBoxRange(), attribs.config);
|
||||
if (attribs.scanlinePass)
|
||||
msdfgen::distanceSignCorrection(output, glyph.getShape(), glyph.getBoxProjection(), MSDF_ATLAS_GLYPH_FILL_RULE);
|
||||
}
|
||||
|
||||
void psdfGenerator(const msdfgen::BitmapRef<float, 1> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs) {
|
||||
msdfgen::generatePseudoSDF(output, glyph.getShape(), glyph.getBoxProjection(), glyph.getBoxRange(), attribs.config);
|
||||
if (attribs.scanlinePass)
|
||||
msdfgen::distanceSignCorrection(output, glyph.getShape(), glyph.getBoxProjection(), MSDF_ATLAS_GLYPH_FILL_RULE);
|
||||
}
|
||||
|
||||
void msdfGenerator(const msdfgen::BitmapRef<float, 3> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs) {
|
||||
msdfgen::MSDFGeneratorConfig config = attribs.config;
|
||||
if (attribs.scanlinePass)
|
||||
config.errorCorrection.mode = msdfgen::ErrorCorrectionConfig::DISABLED;
|
||||
msdfgen::generateMSDF(output, glyph.getShape(), glyph.getBoxProjection(), glyph.getBoxRange(), config);
|
||||
if (attribs.scanlinePass) {
|
||||
msdfgen::distanceSignCorrection(output, glyph.getShape(), glyph.getBoxProjection(), MSDF_ATLAS_GLYPH_FILL_RULE);
|
||||
if (attribs.config.errorCorrection.mode != msdfgen::ErrorCorrectionConfig::DISABLED) {
|
||||
config.errorCorrection.mode = attribs.config.errorCorrection.mode;
|
||||
config.errorCorrection.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
msdfgen::msdfErrorCorrection(output, glyph.getShape(), glyph.getBoxProjection(), glyph.getBoxRange(), config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mtsdfGenerator(const msdfgen::BitmapRef<float, 4> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs) {
|
||||
msdfgen::MSDFGeneratorConfig config = attribs.config;
|
||||
if (attribs.scanlinePass)
|
||||
config.errorCorrection.mode = msdfgen::ErrorCorrectionConfig::DISABLED;
|
||||
msdfgen::generateMTSDF(output, glyph.getShape(), glyph.getBoxProjection(), glyph.getBoxRange(), config);
|
||||
if (attribs.scanlinePass) {
|
||||
msdfgen::distanceSignCorrection(output, glyph.getShape(), glyph.getBoxProjection(), MSDF_ATLAS_GLYPH_FILL_RULE);
|
||||
if (attribs.config.errorCorrection.mode != msdfgen::ErrorCorrectionConfig::DISABLED) {
|
||||
config.errorCorrection.mode = attribs.config.errorCorrection.mode;
|
||||
config.errorCorrection.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
msdfgen::msdfErrorCorrection(output, glyph.getShape(), glyph.getBoxProjection(), glyph.getBoxRange(), config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
25
Nuake/src/Vendors/msdf-atlas-gen/glyph-generators.h
Normal file
25
Nuake/src/Vendors/msdf-atlas-gen/glyph-generators.h
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include "GlyphGeometry.h"
|
||||
#include "AtlasGenerator.h"
|
||||
|
||||
#define MSDF_ATLAS_GLYPH_FILL_RULE msdfgen::FILL_NONZERO
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
// Glyph bitmap generator functions
|
||||
|
||||
/// Generates non-anti-aliased binary image of the glyph using scanline rasterization
|
||||
void scanlineGenerator(const msdfgen::BitmapRef<float, 1> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs);
|
||||
/// Generates a true signed distance field of the glyph
|
||||
void sdfGenerator(const msdfgen::BitmapRef<float, 1> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs);
|
||||
/// Generates a signed pseudo-distance field of the glyph
|
||||
void psdfGenerator(const msdfgen::BitmapRef<float, 1> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs);
|
||||
/// Generates a multi-channel signed distance field of the glyph
|
||||
void msdfGenerator(const msdfgen::BitmapRef<float, 3> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs);
|
||||
/// Generates a multi-channel and alpha-encoded true signed distance field of the glyph
|
||||
void mtsdfGenerator(const msdfgen::BitmapRef<float, 4> &output, const GlyphGeometry &glyph, const GeneratorAttributes &attribs);
|
||||
|
||||
}
|
||||
BIN
Nuake/src/Vendors/msdf-atlas-gen/icon.ico
Normal file
BIN
Nuake/src/Vendors/msdf-atlas-gen/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
63
Nuake/src/Vendors/msdf-atlas-gen/image-encode.cpp
Normal file
63
Nuake/src/Vendors/msdf-atlas-gen/image-encode.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
#include "image-encode.h"
|
||||
|
||||
#include <lodepng.h>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<msdfgen::byte, 1> &bitmap) {
|
||||
std::vector<byte> pixels(bitmap.width*bitmap.height);
|
||||
for (int y = 0; y < bitmap.height; ++y)
|
||||
memcpy(&pixels[bitmap.width*y], bitmap(0, bitmap.height-y-1), bitmap.width);
|
||||
return !lodepng::encode(output, pixels, bitmap.width, bitmap.height, LCT_GREY);
|
||||
}
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<msdfgen::byte, 3> &bitmap) {
|
||||
std::vector<byte> pixels(3*bitmap.width*bitmap.height);
|
||||
for (int y = 0; y < bitmap.height; ++y)
|
||||
memcpy(&pixels[3*bitmap.width*y], bitmap(0, bitmap.height-y-1), 3*bitmap.width);
|
||||
return !lodepng::encode(output, pixels, bitmap.width, bitmap.height, LCT_RGB);
|
||||
}
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<msdfgen::byte, 4> &bitmap) {
|
||||
std::vector<byte> pixels(4*bitmap.width*bitmap.height);
|
||||
for (int y = 0; y < bitmap.height; ++y)
|
||||
memcpy(&pixels[4*bitmap.width*y], bitmap(0, bitmap.height-y-1), 4*bitmap.width);
|
||||
return !lodepng::encode(output, pixels, bitmap.width, bitmap.height, LCT_RGBA);
|
||||
}
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<float, 1> &bitmap) {
|
||||
std::vector<byte> pixels(bitmap.width*bitmap.height);
|
||||
std::vector<byte>::iterator it = pixels.begin();
|
||||
for (int y = bitmap.height-1; y >= 0; --y)
|
||||
for (int x = 0; x < bitmap.width; ++x)
|
||||
*it++ = msdfgen::pixelFloatToByte(*bitmap(x, y));
|
||||
return !lodepng::encode(output, pixels, bitmap.width, bitmap.height, LCT_GREY);
|
||||
}
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<float, 3> &bitmap) {
|
||||
std::vector<byte> pixels(3*bitmap.width*bitmap.height);
|
||||
std::vector<byte>::iterator it = pixels.begin();
|
||||
for (int y = bitmap.height-1; y >= 0; --y)
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[0]);
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[1]);
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[2]);
|
||||
}
|
||||
return !lodepng::encode(output, pixels, bitmap.width, bitmap.height, LCT_RGB);
|
||||
}
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<float, 4> &bitmap) {
|
||||
std::vector<byte> pixels(4*bitmap.width*bitmap.height);
|
||||
std::vector<byte>::iterator it = pixels.begin();
|
||||
for (int y = bitmap.height-1; y >= 0; --y)
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[0]);
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[1]);
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[2]);
|
||||
*it++ = msdfgen::pixelFloatToByte(bitmap(x, y)[3]);
|
||||
}
|
||||
return !lodepng::encode(output, pixels, bitmap.width, bitmap.height, LCT_RGBA);
|
||||
}
|
||||
|
||||
}
|
||||
20
Nuake/src/Vendors/msdf-atlas-gen/image-encode.h
Normal file
20
Nuake/src/Vendors/msdf-atlas-gen/image-encode.h
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <msdfgen.h>
|
||||
#include "types.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
// Functions to encode an image as a sequence of bytes in memory
|
||||
// Only PNG format available currently
|
||||
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<msdfgen::byte, 1> &bitmap);
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<msdfgen::byte, 3> &bitmap);
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<msdfgen::byte, 4> &bitmap);
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<float, 1> &bitmap);
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<float, 3> &bitmap);
|
||||
bool encodePng(std::vector<byte> &output, const msdfgen::BitmapConstRef<float, 4> &bitmap);
|
||||
|
||||
}
|
||||
15
Nuake/src/Vendors/msdf-atlas-gen/image-save.h
Normal file
15
Nuake/src/Vendors/msdf-atlas-gen/image-save.h
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include "types.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Saves the bitmap as an image file with the specified format
|
||||
template <typename T, int N>
|
||||
bool saveImage(const msdfgen::BitmapConstRef<T, N> &bitmap, ImageFormat format, const char *filename, YDirection outputYDirection = YDirection::BOTTOM_UP);
|
||||
|
||||
}
|
||||
|
||||
#include "image-save.hpp"
|
||||
172
Nuake/src/Vendors/msdf-atlas-gen/image-save.hpp
Normal file
172
Nuake/src/Vendors/msdf-atlas-gen/image-save.hpp
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
#include "image-save.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <msdfgen-ext.h>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
template <int N>
|
||||
bool saveImageBinary(const msdfgen::BitmapConstRef<byte, N> &bitmap, const char *filename, YDirection outputYDirection);
|
||||
template <int N>
|
||||
bool saveImageBinaryLE(const msdfgen::BitmapConstRef<float, N> &bitmap, const char *filename, YDirection outputYDirection);
|
||||
template <int N>
|
||||
bool saveImageBinaryBE(const msdfgen::BitmapConstRef<float, N> &bitmap, const char *filename, YDirection outputYDirection);
|
||||
|
||||
template <int N>
|
||||
bool saveImageText(const msdfgen::BitmapConstRef<byte, N> &bitmap, const char *filename, YDirection outputYDirection);
|
||||
template <int N>
|
||||
bool saveImageText(const msdfgen::BitmapConstRef<float, N> &bitmap, const char *filename, YDirection outputYDirection);
|
||||
|
||||
template <int N>
|
||||
bool saveImage(const msdfgen::BitmapConstRef<byte, N> &bitmap, ImageFormat format, const char *filename, YDirection outputYDirection) {
|
||||
switch (format) {
|
||||
//case ImageFormat::PNG:
|
||||
// return msdfgen::savePng(bitmap, filename);
|
||||
case ImageFormat::BMP:
|
||||
return msdfgen::saveBmp(bitmap, filename);
|
||||
case ImageFormat::TIFF:
|
||||
return false;
|
||||
case ImageFormat::TEXT:
|
||||
return saveImageText(bitmap, filename, outputYDirection);
|
||||
case ImageFormat::TEXT_FLOAT:
|
||||
return false;
|
||||
case ImageFormat::BINARY:
|
||||
return saveImageBinary(bitmap, filename, outputYDirection);
|
||||
case ImageFormat::BINARY_FLOAT:
|
||||
case ImageFormat::BINARY_FLOAT_BE:
|
||||
return false;
|
||||
default:;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool saveImage(const msdfgen::BitmapConstRef<float, N> &bitmap, ImageFormat format, const char *filename, YDirection outputYDirection) {
|
||||
switch (format) {
|
||||
case ImageFormat::PNG:
|
||||
return msdfgen::savePng(bitmap, filename);
|
||||
case ImageFormat::BMP:
|
||||
return msdfgen::saveBmp(bitmap, filename);
|
||||
case ImageFormat::TIFF:
|
||||
return msdfgen::saveTiff(bitmap, filename);
|
||||
case ImageFormat::TEXT:
|
||||
return false;
|
||||
case ImageFormat::TEXT_FLOAT:
|
||||
return saveImageText(bitmap, filename, outputYDirection);
|
||||
case ImageFormat::BINARY:
|
||||
return false;
|
||||
case ImageFormat::BINARY_FLOAT:
|
||||
return saveImageBinaryLE(bitmap, filename, outputYDirection);
|
||||
case ImageFormat::BINARY_FLOAT_BE:
|
||||
return saveImageBinaryBE(bitmap, filename, outputYDirection);
|
||||
default:;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool saveImageBinary(const msdfgen::BitmapConstRef<byte, N> &bitmap, const char *filename, YDirection outputYDirection) {
|
||||
bool success = false;
|
||||
if (FILE *f = fopen(filename, "wb")) {
|
||||
int written = 0;
|
||||
switch (outputYDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
written = fwrite(bitmap.pixels, 1, N*bitmap.width*bitmap.height, f);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
for (int y = bitmap.height-1; y >= 0; --y)
|
||||
written += fwrite(bitmap.pixels+N*bitmap.width*y, 1, N*bitmap.width, f);
|
||||
break;
|
||||
}
|
||||
success = written == N*bitmap.width*bitmap.height;
|
||||
fclose(f);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool
|
||||
#ifdef __BIG_ENDIAN__
|
||||
saveImageBinaryBE
|
||||
#else
|
||||
saveImageBinaryLE
|
||||
#endif
|
||||
(const msdfgen::BitmapConstRef<float, N> &bitmap, const char *filename, YDirection outputYDirection) {
|
||||
bool success = false;
|
||||
if (FILE *f = fopen(filename, "wb")) {
|
||||
int written = 0;
|
||||
switch (outputYDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
written = fwrite(bitmap.pixels, sizeof(float), N*bitmap.width*bitmap.height, f);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
for (int y = bitmap.height-1; y >= 0; --y)
|
||||
written += fwrite(bitmap.pixels+N*bitmap.width*y, sizeof(float), N*bitmap.width, f);
|
||||
break;
|
||||
}
|
||||
success = written == N*bitmap.width*bitmap.height;
|
||||
fclose(f);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool
|
||||
#ifdef __BIG_ENDIAN__
|
||||
saveImageBinaryLE
|
||||
#else
|
||||
saveImageBinaryBE
|
||||
#endif
|
||||
(const msdfgen::BitmapConstRef<float, N> &bitmap, const char *filename, YDirection outputYDirection) {
|
||||
bool success = false;
|
||||
if (FILE *f = fopen(filename, "wb")) {
|
||||
int written = 0;
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
const float *p = bitmap.pixels+N*bitmap.width*(outputYDirection == YDirection::TOP_DOWN ? bitmap.height-y-1 : y);
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
const unsigned char *b = reinterpret_cast<const unsigned char *>(p++);
|
||||
for (int i = sizeof(float)-1; i >= 0; --i)
|
||||
written += fwrite(b+i, 1, 1, f);
|
||||
}
|
||||
}
|
||||
success = written == sizeof(float)*N*bitmap.width*bitmap.height;
|
||||
fclose(f);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
template <int N>
|
||||
bool saveImageText(const msdfgen::BitmapConstRef<byte, N> &bitmap, const char *filename, YDirection outputYDirection) {
|
||||
bool success = false;
|
||||
if (FILE *f = fopen(filename, "wb")) {
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
const byte *p = bitmap.pixels+N*bitmap.width*(outputYDirection == YDirection::TOP_DOWN ? bitmap.height-y-1 : y);
|
||||
for (int x = 0; x < N*bitmap.width; ++x) {
|
||||
fprintf(f, x ? " %02X" : "%02X", (unsigned) *p++);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool saveImageText(const msdfgen::BitmapConstRef<float, N> &bitmap, const char *filename, YDirection outputYDirection) {
|
||||
bool success = false;
|
||||
if (FILE *f = fopen(filename, "wb")) {
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
const float *p = bitmap.pixels+N*bitmap.width*(outputYDirection == YDirection::TOP_DOWN ? bitmap.height-y-1 : y);
|
||||
for (int x = 0; x < N*bitmap.width; ++x) {
|
||||
fprintf(f, x ? " %g" : "%g", *p++);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
||||
186
Nuake/src/Vendors/msdf-atlas-gen/json-export.cpp
Normal file
186
Nuake/src/Vendors/msdf-atlas-gen/json-export.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
|
||||
#include "json-export.h"
|
||||
|
||||
#include <string>
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static std::string escapeJsonString(const char *str) {
|
||||
char uval[7] = "\\u0000";
|
||||
std::string outStr;
|
||||
while (*str) {
|
||||
switch (*str) {
|
||||
case '\\':
|
||||
outStr += "\\\\";
|
||||
break;
|
||||
case '"':
|
||||
outStr += "\\\"";
|
||||
break;
|
||||
case '\n':
|
||||
outStr += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
outStr += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
outStr += "\\t";
|
||||
break;
|
||||
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: /* \\t */ /* \\n */ case 0x0b: case 0x0c: /* \\r */ case 0x0e: case 0x0f:
|
||||
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
||||
uval[4] = '0'+(*str >= 0x10);
|
||||
uval[5] = "0123456789abcdef"[*str&0x0f];
|
||||
outStr += uval;
|
||||
break;
|
||||
default:
|
||||
outStr.push_back(*str);
|
||||
}
|
||||
++str;
|
||||
}
|
||||
return outStr;
|
||||
}
|
||||
|
||||
static const char * imageTypeString(ImageType type) {
|
||||
switch (type) {
|
||||
case ImageType::HARD_MASK:
|
||||
return "hardmask";
|
||||
case ImageType::SOFT_MASK:
|
||||
return "softmask";
|
||||
case ImageType::SDF:
|
||||
return "sdf";
|
||||
case ImageType::PSDF:
|
||||
return "psdf";
|
||||
case ImageType::MSDF:
|
||||
return "msdf";
|
||||
case ImageType::MTSDF:
|
||||
return "mtsdf";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool exportJSON(const FontGeometry *fonts, int fontCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, YDirection yDirection, const char *filename, bool kerning) {
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (!f)
|
||||
return false;
|
||||
fputs("{", f);
|
||||
|
||||
// Atlas properties
|
||||
fputs("\"atlas\":{", f); {
|
||||
fprintf(f, "\"type\":\"%s\",", imageTypeString(imageType));
|
||||
if (imageType == ImageType::SDF || imageType == ImageType::PSDF || imageType == ImageType::MSDF || imageType == ImageType::MTSDF)
|
||||
fprintf(f, "\"distanceRange\":%.17g,", pxRange);
|
||||
fprintf(f, "\"size\":%.17g,", fontSize);
|
||||
fprintf(f, "\"width\":%d,", atlasWidth);
|
||||
fprintf(f, "\"height\":%d,", atlasHeight);
|
||||
fprintf(f, "\"yOrigin\":\"%s\"", yDirection == YDirection::TOP_DOWN ? "top" : "bottom");
|
||||
} fputs("},", f);
|
||||
|
||||
if (fontCount > 1)
|
||||
fputs("\"variants\":[", f);
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
const FontGeometry &font = fonts[i];
|
||||
if (fontCount > 1)
|
||||
fputs(i == 0 ? "{" : ",{", f);
|
||||
|
||||
// Font name
|
||||
const char *name = font.getName();
|
||||
if (name)
|
||||
fprintf(f, "\"name\":\"%s\",", escapeJsonString(name).c_str());
|
||||
|
||||
// Font metrics
|
||||
fputs("\"metrics\":{", f); {
|
||||
double yFactor = yDirection == YDirection::TOP_DOWN ? -1 : 1;
|
||||
const msdfgen::FontMetrics &metrics = font.getMetrics();
|
||||
fprintf(f, "\"emSize\":%.17g,", metrics.emSize);
|
||||
fprintf(f, "\"lineHeight\":%.17g,", metrics.lineHeight);
|
||||
fprintf(f, "\"ascender\":%.17g,", yFactor*metrics.ascenderY);
|
||||
fprintf(f, "\"descender\":%.17g,", yFactor*metrics.descenderY);
|
||||
fprintf(f, "\"underlineY\":%.17g,", yFactor*metrics.underlineY);
|
||||
fprintf(f, "\"underlineThickness\":%.17g", metrics.underlineThickness);
|
||||
} fputs("},", f);
|
||||
|
||||
// Glyph mapping
|
||||
fputs("\"glyphs\":[", f);
|
||||
bool firstGlyph = true;
|
||||
for (const GlyphGeometry &glyph : font.getGlyphs()) {
|
||||
fputs(firstGlyph ? "{" : ",{", f);
|
||||
switch (font.getPreferredIdentifierType()) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
fprintf(f, "\"index\":%d,", glyph.getIndex());
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
fprintf(f, "\"unicode\":%u,", glyph.getCodepoint());
|
||||
break;
|
||||
}
|
||||
fprintf(f, "\"advance\":%.17g", glyph.getAdvance());
|
||||
double l, b, r, t;
|
||||
glyph.getQuadPlaneBounds(l, b, r, t);
|
||||
if (l || b || r || t) {
|
||||
switch (yDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
fprintf(f, ",\"planeBounds\":{\"left\":%.17g,\"bottom\":%.17g,\"right\":%.17g,\"top\":%.17g}", l, b, r, t);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
fprintf(f, ",\"planeBounds\":{\"left\":%.17g,\"top\":%.17g,\"right\":%.17g,\"bottom\":%.17g}", l, -t, r, -b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
glyph.getQuadAtlasBounds(l, b, r, t);
|
||||
if (l || b || r || t) {
|
||||
switch (yDirection) {
|
||||
case YDirection::BOTTOM_UP:
|
||||
fprintf(f, ",\"atlasBounds\":{\"left\":%.17g,\"bottom\":%.17g,\"right\":%.17g,\"top\":%.17g}", l, b, r, t);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
fprintf(f, ",\"atlasBounds\":{\"left\":%.17g,\"top\":%.17g,\"right\":%.17g,\"bottom\":%.17g}", l, atlasHeight-t, r, atlasHeight-b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fputs("}", f);
|
||||
firstGlyph = false;
|
||||
} fputs("]", f);
|
||||
|
||||
// Kerning pairs
|
||||
if (kerning) {
|
||||
fputs(",\"kerning\":[", f);
|
||||
bool firstPair = true;
|
||||
switch (font.getPreferredIdentifierType()) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
for (const std::pair<std::pair<int, int>, double> &kernPair : font.getKerning()) {
|
||||
fputs(firstPair ? "{" : ",{", f);
|
||||
fprintf(f, "\"index1\":%d,", kernPair.first.first);
|
||||
fprintf(f, "\"index2\":%d,", kernPair.first.second);
|
||||
fprintf(f, "\"advance\":%.17g", kernPair.second);
|
||||
fputs("}", f);
|
||||
firstPair = false;
|
||||
}
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
for (const std::pair<std::pair<int, int>, double> &kernPair : font.getKerning()) {
|
||||
const GlyphGeometry *glyph1 = font.getGlyph(msdfgen::GlyphIndex(kernPair.first.first));
|
||||
const GlyphGeometry *glyph2 = font.getGlyph(msdfgen::GlyphIndex(kernPair.first.second));
|
||||
if (glyph1 && glyph2 && glyph1->getCodepoint() && glyph2->getCodepoint()) {
|
||||
fputs(firstPair ? "{" : ",{", f);
|
||||
fprintf(f, "\"unicode1\":%u,", glyph1->getCodepoint());
|
||||
fprintf(f, "\"unicode2\":%u,", glyph2->getCodepoint());
|
||||
fprintf(f, "\"advance\":%.17g", kernPair.second);
|
||||
fputs("}", f);
|
||||
firstPair = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} fputs("]", f);
|
||||
}
|
||||
|
||||
if (fontCount > 1)
|
||||
fputs("}", f);
|
||||
}
|
||||
if (fontCount > 1)
|
||||
fputs("]", f);
|
||||
|
||||
fputs("}\n", f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
14
Nuake/src/Vendors/msdf-atlas-gen/json-export.h
Normal file
14
Nuake/src/Vendors/msdf-atlas-gen/json-export.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Writes the font and glyph metrics and atlas layout data into a comprehensive JSON file
|
||||
bool exportJSON(const FontGeometry *fonts, int fontCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, YDirection yDirection, const char *filename, bool kerning);
|
||||
|
||||
}
|
||||
999
Nuake/src/Vendors/msdf-atlas-gen/main.cpp
Normal file
999
Nuake/src/Vendors/msdf-atlas-gen/main.cpp
Normal file
@@ -0,0 +1,999 @@
|
||||
|
||||
/*
|
||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD ATLAS GENERATOR v1.2 (2021-05-29) - standalone console program
|
||||
* --------------------------------------------------------------------------------------------------
|
||||
* A utility by Viktor Chlumsky, (c) 2020 - 2021
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef MSDF_ATLAS_STANDALONE
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
#include "msdf-atlas-gen.h"
|
||||
|
||||
using namespace msdf_atlas;
|
||||
|
||||
#define DEFAULT_ANGLE_THRESHOLD 3.0
|
||||
#define DEFAULT_MITER_LIMIT 1.0
|
||||
#define DEFAULT_PIXEL_RANGE 2.0
|
||||
#define SDF_ERROR_ESTIMATE_PRECISION 19
|
||||
#define GLYPH_FILL_RULE msdfgen::FILL_NONZERO
|
||||
#define LCG_MULTIPLIER 6364136223846793005ull
|
||||
#define LCG_INCREMENT 1442695040888963407ull
|
||||
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
#define TITLE_SUFFIX " & Skia"
|
||||
#define EXTRA_UNDERLINE "-------"
|
||||
#else
|
||||
#define TITLE_SUFFIX
|
||||
#define EXTRA_UNDERLINE
|
||||
#endif
|
||||
|
||||
static const char * const helpText = R"(
|
||||
MSDF Atlas Generator by Viktor Chlumsky v)" MSDF_ATLAS_VERSION R"( (with MSDFGEN v)" MSDFGEN_VERSION TITLE_SUFFIX R"()
|
||||
----------------------------------------------------------------)" EXTRA_UNDERLINE R"(
|
||||
|
||||
INPUT SPECIFICATION
|
||||
-font <filename.ttf/otf>
|
||||
Specifies the input TrueType / OpenType font file. This is required.
|
||||
-charset <filename>
|
||||
Specifies the input character set. Refer to the documentation for format of charset specification. Defaults to ASCII.
|
||||
-glyphset <filename>
|
||||
Specifies the set of input glyphs as glyph indices within the font file.
|
||||
-fontscale <scale>
|
||||
Specifies the scale to be applied to the glyph geometry of the font.
|
||||
-fontname <name>
|
||||
Specifies a name for the font that will be propagated into the output files as metadata.
|
||||
-and
|
||||
Separates multiple inputs to be combined into a single atlas.
|
||||
|
||||
ATLAS CONFIGURATION
|
||||
-type <hardmask / softmask / sdf / psdf / msdf / mtsdf>
|
||||
Selects the type of atlas to be generated.
|
||||
-format <png / bmp / tiff / text / textfloat / bin / binfloat / binfloatbe>
|
||||
Selects the format for the atlas image output. Some image formats may be incompatible with embedded output formats.
|
||||
-dimensions <width> <height>
|
||||
Sets the atlas to have fixed dimensions (width x height).
|
||||
-pots / -potr / -square / -square2 / -square4
|
||||
Picks the minimum atlas dimensions that fit all glyphs and satisfy the selected constraint:
|
||||
power of two square / ... rectangle / any square / square with side divisible by 2 / ... 4
|
||||
-yorigin <bottom / top>
|
||||
Determines whether the Y-axis is oriented upwards (bottom origin, default) or downwards (top origin).
|
||||
|
||||
OUTPUT SPECIFICATION - one or more can be specified
|
||||
-imageout <filename.*>
|
||||
Saves the atlas as an image file with the specified format. Layout data must be stored separately.
|
||||
-json <filename.json>
|
||||
Writes the atlas's layout data, as well as other metrics into a structured JSON file.
|
||||
-csv <filename.csv>
|
||||
Writes the layout data of the glyphs into a simple CSV file.
|
||||
-arfont <filename.arfont>
|
||||
Stores the atlas and its layout data as an Artery Font file. Supported formats: png, bin, binfloat.
|
||||
-shadronpreview <filename.shadron> <sample text>
|
||||
Generates a Shadron script that uses the generated atlas to draw a sample text as a preview.
|
||||
|
||||
GLYPH CONFIGURATION
|
||||
-size <EM size>
|
||||
Specifies the size of the glyphs in the atlas bitmap in pixels per EM.
|
||||
-minsize <EM size>
|
||||
Specifies the minimum size. The largest possible size that fits the same atlas dimensions will be used.
|
||||
-emrange <EM range>
|
||||
Specifies the SDF distance range in EM's.
|
||||
-pxrange <pixel range>
|
||||
Specifies the SDF distance range in output pixels. The default value is 2.
|
||||
-nokerning
|
||||
Disables inclusion of kerning pair table in output files.
|
||||
|
||||
DISTANCE FIELD GENERATOR SETTINGS
|
||||
-angle <angle>
|
||||
Specifies the minimum angle between adjacent edges to be considered a corner. Append D for degrees. (msdf / mtsdf only)
|
||||
-coloringstrategy <simple / inktrap / distance>
|
||||
Selects the strategy of the edge coloring heuristic.
|
||||
-errorcorrection <mode>
|
||||
Changes the MSDF/MTSDF error correction mode. Use -errorcorrection help for a list of valid modes.
|
||||
-errordeviationratio <ratio>
|
||||
Sets the minimum ratio between the actual and maximum expected distance delta to be considered an error.
|
||||
-errorimproveratio <ratio>
|
||||
Sets the minimum ratio between the pre-correction distance error and the post-correction distance error.
|
||||
-miterlimit <value>
|
||||
Sets the miter limit that limits the extension of each glyph's bounding box due to very sharp corners. (psdf / msdf / mtsdf only))"
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
R"(
|
||||
-overlap
|
||||
Switches to distance field generator with support for overlapping contours.
|
||||
-nopreprocess
|
||||
Disables path preprocessing which resolves self-intersections and overlapping contours.
|
||||
-scanline
|
||||
Performs an additional scanline pass to fix the signs of the distances.)"
|
||||
#else
|
||||
R"(
|
||||
-nooverlap
|
||||
Disables resolution of overlapping contours.
|
||||
-noscanline
|
||||
Disables the scanline pass, which corrects the distance field's signs according to the non-zero fill rule.)"
|
||||
#endif
|
||||
R"(
|
||||
-seed <N>
|
||||
Sets the initial seed for the edge coloring heuristic.
|
||||
-threads <N>
|
||||
Sets the number of threads for the parallel computation. (0 = auto)
|
||||
)";
|
||||
|
||||
static const char *errorCorrectionHelpText = R"(
|
||||
ERROR CORRECTION MODES
|
||||
auto-fast
|
||||
Detects inversion artifacts and distance errors that do not affect edges by range testing.
|
||||
auto-full
|
||||
Detects inversion artifacts and distance errors that do not affect edges by exact distance evaluation.
|
||||
auto-mixed (default)
|
||||
Detects inversions by distance evaluation and distance errors that do not affect edges by range testing.
|
||||
disabled
|
||||
Disables error correction.
|
||||
distance-fast
|
||||
Detects distance errors by range testing. Does not care if edges and corners are affected.
|
||||
distance-full
|
||||
Detects distance errors by exact distance evaluation. Does not care if edges and corners are affected, slow.
|
||||
edge-fast
|
||||
Detects inversion artifacts only by range testing.
|
||||
edge-full
|
||||
Detects inversion artifacts only by exact distance evaluation.
|
||||
help
|
||||
Displays this help.
|
||||
)";
|
||||
|
||||
static char toupper(char c) {
|
||||
return c >= 'a' && c <= 'z' ? c-'a'+'A' : c;
|
||||
}
|
||||
|
||||
static bool parseUnsigned(unsigned &value, const char *arg) {
|
||||
static char c;
|
||||
return sscanf(arg, "%u%c", &value, &c) == 1;
|
||||
}
|
||||
|
||||
static bool parseUnsignedLL(unsigned long long &value, const char *arg) {
|
||||
static char c;
|
||||
return sscanf(arg, "%llu%c", &value, &c) == 1;
|
||||
}
|
||||
|
||||
static bool parseDouble(double &value, const char *arg) {
|
||||
static char c;
|
||||
return sscanf(arg, "%lf%c", &value, &c) == 1;
|
||||
}
|
||||
|
||||
static bool parseAngle(double &value, const char *arg) {
|
||||
char c1, c2;
|
||||
int result = sscanf(arg, "%lf%c%c", &value, &c1, &c2);
|
||||
if (result == 1)
|
||||
return true;
|
||||
if (result == 2 && (c1 == 'd' || c1 == 'D')) {
|
||||
value *= M_PI/180;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool cmpExtension(const char *path, const char *ext) {
|
||||
for (const char *a = path+strlen(path)-1, *b = ext+strlen(ext)-1; b >= ext; --a, --b)
|
||||
if (a < path || toupper(*a) != toupper(*b))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct FontInput {
|
||||
const char *fontFilename;
|
||||
GlyphIdentifierType glyphIdentifierType;
|
||||
const char *charsetFilename;
|
||||
double fontScale;
|
||||
const char *fontName;
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
ImageType imageType;
|
||||
ImageFormat imageFormat;
|
||||
YDirection yDirection;
|
||||
int width, height;
|
||||
double emSize;
|
||||
double pxRange;
|
||||
double angleThreshold;
|
||||
double miterLimit;
|
||||
void (*edgeColoring)(msdfgen::Shape &, double, unsigned long long);
|
||||
bool expensiveColoring;
|
||||
unsigned long long coloringSeed;
|
||||
GeneratorAttributes generatorAttributes;
|
||||
bool preprocessGeometry;
|
||||
bool kerning;
|
||||
int threadCount;
|
||||
const char *arteryFontFilename;
|
||||
const char *imageFilename;
|
||||
const char *jsonFilename;
|
||||
const char *csvFilename;
|
||||
const char *shadronPreviewFilename;
|
||||
const char *shadronPreviewText;
|
||||
};
|
||||
|
||||
template <typename T, typename S, int N, GeneratorFunction<S, N> GEN_FN>
|
||||
static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, const std::vector<FontGeometry> &fonts, const Configuration &config) {
|
||||
ImmediateAtlasGenerator<S, N, GEN_FN, BitmapAtlasStorage<T, N> > generator(config.width, config.height);
|
||||
generator.setAttributes(config.generatorAttributes);
|
||||
generator.setThreadCount(config.threadCount);
|
||||
generator.generate(glyphs.data(), glyphs.size());
|
||||
msdfgen::BitmapConstRef<T, N> bitmap = (msdfgen::BitmapConstRef<T, N>) generator.atlasStorage();
|
||||
|
||||
bool success = true;
|
||||
|
||||
if (config.imageFilename) {
|
||||
if (saveImage(bitmap, config.imageFormat, config.imageFilename, config.yDirection))
|
||||
puts("Atlas image file saved.");
|
||||
else {
|
||||
success = false;
|
||||
puts("Failed to save the atlas as an image file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.arteryFontFilename) {
|
||||
ArteryFontExportProperties arfontProps;
|
||||
arfontProps.fontSize = config.emSize;
|
||||
arfontProps.pxRange = config.pxRange;
|
||||
arfontProps.imageType = config.imageType;
|
||||
arfontProps.imageFormat = config.imageFormat;
|
||||
arfontProps.yDirection = config.yDirection;
|
||||
if (exportArteryFont<float>(fonts.data(), fonts.size(), bitmap, config.arteryFontFilename, arfontProps))
|
||||
puts("Artery Font file generated.");
|
||||
else {
|
||||
success = false;
|
||||
puts("Failed to generate Artery Font file.");
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int main(int argc, const char * const *argv) {
|
||||
#define ABORT(msg) { puts(msg); return 1; }
|
||||
|
||||
int result = 0;
|
||||
std::vector<FontInput> fontInputs;
|
||||
FontInput fontInput = { };
|
||||
Configuration config = { };
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
fontInput.fontScale = -1;
|
||||
config.imageType = ImageType::MSDF;
|
||||
config.imageFormat = ImageFormat::UNSPECIFIED;
|
||||
config.yDirection = YDirection::BOTTOM_UP;
|
||||
config.edgeColoring = msdfgen::edgeColoringInkTrap;
|
||||
config.kerning = true;
|
||||
const char *imageFormatName = nullptr;
|
||||
int fixedWidth = -1, fixedHeight = -1;
|
||||
config.preprocessGeometry = (
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
config.generatorAttributes.config.overlapSupport = !config.preprocessGeometry;
|
||||
config.generatorAttributes.scanlinePass = !config.preprocessGeometry;
|
||||
double minEmSize = 0;
|
||||
enum {
|
||||
/// Range specified in EMs
|
||||
RANGE_EM,
|
||||
/// Range specified in output pixels
|
||||
RANGE_PIXEL,
|
||||
} rangeMode = RANGE_PIXEL;
|
||||
double rangeValue = 0;
|
||||
TightAtlasPacker::DimensionsConstraint atlasSizeConstraint = TightAtlasPacker::DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE;
|
||||
config.angleThreshold = DEFAULT_ANGLE_THRESHOLD;
|
||||
config.miterLimit = DEFAULT_MITER_LIMIT;
|
||||
config.threadCount = 0;
|
||||
|
||||
// Parse command line
|
||||
int argPos = 1;
|
||||
bool suggestHelp = false;
|
||||
bool explicitErrorCorrectionMode = false;
|
||||
while (argPos < argc) {
|
||||
const char *arg = argv[argPos];
|
||||
#define ARG_CASE(s, p) if (!strcmp(arg, s) && argPos+(p) < argc)
|
||||
|
||||
ARG_CASE("-type", 1) {
|
||||
arg = argv[++argPos];
|
||||
if (!strcmp(arg, "hardmask"))
|
||||
config.imageType = ImageType::HARD_MASK;
|
||||
else if (!strcmp(arg, "softmask"))
|
||||
config.imageType = ImageType::SOFT_MASK;
|
||||
else if (!strcmp(arg, "sdf"))
|
||||
config.imageType = ImageType::SDF;
|
||||
else if (!strcmp(arg, "psdf"))
|
||||
config.imageType = ImageType::PSDF;
|
||||
else if (!strcmp(arg, "msdf"))
|
||||
config.imageType = ImageType::MSDF;
|
||||
else if (!strcmp(arg, "mtsdf"))
|
||||
config.imageType = ImageType::MTSDF;
|
||||
else
|
||||
ABORT("Invalid atlas type. Valid types are: hardmask, softmask, sdf, psdf, msdf, mtsdf");
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-format", 1) {
|
||||
arg = argv[++argPos];
|
||||
if (!strcmp(arg, "png"))
|
||||
config.imageFormat = ImageFormat::PNG;
|
||||
else if (!strcmp(arg, "bmp"))
|
||||
config.imageFormat = ImageFormat::BMP;
|
||||
else if (!strcmp(arg, "tiff"))
|
||||
config.imageFormat = ImageFormat::TIFF;
|
||||
else if (!strcmp(arg, "text"))
|
||||
config.imageFormat = ImageFormat::TEXT;
|
||||
else if (!strcmp(arg, "textfloat"))
|
||||
config.imageFormat = ImageFormat::TEXT_FLOAT;
|
||||
else if (!strcmp(arg, "bin"))
|
||||
config.imageFormat = ImageFormat::BINARY;
|
||||
else if (!strcmp(arg, "binfloat"))
|
||||
config.imageFormat = ImageFormat::BINARY_FLOAT;
|
||||
else if (!strcmp(arg, "binfloatbe"))
|
||||
config.imageFormat = ImageFormat::BINARY_FLOAT_BE;
|
||||
else
|
||||
ABORT("Invalid image format. Valid formats are: png, bmp, tiff, text, textfloat, bin, binfloat");
|
||||
imageFormatName = arg;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-font", 1) {
|
||||
fontInput.fontFilename = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-charset", 1) {
|
||||
fontInput.charsetFilename = argv[++argPos];
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-glyphset", 1) {
|
||||
fontInput.charsetFilename = argv[++argPos];
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-fontscale", 1) {
|
||||
double fs;
|
||||
if (!(parseDouble(fs, argv[++argPos]) && fs > 0))
|
||||
ABORT("Invalid font scale argument. Use -fontscale <font scale> with a positive real number.");
|
||||
fontInput.fontScale = fs;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-fontname", 1) {
|
||||
fontInput.fontName = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-and", 0) {
|
||||
if (!fontInput.fontFilename && !fontInput.charsetFilename && fontInput.fontScale < 0)
|
||||
ABORT("No font, character set, or font scale specified before -and separator.");
|
||||
if (!fontInputs.empty() && !memcmp(&fontInputs.back(), &fontInput, sizeof(FontInput)))
|
||||
ABORT("No changes between subsequent inputs. A different font, character set, or font scale must be set inbetween -and separators.");
|
||||
fontInputs.push_back(fontInput);
|
||||
fontInput.fontName = nullptr;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-arfont", 1) {
|
||||
config.arteryFontFilename = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-imageout", 1) {
|
||||
config.imageFilename = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-json", 1) {
|
||||
config.jsonFilename = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-csv", 1) {
|
||||
config.csvFilename = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-shadronpreview", 2) {
|
||||
config.shadronPreviewFilename = argv[++argPos];
|
||||
config.shadronPreviewText = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-dimensions", 2) {
|
||||
unsigned w, h;
|
||||
if (!(parseUnsigned(w, argv[argPos+1]) && parseUnsigned(h, argv[argPos+2]) && w && h))
|
||||
ABORT("Invalid atlas dimensions. Use -dimensions <width> <height> with two positive integers.");
|
||||
fixedWidth = w, fixedHeight = h;
|
||||
argPos += 3;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-pots", 0) {
|
||||
atlasSizeConstraint = TightAtlasPacker::DimensionsConstraint::POWER_OF_TWO_SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-potr", 0) {
|
||||
atlasSizeConstraint = TightAtlasPacker::DimensionsConstraint::POWER_OF_TWO_RECTANGLE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-square", 0) {
|
||||
atlasSizeConstraint = TightAtlasPacker::DimensionsConstraint::SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-square2", 0) {
|
||||
atlasSizeConstraint = TightAtlasPacker::DimensionsConstraint::EVEN_SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-square4", 0) {
|
||||
atlasSizeConstraint = TightAtlasPacker::DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-yorigin", 1) {
|
||||
arg = argv[++argPos];
|
||||
if (!strcmp(arg, "bottom"))
|
||||
config.yDirection = YDirection::BOTTOM_UP;
|
||||
else if (!strcmp(arg, "top"))
|
||||
config.yDirection = YDirection::TOP_DOWN;
|
||||
else
|
||||
ABORT("Invalid Y-axis origin. Use bottom or top.");
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-size", 1) {
|
||||
double s;
|
||||
if (!(parseDouble(s, argv[++argPos]) && s > 0))
|
||||
ABORT("Invalid EM size argument. Use -size <EM size> with a positive real number.");
|
||||
config.emSize = s;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-minsize", 1) {
|
||||
double s;
|
||||
if (!(parseDouble(s, argv[++argPos]) && s > 0))
|
||||
ABORT("Invalid minimum EM size argument. Use -minsize <EM size> with a positive real number.");
|
||||
minEmSize = s;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-emrange", 1) {
|
||||
double r;
|
||||
if (!(parseDouble(r, argv[++argPos]) && r >= 0))
|
||||
ABORT("Invalid range argument. Use -emrange <EM range> with a positive real number.");
|
||||
rangeMode = RANGE_EM;
|
||||
rangeValue = r;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-pxrange", 1) {
|
||||
double r;
|
||||
if (!(parseDouble(r, argv[++argPos]) && r >= 0))
|
||||
ABORT("Invalid range argument. Use -pxrange <pixel range> with a positive real number.");
|
||||
rangeMode = RANGE_PIXEL;
|
||||
rangeValue = r;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-angle", 1) {
|
||||
double at;
|
||||
if (!parseAngle(at, argv[argPos+1]))
|
||||
ABORT("Invalid angle threshold. Use -angle <min angle> with a positive real number less than PI or a value in degrees followed by 'd' below 180d.");
|
||||
config.angleThreshold = at;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-errorcorrection", 1) {
|
||||
msdfgen::ErrorCorrectionConfig &ec = config.generatorAttributes.config.errorCorrection;
|
||||
if (!strcmp(argv[argPos+1], "disabled") || !strcmp(argv[argPos+1], "0") || !strcmp(argv[argPos+1], "none")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::DISABLED;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "default") || !strcmp(argv[argPos+1], "auto") || !strcmp(argv[argPos+1], "auto-mixed") || !strcmp(argv[argPos+1], "mixed")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::CHECK_DISTANCE_AT_EDGE;
|
||||
} else if (!strcmp(argv[argPos+1], "auto-fast") || !strcmp(argv[argPos+1], "fast")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "auto-full") || !strcmp(argv[argPos+1], "full")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "distance") || !strcmp(argv[argPos+1], "distance-fast") || !strcmp(argv[argPos+1], "indiscriminate") || !strcmp(argv[argPos+1], "indiscriminate-fast")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::INDISCRIMINATE;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "distance-full") || !strcmp(argv[argPos+1], "indiscriminate-full")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::INDISCRIMINATE;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "edge-fast")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_ONLY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "edge") || !strcmp(argv[argPos+1], "edge-full")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_ONLY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "help")) {
|
||||
puts(errorCorrectionHelpText);
|
||||
return 0;
|
||||
} else
|
||||
ABORT("Unknown error correction mode. Use -errorcorrection help for more information.");
|
||||
explicitErrorCorrectionMode = true;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-errordeviationratio", 1) {
|
||||
double edr;
|
||||
if (!(parseDouble(edr, argv[argPos+1]) && edr > 0))
|
||||
ABORT("Invalid error deviation ratio. Use -errordeviationratio <ratio> with a positive real number.");
|
||||
config.generatorAttributes.config.errorCorrection.minDeviationRatio = edr;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-errorimproveratio", 1) {
|
||||
double eir;
|
||||
if (!(parseDouble(eir, argv[argPos+1]) && eir > 0))
|
||||
ABORT("Invalid error improvement ratio. Use -errorimproveratio <ratio> with a positive real number.");
|
||||
config.generatorAttributes.config.errorCorrection.minImproveRatio = eir;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-coloringstrategy", 1) {
|
||||
if (!strcmp(argv[argPos+1], "simple")) config.edgeColoring = msdfgen::edgeColoringSimple, config.expensiveColoring = false;
|
||||
else if (!strcmp(argv[argPos+1], "inktrap")) config.edgeColoring = msdfgen::edgeColoringInkTrap, config.expensiveColoring = false;
|
||||
else if (!strcmp(argv[argPos+1], "distance")) config.edgeColoring = msdfgen::edgeColoringByDistance, config.expensiveColoring = true;
|
||||
else
|
||||
puts("Unknown coloring strategy specified.");
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-miterlimit", 1) {
|
||||
double m;
|
||||
if (!(parseDouble(m, argv[++argPos]) && m >= 0))
|
||||
ABORT("Invalid miter limit argument. Use -miterlimit <limit> with a positive real number.");
|
||||
config.miterLimit = m;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nokerning", 0) {
|
||||
config.kerning = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-kerning", 0) {
|
||||
config.kerning = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nopreprocess", 0) {
|
||||
config.preprocessGeometry = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-preprocess", 0) {
|
||||
config.preprocessGeometry = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nooverlap", 0) {
|
||||
config.generatorAttributes.config.overlapSupport = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-overlap", 0) {
|
||||
config.generatorAttributes.config.overlapSupport = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-noscanline", 0) {
|
||||
config.generatorAttributes.scanlinePass = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-scanline", 0) {
|
||||
config.generatorAttributes.scanlinePass = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-seed", 1) {
|
||||
if (!parseUnsignedLL(config.coloringSeed, argv[argPos+1]))
|
||||
ABORT("Invalid seed. Use -seed <N> with N being a non-negative integer.");
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-threads", 1) {
|
||||
unsigned tc;
|
||||
if (!parseUnsigned(tc, argv[argPos+1]) || (int) tc < 0)
|
||||
ABORT("Invalid thread count. Use -threads <N> with N being a non-negative integer.");
|
||||
config.threadCount = (int) tc;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-help", 0) {
|
||||
puts(helpText);
|
||||
return 0;
|
||||
}
|
||||
printf("Unknown setting or insufficient parameters: %s\n", arg);
|
||||
suggestHelp = true;
|
||||
++argPos;
|
||||
}
|
||||
if (suggestHelp)
|
||||
printf("Use -help for more information.\n");
|
||||
|
||||
// Nothing to do?
|
||||
if (argc == 1) {
|
||||
printf(
|
||||
"Usage: msdf-atlas-gen"
|
||||
#ifdef _WIN32
|
||||
".exe"
|
||||
#endif
|
||||
" -font <filename.ttf/otf> -charset <charset> <output specification> <options>\n"
|
||||
"Use -help for more information.\n"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
if (!fontInput.fontFilename)
|
||||
ABORT("No font specified.");
|
||||
if (!(config.arteryFontFilename || config.imageFilename || config.jsonFilename || config.csvFilename || config.shadronPreviewFilename)) {
|
||||
puts("No output specified.");
|
||||
return 0;
|
||||
}
|
||||
bool layoutOnly = !(config.arteryFontFilename || config.imageFilename);
|
||||
|
||||
// Finalize font inputs
|
||||
const FontInput *nextFontInput = &fontInput;
|
||||
for (std::vector<FontInput>::reverse_iterator it = fontInputs.rbegin(); it != fontInputs.rend(); ++it) {
|
||||
if (!it->fontFilename && nextFontInput->fontFilename)
|
||||
it->fontFilename = nextFontInput->fontFilename;
|
||||
if (!it->charsetFilename && nextFontInput->charsetFilename) {
|
||||
it->charsetFilename = nextFontInput->charsetFilename;
|
||||
it->glyphIdentifierType = nextFontInput->glyphIdentifierType;
|
||||
}
|
||||
if (it->fontScale < 0 && nextFontInput->fontScale >= 0)
|
||||
it->fontScale = nextFontInput->fontScale;
|
||||
nextFontInput = &*it;
|
||||
}
|
||||
if (fontInputs.empty() || memcmp(&fontInputs.back(), &fontInput, sizeof(FontInput)))
|
||||
fontInputs.push_back(fontInput);
|
||||
|
||||
// Fix up configuration based on related values
|
||||
if (!(config.imageType == ImageType::PSDF || config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF))
|
||||
config.miterLimit = 0;
|
||||
if (config.emSize > minEmSize)
|
||||
minEmSize = config.emSize;
|
||||
if (!(fixedWidth > 0 && fixedHeight > 0) && !(minEmSize > 0)) {
|
||||
puts("Neither atlas size nor glyph size selected, using default...");
|
||||
minEmSize = MSDF_ATLAS_DEFAULT_EM_SIZE;
|
||||
}
|
||||
if (!(config.imageType == ImageType::SDF || config.imageType == ImageType::PSDF || config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF)) {
|
||||
rangeMode = RANGE_PIXEL;
|
||||
rangeValue = (double) (config.imageType == ImageType::SOFT_MASK);
|
||||
} else if (rangeValue <= 0) {
|
||||
rangeMode = RANGE_PIXEL;
|
||||
rangeValue = DEFAULT_PIXEL_RANGE;
|
||||
}
|
||||
if (config.kerning && !(config.arteryFontFilename || config.jsonFilename || config.shadronPreviewFilename))
|
||||
config.kerning = false;
|
||||
if (config.threadCount <= 0)
|
||||
config.threadCount = std::max((int) std::thread::hardware_concurrency(), 1);
|
||||
if (config.generatorAttributes.scanlinePass) {
|
||||
if (explicitErrorCorrectionMode && config.generatorAttributes.config.errorCorrection.distanceCheckMode != msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE) {
|
||||
const char *fallbackModeName = "unknown";
|
||||
switch (config.generatorAttributes.config.errorCorrection.mode) {
|
||||
case msdfgen::ErrorCorrectionConfig::DISABLED: fallbackModeName = "disabled"; break;
|
||||
case msdfgen::ErrorCorrectionConfig::INDISCRIMINATE: fallbackModeName = "distance-fast"; break;
|
||||
case msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY: fallbackModeName = "auto-fast"; break;
|
||||
case msdfgen::ErrorCorrectionConfig::EDGE_ONLY: fallbackModeName = "edge-fast"; break;
|
||||
}
|
||||
printf("Selected error correction mode not compatible with scanline mode, falling back to %s.\n", fallbackModeName);
|
||||
}
|
||||
config.generatorAttributes.config.errorCorrection.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
}
|
||||
|
||||
// Finalize image format
|
||||
ImageFormat imageExtension = ImageFormat::UNSPECIFIED;
|
||||
if (config.imageFilename) {
|
||||
if (cmpExtension(config.imageFilename, ".png")) imageExtension = ImageFormat::PNG;
|
||||
else if (cmpExtension(config.imageFilename, ".bmp")) imageExtension = ImageFormat::BMP;
|
||||
else if (cmpExtension(config.imageFilename, ".tif") || cmpExtension(config.imageFilename, ".tiff")) imageExtension = ImageFormat::TIFF;
|
||||
else if (cmpExtension(config.imageFilename, ".txt")) imageExtension = ImageFormat::TEXT;
|
||||
else if (cmpExtension(config.imageFilename, ".bin")) imageExtension = ImageFormat::BINARY;
|
||||
}
|
||||
if (config.imageFormat == ImageFormat::UNSPECIFIED) {
|
||||
config.imageFormat = ImageFormat::PNG;
|
||||
imageFormatName = "png";
|
||||
// If image format is not specified and -imageout is the only image output, infer format from its extension
|
||||
if (imageExtension != ImageFormat::UNSPECIFIED && !config.arteryFontFilename)
|
||||
config.imageFormat = imageExtension;
|
||||
}
|
||||
if (config.imageType == ImageType::MTSDF && config.imageFormat == ImageFormat::BMP)
|
||||
ABORT("Atlas type not compatible with image format. MTSDF requires a format with alpha channel.");
|
||||
if (config.arteryFontFilename && !(config.imageFormat == ImageFormat::PNG || config.imageFormat == ImageFormat::BINARY || config.imageFormat == ImageFormat::BINARY_FLOAT)) {
|
||||
config.arteryFontFilename = nullptr;
|
||||
result = 1;
|
||||
puts("Error: Unable to create an Artery Font file with the specified image format!");
|
||||
// Recheck whether there is anything else to do
|
||||
if (!(config.arteryFontFilename || config.imageFilename || config.jsonFilename || config.csvFilename || config.shadronPreviewFilename))
|
||||
return result;
|
||||
layoutOnly = !(config.arteryFontFilename || config.imageFilename);
|
||||
}
|
||||
if (imageExtension != ImageFormat::UNSPECIFIED) {
|
||||
// Warn if image format mismatches -imageout extension
|
||||
bool mismatch = false;
|
||||
switch (config.imageFormat) {
|
||||
case ImageFormat::TEXT: case ImageFormat::TEXT_FLOAT:
|
||||
mismatch = imageExtension != ImageFormat::TEXT;
|
||||
break;
|
||||
case ImageFormat::BINARY: case ImageFormat::BINARY_FLOAT: case ImageFormat::BINARY_FLOAT_BE:
|
||||
mismatch = imageExtension != ImageFormat::BINARY;
|
||||
break;
|
||||
default:
|
||||
mismatch = imageExtension != config.imageFormat;
|
||||
}
|
||||
if (mismatch)
|
||||
printf("Warning: Output image file extension does not match the image's actual format (%s)!\n", imageFormatName);
|
||||
}
|
||||
imageFormatName = nullptr; // No longer consistent with imageFormat
|
||||
bool floatingPointFormat = (
|
||||
config.imageFormat == ImageFormat::TIFF ||
|
||||
config.imageFormat == ImageFormat::TEXT_FLOAT ||
|
||||
config.imageFormat == ImageFormat::BINARY_FLOAT ||
|
||||
config.imageFormat == ImageFormat::BINARY_FLOAT_BE
|
||||
);
|
||||
|
||||
// Load fonts
|
||||
std::vector<GlyphGeometry> glyphs;
|
||||
std::vector<FontGeometry> fonts;
|
||||
bool anyCodepointsAvailable = false;
|
||||
{
|
||||
class FontHolder {
|
||||
msdfgen::FreetypeHandle *ft;
|
||||
msdfgen::FontHandle *font;
|
||||
const char *fontFilename;
|
||||
public:
|
||||
FontHolder() : ft(msdfgen::initializeFreetype()), font(nullptr), fontFilename(nullptr) { }
|
||||
~FontHolder() {
|
||||
if (ft) {
|
||||
if (font)
|
||||
msdfgen::destroyFont(font);
|
||||
msdfgen::deinitializeFreetype(ft);
|
||||
}
|
||||
}
|
||||
bool load(const char *fontFilename) {
|
||||
if (ft && fontFilename) {
|
||||
if (this->fontFilename && !strcmp(this->fontFilename, fontFilename))
|
||||
return true;
|
||||
if (font)
|
||||
msdfgen::destroyFont(font);
|
||||
if ((font = msdfgen::loadFont(ft, fontFilename))) {
|
||||
this->fontFilename = fontFilename;
|
||||
return true;
|
||||
}
|
||||
this->fontFilename = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
operator msdfgen::FontHandle *() const {
|
||||
return font;
|
||||
}
|
||||
} font;
|
||||
|
||||
for (FontInput &fontInput : fontInputs) {
|
||||
if (!font.load(fontInput.fontFilename))
|
||||
ABORT("Failed to load specified font file.");
|
||||
if (fontInput.fontScale <= 0)
|
||||
fontInput.fontScale = 1;
|
||||
|
||||
// Load character set
|
||||
Charset charset;
|
||||
if (fontInput.charsetFilename) {
|
||||
if (!charset.load(fontInput.charsetFilename, fontInput.glyphIdentifierType != GlyphIdentifierType::UNICODE_CODEPOINT))
|
||||
ABORT(fontInput.glyphIdentifierType == GlyphIdentifierType::GLYPH_INDEX ? "Failed to load glyph set specification." : "Failed to load character set specification.");
|
||||
} else {
|
||||
charset = Charset::ASCII;
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
}
|
||||
|
||||
// Load glyphs
|
||||
FontGeometry fontGeometry(&glyphs);
|
||||
int glyphsLoaded = -1;
|
||||
switch (fontInput.glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
glyphsLoaded = fontGeometry.loadGlyphset(font, fontInput.fontScale, charset, config.preprocessGeometry, config.kerning);
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
glyphsLoaded = fontGeometry.loadCharset(font, fontInput.fontScale, charset, config.preprocessGeometry, config.kerning);
|
||||
anyCodepointsAvailable |= glyphsLoaded > 0;
|
||||
break;
|
||||
}
|
||||
if (glyphsLoaded < 0)
|
||||
ABORT("Failed to load glyphs from font.");
|
||||
printf("Loaded geometry of %d out of %d glyphs", glyphsLoaded, (int) charset.size());
|
||||
if (fontInputs.size() > 1)
|
||||
printf(" from font \"%s\"", fontInput.fontFilename);
|
||||
printf(".\n");
|
||||
// List missing glyphs
|
||||
if (glyphsLoaded < (int) charset.size()) {
|
||||
printf("Missing %d %s", (int) charset.size()-glyphsLoaded, fontInput.glyphIdentifierType == GlyphIdentifierType::UNICODE_CODEPOINT ? "codepoints" : "glyphs");
|
||||
bool first = true;
|
||||
switch (fontInput.glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
for (unicode_t cp : charset)
|
||||
if (!fontGeometry.getGlyph(msdfgen::GlyphIndex(cp)))
|
||||
printf("%c 0x%02X", first ? ((first = false), ':') : ',', cp);
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
for (unicode_t cp : charset)
|
||||
if (!fontGeometry.getGlyph(cp))
|
||||
printf("%c 0x%02X", first ? ((first = false), ':') : ',', cp);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (fontInput.fontName)
|
||||
fontGeometry.setName(fontInput.fontName);
|
||||
|
||||
fonts.push_back((FontGeometry &&) fontGeometry);
|
||||
}
|
||||
}
|
||||
if (glyphs.empty())
|
||||
ABORT("No glyphs loaded.");
|
||||
|
||||
// Determine final atlas dimensions, scale and range, pack glyphs
|
||||
{
|
||||
double unitRange = 0, pxRange = 0;
|
||||
switch (rangeMode) {
|
||||
case RANGE_EM:
|
||||
unitRange = rangeValue;
|
||||
break;
|
||||
case RANGE_PIXEL:
|
||||
pxRange = rangeValue;
|
||||
break;
|
||||
}
|
||||
bool fixedDimensions = fixedWidth >= 0 && fixedHeight >= 0;
|
||||
bool fixedScale = config.emSize > 0;
|
||||
TightAtlasPacker atlasPacker;
|
||||
if (fixedDimensions)
|
||||
atlasPacker.setDimensions(fixedWidth, fixedHeight);
|
||||
else
|
||||
atlasPacker.setDimensionsConstraint(atlasSizeConstraint);
|
||||
atlasPacker.setPadding(config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF ? 0 : -1);
|
||||
// TODO: In this case (if padding is -1), the border pixels of each glyph are black, but still computed. For floating-point output, this may play a role.
|
||||
if (fixedScale)
|
||||
atlasPacker.setScale(config.emSize);
|
||||
else
|
||||
atlasPacker.setMinimumScale(minEmSize);
|
||||
atlasPacker.setPixelRange(pxRange);
|
||||
atlasPacker.setUnitRange(unitRange);
|
||||
atlasPacker.setMiterLimit(config.miterLimit);
|
||||
if (int remaining = atlasPacker.pack(glyphs.data(), glyphs.size())) {
|
||||
if (remaining < 0) {
|
||||
ABORT("Failed to pack glyphs into atlas.");
|
||||
} else {
|
||||
printf("Error: Could not fit %d out of %d glyphs into the atlas.\n", remaining, (int) glyphs.size());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
atlasPacker.getDimensions(config.width, config.height);
|
||||
if (!(config.width > 0 && config.height > 0))
|
||||
ABORT("Unable to determine atlas size.");
|
||||
config.emSize = atlasPacker.getScale();
|
||||
config.pxRange = atlasPacker.getPixelRange();
|
||||
if (!fixedScale)
|
||||
printf("Glyph size: %.9g pixels/EM\n", config.emSize);
|
||||
if (!fixedDimensions)
|
||||
printf("Atlas dimensions: %d x %d\n", config.width, config.height);
|
||||
}
|
||||
|
||||
// Generate atlas bitmap
|
||||
if (!layoutOnly) {
|
||||
|
||||
// Edge coloring
|
||||
if (config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF) {
|
||||
if (config.expensiveColoring) {
|
||||
Workload([&glyphs, &config](int i, int threadNo) -> bool {
|
||||
unsigned long long glyphSeed = (LCG_MULTIPLIER*(config.coloringSeed^i)+LCG_INCREMENT)*!!config.coloringSeed;
|
||||
glyphs[i].edgeColoring(config.edgeColoring, config.angleThreshold, glyphSeed);
|
||||
return true;
|
||||
}, glyphs.size()).finish(config.threadCount);
|
||||
} else {
|
||||
unsigned long long glyphSeed = config.coloringSeed;
|
||||
for (GlyphGeometry &glyph : glyphs) {
|
||||
glyphSeed *= LCG_MULTIPLIER;
|
||||
glyph.edgeColoring(config.edgeColoring, config.angleThreshold, glyphSeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
switch (config.imageType) {
|
||||
case ImageType::HARD_MASK:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 1, scanlineGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 1, scanlineGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::SOFT_MASK:
|
||||
case ImageType::SDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 1, sdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 1, sdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::PSDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 1, psdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 1, psdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::MSDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 3, msdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 3, msdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::MTSDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 4, mtsdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 4, mtsdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
}
|
||||
if (!success)
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (config.csvFilename) {
|
||||
if (exportCSV(fonts.data(), fonts.size(), config.width, config.height, config.yDirection, config.csvFilename))
|
||||
puts("Glyph layout written into CSV file.");
|
||||
else {
|
||||
result = 1;
|
||||
puts("Failed to write CSV output file.");
|
||||
}
|
||||
}
|
||||
if (config.jsonFilename) {
|
||||
if (exportJSON(fonts.data(), fonts.size(), config.emSize, config.pxRange, config.width, config.height, config.imageType, config.yDirection, config.jsonFilename, config.kerning))
|
||||
puts("Glyph layout and metadata written into JSON file.");
|
||||
else {
|
||||
result = 1;
|
||||
puts("Failed to write JSON output file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.shadronPreviewFilename && config.shadronPreviewText) {
|
||||
if (anyCodepointsAvailable) {
|
||||
std::vector<unicode_t> previewText;
|
||||
utf8Decode(previewText, config.shadronPreviewText);
|
||||
previewText.push_back(0);
|
||||
if (generateShadronPreview(fonts.data(), fonts.size(), config.imageType, config.width, config.height, config.pxRange, previewText.data(), config.imageFilename, floatingPointFormat, config.shadronPreviewFilename))
|
||||
puts("Shadron preview script generated.");
|
||||
else {
|
||||
result = 1;
|
||||
puts("Failed to generate Shadron preview file.");
|
||||
}
|
||||
} else {
|
||||
result = 1;
|
||||
puts("Shadron preview not supported in -glyphset mode.");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
42
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.h
Normal file
42
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.h
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD ATLAS GENERATOR v1.2 (2021-05-29)
|
||||
* ---------------------------------------------------------------------
|
||||
* A utility by Viktor Chlumsky, (c) 2020 - 2021
|
||||
*
|
||||
* Generates compact bitmap font atlases using MSDFGEN.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "utf8.h"
|
||||
#include "Rectangle.h"
|
||||
#include "Charset.h"
|
||||
#include "GlyphBox.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "FontGeometry.h"
|
||||
#include "RectanglePacker.h"
|
||||
#include "rectangle-packing.h"
|
||||
#include "Workload.h"
|
||||
#include "size-selectors.h"
|
||||
#include "bitmap-blit.h"
|
||||
#include "AtlasStorage.h"
|
||||
#include "BitmapAtlasStorage.h"
|
||||
#include "TightAtlasPacker.h"
|
||||
#include "AtlasGenerator.h"
|
||||
#include "ImmediateAtlasGenerator.h"
|
||||
#include "DynamicAtlas.h"
|
||||
#include "glyph-generators.h"
|
||||
#include "image-encode.h"
|
||||
#include "image-save.h"
|
||||
#include "artery-font-export.h"
|
||||
#include "csv-export.h"
|
||||
#include "json-export.h"
|
||||
#include "shadron-preview-generator.h"
|
||||
|
||||
#define MSDF_ATLAS_VERSION "1.2"
|
||||
BIN
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.rc
Normal file
BIN
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.rc
Normal file
Binary file not shown.
61
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.sln
Normal file
61
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.sln
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Msdfgen", "msdfgen\Msdfgen.vcxproj", "{84BE2D91-F071-4151-BE12-61460464C494}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msdf-atlas-gen", "msdf-atlas-gen.vcxproj", "{223EDB94-5B35-45F2-A584-273DE6E45F6F}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{84BE2D91-F071-4151-BE12-61460464C494} = {84BE2D91-F071-4151-BE12-61460464C494}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug Library|x64 = Debug Library|x64
|
||||
Debug Library|x86 = Debug Library|x86
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release Library|x64 = Release Library|x64
|
||||
Release Library|x86 = Release Library|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug Library|x64.ActiveCfg = Debug Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug Library|x64.Build.0 = Debug Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug Library|x86.ActiveCfg = Debug Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug Library|x86.Build.0 = Debug Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug|x64.Build.0 = Debug Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug|x86.ActiveCfg = Debug Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Debug|x86.Build.0 = Debug Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release Library|x64.ActiveCfg = Release Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release Library|x64.Build.0 = Release Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release Library|x86.ActiveCfg = Release Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release Library|x86.Build.0 = Release Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release|x64.ActiveCfg = Release Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release|x64.Build.0 = Release Library|x64
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release|x86.ActiveCfg = Release Library|Win32
|
||||
{84BE2D91-F071-4151-BE12-61460464C494}.Release|x86.Build.0 = Release Library|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug Library|x64.ActiveCfg = Debug Library|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug Library|x64.Build.0 = Debug Library|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug Library|x86.ActiveCfg = Debug Library|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug Library|x86.Build.0 = Debug Library|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug|x64.Build.0 = Debug|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Debug|x86.Build.0 = Debug|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release Library|x64.ActiveCfg = Release Library|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release Library|x64.Build.0 = Release Library|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release Library|x86.ActiveCfg = Release Library|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release Library|x86.Build.0 = Release Library|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release|x64.ActiveCfg = Release|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release|x64.Build.0 = Release|x64
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release|x86.ActiveCfg = Release|Win32
|
||||
{223EDB94-5B35-45F2-A584-273DE6E45F6F}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
374
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.vcxproj
Normal file
374
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.vcxproj
Normal file
@@ -0,0 +1,374 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug Library|Win32">
|
||||
<Configuration>Debug Library</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug Library|x64">
|
||||
<Configuration>Debug Library</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release Library|Win32">
|
||||
<Configuration>Release Library</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release Library|x64">
|
||||
<Configuration>Release Library</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{223EDB94-5B35-45F2-A584-273DE6E45F6F}</ProjectGuid>
|
||||
<RootNamespace>msdfatlasgen</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|Win32'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
|
||||
<TargetName>msdf-atlas-gen</TargetName>
|
||||
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDF_ATLAS_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;skia.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\$(Configuration);msdfgen\$(Configuration) Library;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\msdfgen\freetype\win32;$(SolutionDir)$(Configuration) Library;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\debug;msdfgen\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDF_ATLAS_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;skia.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\$(Configuration);msdfgen\$(Platform)\$(Configuration) Library;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\msdfgen\freetype\win64;$(SolutionDir)$(Platform)\$(Configuration) Library;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\debug;msdfgen\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDF_ATLAS_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;skia.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\$(Configuration);msdfgen\bin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\msdfgen\freetype\win32;$(SolutionDir)bin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\release;msdfgen\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDF_ATLAS_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;skia.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\$(Configuration);msdfgen\$(Platform)\$(Configuration) Library;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>msdfgen\include;msdfgen\freetype\include;msdfgen;artery-font-format;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>freetype.lib;msdfgen.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\msdfgen\freetype\win64;$(SolutionDir)$(Platform)\$(Configuration) Library;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>msdfgen\freetype\win$(PlatformArchitecture);msdfgen\skia\win$(PlatformArchitecture)\release;msdfgen\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="msdf-atlas-gen\artery-font-export.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\bitmap-blit.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\charset-parser.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\Charset.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\csv-export.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\FontGeometry.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\glyph-generators.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\GlyphGeometry.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\image-encode.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\json-export.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\main.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\RectanglePacker.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\shadron-preview-generator.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\size-selectors.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\TightAtlasPacker.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\utf8.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\Workload.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\artery-font-export.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\AtlasGenerator.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\AtlasStorage.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\bitmap-blit.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\BitmapAtlasStorage.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\BitmapAtlasStorage.hpp" />
|
||||
<ClInclude Include="msdf-atlas-gen\csv-export.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\DynamicAtlas.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\DynamicAtlas.hpp" />
|
||||
<ClInclude Include="msdf-atlas-gen\FontGeometry.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\glyph-generators.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\image-encode.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\Charset.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\GlyphGeometry.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\image-save.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\image-save.hpp" />
|
||||
<ClInclude Include="msdf-atlas-gen\ImmediateAtlasGenerator.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\ImmediateAtlasGenerator.hpp" />
|
||||
<ClInclude Include="msdf-atlas-gen\json-export.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\msdf-atlas-gen.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\rectangle-packing.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\rectangle-packing.hpp" />
|
||||
<ClInclude Include="msdf-atlas-gen\Rectangle.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\RectanglePacker.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\Remap.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\shadron-preview-generator.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\size-selectors.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\GlyphBox.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\types.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\utf8.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\Workload.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\TightAtlasPacker.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="msdf-atlas-gen.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="icon.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
184
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.vcxproj.filters
Normal file
184
Nuake/src/Vendors/msdf-atlas-gen/msdf-atlas-gen.vcxproj.filters
Normal file
@@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Template Source Files">
|
||||
<UniqueIdentifier>{ee785f45-c1cf-48ae-b864-f27237b077c1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="msdf-atlas-gen\artery-font-export.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\bitmap-blit.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\csv-export.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\glyph-generators.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\GlyphGeometry.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\Charset.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\charset-parser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\image-encode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\json-export.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\RectanglePacker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\shadron-preview-generator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\size-selectors.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\TightAtlasPacker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\utf8.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\Workload.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\FontGeometry.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\artery-font-export.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\AtlasGenerator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\AtlasStorage.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\BitmapAtlasStorage.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\BitmapAtlasStorage.hpp">
|
||||
<Filter>Template Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\bitmap-blit.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\csv-export.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\DynamicAtlas.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\DynamicAtlas.hpp">
|
||||
<Filter>Template Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\GlyphBox.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\glyph-generators.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\GlyphGeometry.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\Charset.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\image-encode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\image-save.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\image-save.hpp">
|
||||
<Filter>Template Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\ImmediateAtlasGenerator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\ImmediateAtlasGenerator.hpp">
|
||||
<Filter>Template Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\json-export.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\msdf-atlas-gen.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\Rectangle.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\RectanglePacker.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\rectangle-packing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\rectangle-packing.hpp">
|
||||
<Filter>Template Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\Remap.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\shadron-preview-generator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\size-selectors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\TightAtlasPacker.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\utf8.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\Workload.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\FontGeometry.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="msdf-atlas-gen.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="icon.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
19
Nuake/src/Vendors/msdf-atlas-gen/rectangle-packing.h
Normal file
19
Nuake/src/Vendors/msdf-atlas-gen/rectangle-packing.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "Rectangle.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Packs the rectangle array into an atlas with fixed dimensions, returns how many didn't fit (0 on success)
|
||||
template <typename RectangleType>
|
||||
int packRectangles(RectangleType *rectangles, int count, int width, int height, int padding = 0);
|
||||
|
||||
/// Packs the rectangle array into an atlas of unknown size, returns the minimum required dimensions constrained by SizeSelector
|
||||
template <class SizeSelector, typename RectangleType>
|
||||
std::pair<int, int> packRectangles(RectangleType *rectangles, int count, int padding = 0);
|
||||
|
||||
}
|
||||
|
||||
#include "rectangle-packing.hpp"
|
||||
61
Nuake/src/Vendors/msdf-atlas-gen/rectangle-packing.hpp
Normal file
61
Nuake/src/Vendors/msdf-atlas-gen/rectangle-packing.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
#include "rectangle-packing.h"
|
||||
|
||||
#include <vector>
|
||||
#include "RectanglePacker.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static void copyRectanglePlacement(Rectangle &dst, const Rectangle &src) {
|
||||
dst.x = src.x;
|
||||
dst.y = src.y;
|
||||
}
|
||||
|
||||
static void copyRectanglePlacement(OrientedRectangle &dst, const OrientedRectangle &src) {
|
||||
dst.x = src.x;
|
||||
dst.y = src.y;
|
||||
dst.rotated = src.rotated;
|
||||
}
|
||||
|
||||
template <typename RectangleType>
|
||||
int packRectangles(RectangleType *rectangles, int count, int width, int height, int padding) {
|
||||
if (padding)
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rectangles[i].w += padding;
|
||||
rectangles[i].h += padding;
|
||||
}
|
||||
int result = RectanglePacker(width+padding, height+padding).pack(rectangles, count);
|
||||
if (padding)
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rectangles[i].w -= padding;
|
||||
rectangles[i].h -= padding;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class SizeSelector, typename RectangleType>
|
||||
std::pair<int, int> packRectangles(RectangleType *rectangles, int count, int padding) {
|
||||
std::vector<RectangleType> rectanglesCopy(count);
|
||||
int totalArea = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rectanglesCopy[i].w = rectangles[i].w+padding;
|
||||
rectanglesCopy[i].h = rectangles[i].h+padding;
|
||||
totalArea += rectangles[i].w*rectangles[i].h;
|
||||
}
|
||||
std::pair<int, int> dimensions;
|
||||
SizeSelector sizeSelector(totalArea);
|
||||
int width, height;
|
||||
while (sizeSelector(width, height)) {
|
||||
if (!RectanglePacker(width+padding, height+padding).pack(rectanglesCopy.data(), count)) {
|
||||
dimensions.first = width;
|
||||
dimensions.second = height;
|
||||
for (int i = 0; i < count; ++i)
|
||||
copyRectanglePlacement(rectangles[i], rectanglesCopy[i]);
|
||||
--sizeSelector;
|
||||
} else
|
||||
++sizeSelector;
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
}
|
||||
BIN
Nuake/src/Vendors/msdf-atlas-gen/resource.h
Normal file
BIN
Nuake/src/Vendors/msdf-atlas-gen/resource.h
Normal file
Binary file not shown.
155
Nuake/src/Vendors/msdf-atlas-gen/shadron-preview-generator.cpp
Normal file
155
Nuake/src/Vendors/msdf-atlas-gen/shadron-preview-generator.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
#include "shadron-preview-generator.h"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static const char * const shadronFillGlyphMask = R"(
|
||||
template <ATLAS, RANGE, COLOR>
|
||||
glsl vec4 fillGlyph(vec2 texCoord) {
|
||||
float fill = texture((ATLAS), texCoord).r;
|
||||
return vec4(vec3(COLOR), fill);
|
||||
}
|
||||
)";
|
||||
|
||||
static const char * const shadronFillGlyphSdf = R"(
|
||||
template <ATLAS, RANGE, COLOR>
|
||||
glsl vec4 fillGlyph(vec2 texCoord) {
|
||||
vec3 s = texture((ATLAS), texCoord).rgb;
|
||||
float sd = dot(vec2(RANGE), 0.5/fwidth(texCoord))*(median(s.r, s.g, s.b)-0.5);
|
||||
float fill = clamp(sd+0.5, 0.0, 1.0);
|
||||
return vec4(vec3(COLOR), fill);
|
||||
}
|
||||
)";
|
||||
|
||||
static const char * const shadronPreviewPreamble = R"(
|
||||
#include <median>
|
||||
|
||||
glsl struct GlyphVertex {
|
||||
vec2 coord;
|
||||
vec2 texCoord;
|
||||
};
|
||||
|
||||
template <TEXT_SIZE>
|
||||
glsl vec4 projectVertex(out vec2 texCoord, in GlyphVertex vertex) {
|
||||
vec2 coord = vertex.coord;
|
||||
float scale = 2.0/max((TEXT_SIZE).x, shadron_Aspect*(TEXT_SIZE).y);
|
||||
scale *= exp(0.0625*shadron_Mouse.z);
|
||||
coord += vec2(-0.5, 0.5)*vec2(TEXT_SIZE);
|
||||
coord *= scale*vec2(1.0, shadron_Aspect);
|
||||
texCoord = vertex.texCoord;
|
||||
return vec4(coord, 0.0, 1.0);
|
||||
}
|
||||
%s
|
||||
#define PREVIEW_IMAGE(NAME, ATLAS, RANGE, COLOR, VERTEX_LIST, TEXT_SIZE, DIMENSIONS) model image NAME : \
|
||||
vertex_data(GlyphVertex), \
|
||||
fragment_data(vec2), \
|
||||
vertex(projectVertex<TEXT_SIZE>, triangles, VERTEX_LIST), \
|
||||
fragment(fillGlyph<ATLAS, RANGE, COLOR>), \
|
||||
depth(false), \
|
||||
blend(transparency), \
|
||||
background(vec4(vec3(COLOR), 0.0)), \
|
||||
dimensions(DIMENSIONS), \
|
||||
resizable(true)
|
||||
|
||||
)";
|
||||
|
||||
static std::string relativizePath(const char *base, const char *target) {
|
||||
if (target[0] == '/' || (target[0] && target[1] == ':')) // absolute path?
|
||||
return target;
|
||||
int commonPrefix = 0;
|
||||
for (int i = 0; base[i] && target[i] && base[i] == target[i]; ++i) {
|
||||
if (base[i] == '/' || base[i] == '\\')
|
||||
commonPrefix = i+1;
|
||||
}
|
||||
base += commonPrefix;
|
||||
target += commonPrefix;
|
||||
int baseNesting = 0;
|
||||
for (int i = 0; base[i]; ++i)
|
||||
if (base[i] == '/' || base[i] == '\\')
|
||||
++baseNesting;
|
||||
std::string output;
|
||||
for (int i = 0; i < baseNesting; ++i)
|
||||
output += "../";
|
||||
output += target;
|
||||
return output;
|
||||
}
|
||||
|
||||
bool generateShadronPreview(const FontGeometry *fonts, int fontCount, ImageType atlasType, int atlasWidth, int atlasHeight, double pxRange, const unicode_t *text, const char *imageFilename, bool fullRange, const char *outputFilename) {
|
||||
if (fontCount <= 0)
|
||||
return false;
|
||||
double texelWidth = 1./atlasWidth;
|
||||
double texelHeight = 1./atlasHeight;
|
||||
bool anyGlyphs = false;
|
||||
FILE *file = fopen(outputFilename, "w");
|
||||
if (!file)
|
||||
return false;
|
||||
fprintf(file, shadronPreviewPreamble, atlasType == ImageType::HARD_MASK || atlasType == ImageType::SOFT_MASK ? shadronFillGlyphMask : shadronFillGlyphSdf);
|
||||
if (imageFilename)
|
||||
fprintf(file, "image Atlas = file(\"%s\")", relativizePath(outputFilename, imageFilename).c_str());
|
||||
else
|
||||
fprintf(file, "image Atlas = file()");
|
||||
fprintf(file, " : %sfilter(%s), map(repeat);\n", fullRange ? "full_range(true), " : "", atlasType == ImageType::HARD_MASK ? "nearest" : "linear");
|
||||
fprintf(file, "const vec2 txRange = vec2(%.9g, %.9g);\n\n", pxRange*texelWidth, pxRange*texelHeight);
|
||||
{
|
||||
msdfgen::FontMetrics fontMetrics = fonts->getMetrics();
|
||||
for (int i = 1; i < fontCount; ++i) {
|
||||
fontMetrics.lineHeight = std::max(fontMetrics.lineHeight, fonts[i].getMetrics().lineHeight);
|
||||
fontMetrics.ascenderY = std::max(fontMetrics.ascenderY, fonts[i].getMetrics().ascenderY);
|
||||
fontMetrics.descenderY = std::min(fontMetrics.descenderY, fonts[i].getMetrics().descenderY);
|
||||
}
|
||||
double fsScale = 1/(fontMetrics.ascenderY-fontMetrics.descenderY);
|
||||
fputs("vertex_list GlyphVertex textQuadVertices = {\n", file);
|
||||
double x = 0, y = -fsScale*fontMetrics.ascenderY;
|
||||
double textWidth = 0;
|
||||
for (const unicode_t *cp = text; *cp; ++cp) {
|
||||
if (*cp == '\r')
|
||||
continue;
|
||||
if (*cp == '\n') {
|
||||
textWidth = std::max(textWidth, x);
|
||||
x = 0;
|
||||
y -= fsScale*fontMetrics.lineHeight;
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
const GlyphGeometry *glyph = fonts[i].getGlyph(*cp);
|
||||
if (glyph) {
|
||||
if (!glyph->isWhitespace()) {
|
||||
double pl, pb, pr, pt;
|
||||
double il, ib, ir, it;
|
||||
glyph->getQuadPlaneBounds(pl, pb, pr, pt);
|
||||
glyph->getQuadAtlasBounds(il, ib, ir, it);
|
||||
pl *= fsScale, pb *= fsScale, pr *= fsScale, pt *= fsScale;
|
||||
pl += x, pb += y, pr += x, pt += y;
|
||||
il *= texelWidth, ib *= texelHeight, ir *= texelWidth, it *= texelHeight;
|
||||
fprintf(file, " %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g,\n",
|
||||
pl, pb, il, ib,
|
||||
pr, pb, ir, ib,
|
||||
pl, pt, il, it,
|
||||
pr, pt, ir, it,
|
||||
pl, pt, il, it,
|
||||
pr, pb, ir, ib
|
||||
);
|
||||
}
|
||||
double advance = glyph->getAdvance();
|
||||
fonts[i].getAdvance(advance, cp[0], cp[1]);
|
||||
x += fsScale*advance;
|
||||
anyGlyphs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
textWidth = std::max(textWidth, x);
|
||||
y += fsScale*fontMetrics.descenderY;
|
||||
fputs("};\n", file);
|
||||
fprintf(file, "const vec2 textSize = vec2(%.9g, %.9g);\n\n", textWidth, -y);
|
||||
}
|
||||
fputs("PREVIEW_IMAGE(Preview, Atlas, txRange, vec3(1.0), textQuadVertices, textSize, ivec2(1200, 400));\n", file);
|
||||
fputs("export png(Preview, \"preview.png\");\n", file);
|
||||
fclose(file);
|
||||
return anyGlyphs;
|
||||
}
|
||||
|
||||
}
|
||||
14
Nuake/src/Vendors/msdf-atlas-gen/shadron-preview-generator.h
Normal file
14
Nuake/src/Vendors/msdf-atlas-gen/shadron-preview-generator.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Generates a Shadron script that displays a string using the generated atlas
|
||||
bool generateShadronPreview(const FontGeometry *fonts, int fontCount, ImageType atlasType, int atlasWidth, int atlasHeight, double pxRange, const unicode_t *text, const char *imageFilename, bool fullRange, const char *outputFilename);
|
||||
|
||||
}
|
||||
90
Nuake/src/Vendors/msdf-atlas-gen/size-selectors.cpp
Normal file
90
Nuake/src/Vendors/msdf-atlas-gen/size-selectors.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
#include "size-selectors.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
template <int MULTIPLE>
|
||||
SquareSizeSelector<MULTIPLE>::SquareSizeSelector(int minArea) : lowerBound(0), upperBound(-1) {
|
||||
if (minArea > 0)
|
||||
lowerBound = int(sqrt(minArea-1))/MULTIPLE+1;
|
||||
updateCurrent();
|
||||
}
|
||||
|
||||
template <int MULTIPLE>
|
||||
void SquareSizeSelector<MULTIPLE>::updateCurrent() {
|
||||
if (upperBound < 0)
|
||||
current = 5*lowerBound/4+16/MULTIPLE;
|
||||
else
|
||||
current = lowerBound+(upperBound-lowerBound)/2;
|
||||
}
|
||||
|
||||
template <int MULTIPLE>
|
||||
bool SquareSizeSelector<MULTIPLE>::operator()(int &width, int &height) const {
|
||||
width = MULTIPLE*current, height = MULTIPLE*current;
|
||||
return lowerBound < upperBound || upperBound < 0;
|
||||
}
|
||||
|
||||
template <int MULTIPLE>
|
||||
SquareSizeSelector<MULTIPLE> & SquareSizeSelector<MULTIPLE>::operator++() {
|
||||
lowerBound = current+1;
|
||||
updateCurrent();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <int MULTIPLE>
|
||||
SquareSizeSelector<MULTIPLE> & SquareSizeSelector<MULTIPLE>::operator--() {
|
||||
upperBound = current;
|
||||
updateCurrent();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template class SquareSizeSelector<1>;
|
||||
template class SquareSizeSelector<2>;
|
||||
template class SquareSizeSelector<4>;
|
||||
|
||||
SquarePowerOfTwoSizeSelector::SquarePowerOfTwoSizeSelector(int minArea) : side(1) {
|
||||
while (side*side < minArea)
|
||||
side <<= 1;
|
||||
}
|
||||
|
||||
bool SquarePowerOfTwoSizeSelector::operator()(int &width, int &height) const {
|
||||
width = side, height = side;
|
||||
return side > 0;
|
||||
}
|
||||
|
||||
SquarePowerOfTwoSizeSelector & SquarePowerOfTwoSizeSelector::operator++() {
|
||||
side <<= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SquarePowerOfTwoSizeSelector & SquarePowerOfTwoSizeSelector::operator--() {
|
||||
side = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PowerOfTwoSizeSelector::PowerOfTwoSizeSelector(int minArea) : w(1), h(1) {
|
||||
while (w*h < minArea)
|
||||
++*this;
|
||||
}
|
||||
|
||||
bool PowerOfTwoSizeSelector::operator()(int &width, int &height) const {
|
||||
width = w, height = h;
|
||||
return w > 0 && h > 0;
|
||||
}
|
||||
|
||||
PowerOfTwoSizeSelector & PowerOfTwoSizeSelector::operator++() {
|
||||
if (w == h)
|
||||
w <<= 1;
|
||||
else
|
||||
h = w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PowerOfTwoSizeSelector & PowerOfTwoSizeSelector::operator--() {
|
||||
w = 0, h = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
54
Nuake/src/Vendors/msdf-atlas-gen/size-selectors.h
Normal file
54
Nuake/src/Vendors/msdf-atlas-gen/size-selectors.h
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
// The size selector classes are used to select the minimum dimensions of the atlas fitting a given constraint.
|
||||
|
||||
/// Selects square dimensions which are also a multiple of MULTIPLE
|
||||
template <int MULTIPLE = 1>
|
||||
class SquareSizeSelector {
|
||||
|
||||
public:
|
||||
explicit SquareSizeSelector(int minArea = 0);
|
||||
bool operator()(int &width, int &height) const;
|
||||
SquareSizeSelector<MULTIPLE> & operator++();
|
||||
SquareSizeSelector<MULTIPLE> & operator--();
|
||||
|
||||
private:
|
||||
int lowerBound, upperBound;
|
||||
int current;
|
||||
|
||||
void updateCurrent();
|
||||
|
||||
};
|
||||
|
||||
/// Selects square power-of-two dimensions
|
||||
class SquarePowerOfTwoSizeSelector {
|
||||
|
||||
public:
|
||||
explicit SquarePowerOfTwoSizeSelector(int minArea = 0);
|
||||
bool operator()(int &width, int &height) const;
|
||||
SquarePowerOfTwoSizeSelector & operator++();
|
||||
SquarePowerOfTwoSizeSelector & operator--();
|
||||
|
||||
private:
|
||||
int side;
|
||||
|
||||
};
|
||||
|
||||
/// Selects square or rectangular (2:1) power-of-two dimensions
|
||||
class PowerOfTwoSizeSelector {
|
||||
|
||||
public:
|
||||
explicit PowerOfTwoSizeSelector(int minArea = 0);
|
||||
bool operator()(int &width, int &height) const;
|
||||
PowerOfTwoSizeSelector & operator++();
|
||||
PowerOfTwoSizeSelector & operator--();
|
||||
|
||||
private:
|
||||
int w, h;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
52
Nuake/src/Vendors/msdf-atlas-gen/types.h
Normal file
52
Nuake/src/Vendors/msdf-atlas-gen/types.h
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef uint32_t unicode_t;
|
||||
|
||||
/// Type of atlas image contents
|
||||
enum class ImageType {
|
||||
/// Rendered glyphs without anti-aliasing (two colors only)
|
||||
HARD_MASK,
|
||||
/// Rendered glyphs with anti-aliasing
|
||||
SOFT_MASK,
|
||||
/// Signed (true) distance field
|
||||
SDF,
|
||||
/// Signed pseudo-distance field
|
||||
PSDF,
|
||||
/// Multi-channel signed distance field
|
||||
MSDF,
|
||||
/// Multi-channel & true signed distance field
|
||||
MTSDF
|
||||
};
|
||||
|
||||
/// Atlas image encoding
|
||||
enum class ImageFormat {
|
||||
UNSPECIFIED,
|
||||
PNG,
|
||||
BMP,
|
||||
TIFF,
|
||||
TEXT,
|
||||
TEXT_FLOAT,
|
||||
BINARY,
|
||||
BINARY_FLOAT,
|
||||
BINARY_FLOAT_BE
|
||||
};
|
||||
|
||||
/// Glyph identification
|
||||
enum class GlyphIdentifierType {
|
||||
GLYPH_INDEX,
|
||||
UNICODE_CODEPOINT
|
||||
};
|
||||
|
||||
/// Direction of the Y-axis
|
||||
enum class YDirection {
|
||||
BOTTOM_UP,
|
||||
TOP_DOWN
|
||||
};
|
||||
|
||||
}
|
||||
38
Nuake/src/Vendors/msdf-atlas-gen/utf8.cpp
Normal file
38
Nuake/src/Vendors/msdf-atlas-gen/utf8.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
void utf8Decode(std::vector<unicode_t> &codepoints, const char *utf8String) {
|
||||
bool start = true;
|
||||
int rBytes = 0;
|
||||
unicode_t cp = 0;
|
||||
|
||||
for (const char *c = utf8String; *c; ++c) {
|
||||
if (rBytes > 0) {
|
||||
--rBytes;
|
||||
if ((*c&0xc0) == 0x80)
|
||||
cp |= (*c&0x3f)<<(6*rBytes);
|
||||
// else error
|
||||
} else if (!(*c&0x80)) {
|
||||
cp = *c;
|
||||
rBytes = 0;
|
||||
} else if (*c&0x40) {
|
||||
int block;
|
||||
for (block = 0; ((unsigned char) *c<<block)&0x40 && block < 4; ++block);
|
||||
if (block < 4) {
|
||||
cp = (*c&(0x3f>>block))<<(6*block);
|
||||
rBytes = block;
|
||||
} else
|
||||
continue; // error
|
||||
} else
|
||||
continue; // error
|
||||
if (!rBytes) {
|
||||
if (!(start && cp == 0xfeff)) // BOM
|
||||
codepoints.push_back(cp);
|
||||
start = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
Nuake/src/Vendors/msdf-atlas-gen/utf8.h
Normal file
12
Nuake/src/Vendors/msdf-atlas-gen/utf8.h
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "types.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Decodes the UTF-8 string into an array of Unicode codepoints
|
||||
void utf8Decode(std::vector<unicode_t> &codepoints, const char *utf8String);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user