Add Text rendering
- Add FreeType as dependency - Add MsdfGen as dependency - Add MsdfAtlasGen as dependency
This commit is contained in:
@@ -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 &);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 MSDF_ATLAS_PUBLIC 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
#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:
|
||||
enum ChangeFlag {
|
||||
NO_CHANGE = 0x00,
|
||||
RESIZED = 0x01,
|
||||
REARRANGED = 0x02
|
||||
};
|
||||
typedef int ChangeFlags;
|
||||
|
||||
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
|
||||
ChangeFlags add(GlyphGeometry *glyphs, int count, bool allowRearrange = false);
|
||||
/// 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;
|
||||
int padding;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "DynamicAtlas.hpp"
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
#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>
|
||||
typename DynamicAtlas<AtlasGenerator>::ChangeFlags DynamicAtlas<AtlasGenerator>::add(GlyphGeometry *glyphs, int count, bool allowRearrange) {
|
||||
ChangeFlags changeFlags = 0;
|
||||
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 packerStart = start;
|
||||
int remaining;
|
||||
while ((remaining = packer.pack(rectangles.data()+packerStart, rectangles.size()-packerStart)) > 0) {
|
||||
side = (side+!side)<<1;
|
||||
while (side*side < totalArea)
|
||||
side <<= 1;
|
||||
if (allowRearrange) {
|
||||
packer = RectanglePacker(side+padding, side+padding);
|
||||
packerStart = 0;
|
||||
} else {
|
||||
packer.expand(side+padding, side+padding);
|
||||
packerStart = rectangles.size()-remaining;
|
||||
}
|
||||
changeFlags |= RESIZED;
|
||||
}
|
||||
if (packerStart < start) {
|
||||
for (int i = packerStart; 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);
|
||||
changeFlags |= REARRANGED;
|
||||
} else if (changeFlags&RESIZED)
|
||||
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);
|
||||
glyphCount += count;
|
||||
return changeFlags;
|
||||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
AtlasGenerator & DynamicAtlas<AtlasGenerator>::atlasGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
const AtlasGenerator & DynamicAtlas<AtlasGenerator>::atlasGenerator() const {
|
||||
return generator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Rectangle.h"
|
||||
|
||||
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;
|
||||
Rectangle rect;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "Rectangle.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);
|
||||
/// Sets the glyph's box's rectangle in the atlas
|
||||
void setBoxRect(const Rectangle &rect);
|
||||
/// 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;
|
||||
/// Returns the glyph's box in the atlas
|
||||
Rectangle getBoxRect() 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 {
|
||||
Rectangle rect;
|
||||
double range;
|
||||
double scale;
|
||||
msdfgen::Vector2 translate;
|
||||
} box;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
#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;
|
||||
/// Returns the layout of the contained glyphs as a list of GlyphBoxes
|
||||
const std::vector<GlyphBox> & getLayout() const;
|
||||
|
||||
private:
|
||||
AtlasStorage storage;
|
||||
std::vector<GlyphBox> layout;
|
||||
std::vector<T> glyphBuffer;
|
||||
std::vector<byte> errorCorrectionBuffer;
|
||||
GeneratorAttributes attributes;
|
||||
int threadCount;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "ImmediateAtlasGenerator.hpp"
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
const std::vector<GlyphBox> & ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::getLayout() const {
|
||||
return layout;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
struct Rectangle {
|
||||
int x, y, w, h;
|
||||
};
|
||||
|
||||
struct OrientedRectangle : Rectangle {
|
||||
bool rotated;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Rectangle.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Guillotine 2D single bin packer
|
||||
class RectanglePacker {
|
||||
|
||||
public:
|
||||
RectanglePacker();
|
||||
RectanglePacker(int width, int height);
|
||||
/// Expands the packing area - both width and height must be greater or equal to the previous value
|
||||
void expand(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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MSDF_ATLAS_NO_ARTERY_FONT
|
||||
|
||||
#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);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD ATLAS GENERATOR
|
||||
* ---------------------------------------------------
|
||||
* A utility by Viktor Chlumsky, (c) 2020 - 2023
|
||||
* 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 "artery-font-export.h"
|
||||
#include "csv-export.h"
|
||||
#include "json-export.h"
|
||||
#include "shadron-preview-generator.h"
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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