atlas with variations
This commit is contained in:
parent
bfbf02e49e
commit
d4b86f5026
2 changed files with 240 additions and 49 deletions
176
src/Atlas.cpp
176
src/Atlas.cpp
|
@ -1,29 +1,75 @@
|
||||||
#include "Atlas.h"
|
#include "Atlas.h"
|
||||||
#include "BitmapRef.hpp"
|
|
||||||
#include "GlyphBox.h"
|
|
||||||
#include "conversion.h"
|
#include "conversion.h"
|
||||||
#include "edge-coloring.h"
|
|
||||||
#include "import-font.h"
|
#include "import-font.h"
|
||||||
#include "ofFileUtils.h"
|
|
||||||
#include "ofTrueTypeFont.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace ofxMsdfgen {
|
namespace ofxMsdfgen {
|
||||||
|
|
||||||
|
bool compareFontVariations(const FontVariation & a, const FontVariation & b){
|
||||||
|
if(a.name < b.name){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(a.name > b.name){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(a.value < b.value){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// now always false
|
||||||
|
//if(a.value > b.value){
|
||||||
|
//return false;
|
||||||
|
//}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Atlas::Atlas(){
|
Atlas::Atlas(){
|
||||||
}
|
}
|
||||||
Atlas::~Atlas(){
|
Atlas::~Atlas(){
|
||||||
|
if(font){
|
||||||
msdfgen::destroyFont(font);
|
msdfgen::destroyFont(font);
|
||||||
|
}
|
||||||
msdfgen::deinitializeFreetype(ft);
|
msdfgen::deinitializeFreetype(ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Atlas::setup(string _fontPath){
|
void Atlas::setup(string _fontPath){
|
||||||
fontPath = _fontPath;
|
fontPath = _fontPath;
|
||||||
if(generate()){
|
ft = msdfgen::initializeFreetype();
|
||||||
ofLogNotice("Atlas::setup()") << "generated Atlas";
|
font = loadFont(ft, fontPath.c_str());
|
||||||
}else{
|
|
||||||
ofLogError("Atlas::setup()") << "whoops, could not generate Atlas";
|
variationAxesAvailable.clear();
|
||||||
|
vector <msdfgen::FontVariationAxis> _variationAxesAvailable;
|
||||||
|
if(msdfgen::listFontVariationAxes(_variationAxesAvailable,
|
||||||
|
ft,
|
||||||
|
font)){
|
||||||
|
cout << "found variation axes for " << fontPath << ":" << endl;
|
||||||
|
for(const auto & _axis : _variationAxesAvailable){
|
||||||
|
FontVariationAxis axis = {
|
||||||
|
_axis.name,
|
||||||
|
F16DOT16_TO_FLOAT(_axis.minValue),
|
||||||
|
F16DOT16_TO_FLOAT(_axis.maxValue),
|
||||||
|
F16DOT16_TO_FLOAT(_axis.defaultValue)
|
||||||
|
};
|
||||||
|
cout << std::fixed << axis.name << "\n"
|
||||||
|
<< "\tmin:" << axis.minValue
|
||||||
|
<< "\tmax:" << axis.maxValue
|
||||||
|
<< "\t:default:" << axis.defaultValue << endl;
|
||||||
|
variationAxesAvailable.push_back(axis);
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
addVariations({
|
||||||
|
{axis.name, axis.minValue},
|
||||||
|
{axis.name, axis.maxValue}
|
||||||
|
//{axis.name, axis.defaultValue}
|
||||||
|
});
|
||||||
|
cout << __LINE__ << endl;
|
||||||
}
|
}
|
||||||
|
ofLogNotice("Atlas::setup()") << "retrieved variation axes";
|
||||||
|
}else{
|
||||||
|
ofLogNotice("Atlas::setup()") << "font does not have variation axes";
|
||||||
|
}
|
||||||
|
//if(generate()){
|
||||||
|
//ofLogNotice("Atlas::setup()") << "generated Atlas";
|
||||||
|
//}else{
|
||||||
|
//ofLogError("Atlas::setup()") << "whoops, could not generate Atlas";
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Atlas::setup(string _fontPath,
|
void Atlas::setup(string _fontPath,
|
||||||
|
@ -32,45 +78,117 @@ void Atlas::setup(string _fontPath,
|
||||||
setup(_fontPath);
|
setup(_fontPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Atlas::addVariations(vector <FontVariation> variations){
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
// add to extremes
|
||||||
|
for(const auto & variation : variations){
|
||||||
|
auto & v = variationExtremes;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for(const auto & ve : variationExtremes){
|
||||||
|
if(ve.name == variation.name && ve.value == variation.value){
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if(std::find(v.begin(), v.end(), variation) != v.end()){
|
||||||
|
if(!found){
|
||||||
|
variationExtremes.push_back(variation);
|
||||||
|
cout << "variation " << variation.name << " v:" << variation.value << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
// calculate steps
|
||||||
|
variationSteps.clear();
|
||||||
|
// first, sort the extremes
|
||||||
|
sort(variationExtremes.begin(),
|
||||||
|
variationExtremes.end(),
|
||||||
|
compareFontVariations);
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
|
||||||
|
for(int i = 0; i < variationExtremes.size() - 1; i++){
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
const FontVariation & a = variationExtremes[i];
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
const FontVariation & b = variationExtremes[i + 1];
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
cout << "a value: " << ofToString(a.value) << endl;
|
||||||
|
cout << "b value: " << ofToString(b.value) << endl;
|
||||||
|
float diff = b.value - a.value;
|
||||||
|
cout << "diff: " << ofToString(diff) << endl;
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
int stepAmount = ceil(diff / settings.maxInterpolationStepSize);
|
||||||
|
cout << "stepAmount: " << ofToString(stepAmount) << endl;
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
float step = diff / stepAmount;
|
||||||
|
float value = a.value + step;
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
variationSteps.push_back(a);
|
||||||
|
cout << "ADDING " << a.name << " (" << ofToString(a.value) << ")" << endl;
|
||||||
|
int stop = 0;
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
while(value < b.value && stop < 100){
|
||||||
|
variationSteps.push_back({a.name, value});
|
||||||
|
cout << std::fixed << "ADDING " << a.name << " (" << value << ")" << endl;
|
||||||
|
value += step;
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
stop++;
|
||||||
|
}
|
||||||
|
cout << "ADDING " << b.name << " (" << ofToString(b.value) << ")" << endl;
|
||||||
|
variationSteps.push_back(b);
|
||||||
|
}
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
if(variationExtremes.size() == 1){
|
||||||
|
variationSteps = variationExtremes;
|
||||||
|
}
|
||||||
|
cout << __LINE__ << endl;
|
||||||
|
}
|
||||||
|
|
||||||
bool Atlas::generate(){
|
bool Atlas::generate(){
|
||||||
bool success = false;
|
bool success = false;
|
||||||
//{
|
//{
|
||||||
msdfgen::FreetypeHandle * ft = msdfgen::initializeFreetype();
|
|
||||||
if(ft){
|
if(ft){
|
||||||
const char * fontPath_c_str = fontPath.c_str();
|
|
||||||
msdfgen::FontHandle * font = loadFont(ft, fontPath_c_str);
|
|
||||||
if(font){
|
if(font){
|
||||||
// Storage for glyph geometry and their coordinates in the atlas
|
// Storage for glyph geometry and their coordinates in the atlas
|
||||||
std::vector <msdf_atlas::GlyphGeometry> glyphs;
|
std::vector <msdf_atlas::GlyphGeometry> glyphs;
|
||||||
// FontGeometry is a helper class that loads a set of glyphs from a single font.
|
|
||||||
// It can also be used to get additional font metrics, kerning information, etc.
|
for(const FontVariation & variation : variationSteps){
|
||||||
msdf_atlas::FontGeometry _fontGeometry(&glyphs);
|
std::vector <msdf_atlas::GlyphGeometry> variationGlyphs;
|
||||||
|
msdf_atlas::FontGeometry _fontGeometry(&variationGlyphs);
|
||||||
fontGeometry = _fontGeometry;
|
fontGeometry = _fontGeometry;
|
||||||
|
|
||||||
|
msdfgen::setFontVariationAxis(ft,
|
||||||
|
font,
|
||||||
|
variation.name.c_str(),
|
||||||
|
variation.value);
|
||||||
// Load a set of character glyphs:
|
// Load a set of character glyphs:
|
||||||
// The second argument can be ignored unless you mix different font sizes in one atlas.
|
// The second argument can be ignored unless you mix different font sizes in one atlas.
|
||||||
// In the last argument, you can specify a charset other than ASCII.
|
// In the last argument, you can specify a charset other than ASCII.
|
||||||
// To load specific glyph indices, use loadGlyphs instead.
|
// To load specific glyph indices, use loadGlyphs instead.
|
||||||
if(settings.characters == "charset::ascii"){
|
if(settings.characters == "charset::ascii"
|
||||||
|
|| settings.characters == ""){
|
||||||
fontGeometry.loadCharset(font, 1.0, msdf_atlas::Charset::ASCII);
|
fontGeometry.loadCharset(font, 1.0, msdf_atlas::Charset::ASCII);
|
||||||
}else if(settings.characters == ""){
|
|
||||||
msdfgen::GlyphIndex glyphIndex;
|
|
||||||
}else{
|
}else{
|
||||||
msdf_atlas::Charset charset;
|
msdf_atlas::Charset charset;
|
||||||
for(const unsigned char c : settings.characters){
|
for(const unsigned char c : settings.characters){
|
||||||
msdf_atlas::unicode_t ut(c);
|
msdf_atlas::unicode_t ut(c);
|
||||||
cout << "add char(" << c << " " << ofToString(ut) << ")" << endl;
|
|
||||||
charset.add(ut);
|
charset.add(ut);
|
||||||
cout << "charset.size: " << charset.size() << endl;
|
|
||||||
}
|
}
|
||||||
fontGeometry.loadCharset(font, 1.0, charset);
|
//fontGeometry.loadCharset(font, 1.0, charset);
|
||||||
if(glyphs.size() != settings.characters.length()){
|
//if(glyphs.size() != settings.characters.length()){
|
||||||
fontGeometry.getGlyphs().empty();
|
//fontGeometry.getGlyphs().empty();
|
||||||
fontGeometry.loadCharset(font,
|
fontGeometry.loadCharset(font,
|
||||||
1.0, // fontScale
|
1.0, // fontScale
|
||||||
charset, // charset
|
charset, // charset
|
||||||
false, // preprocess geometry
|
false, // preprocess geometry
|
||||||
true); // kerning
|
true); // kerning
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glyphs.insert(glyphs.end(),
|
||||||
|
variationGlyphs.begin(),
|
||||||
|
variationGlyphs.end());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies.
|
// Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies.
|
||||||
for(msdf_atlas::GlyphGeometry & glyph : glyphs){
|
for(msdf_atlas::GlyphGeometry & glyph : glyphs){
|
||||||
|
@ -156,6 +274,14 @@ const GlyphGeometry & Atlas::getGlyphGeometry(unsigned char character){
|
||||||
return glyphGeometries[0];
|
return glyphGeometries[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GlyphGeometry & Atlas::getGlyphGeometry(unsigned char character,
|
||||||
|
FontVariation variation){
|
||||||
|
// FIXME: error handling?
|
||||||
|
//GlyphVariationKey key = {character, variation};
|
||||||
|
//int index = glyphGeometryMap[key];
|
||||||
|
return glyphGeometries[0];
|
||||||
|
}
|
||||||
|
|
||||||
const FontGeometry & Atlas::getFontGeometry(){
|
const FontGeometry & Atlas::getFontGeometry(){
|
||||||
return fontGeometry;
|
return fontGeometry;
|
||||||
}
|
}
|
||||||
|
|
81
src/Atlas.h
81
src/Atlas.h
|
@ -1,13 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "import-font.h"
|
|
||||||
#include "ofMain.h"
|
|
||||||
#include "ofTrueTypeFont.h"
|
|
||||||
#include <freetype2/freetype/freetype.h>
|
|
||||||
#include <msdf-atlas-gen/msdf-atlas-gen.h>
|
|
||||||
#include <msdf-atlas-gen/types.h>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include "ofMain.h"
|
||||||
|
//#include "ofTrueTypeFont.h"
|
||||||
|
//#include "msdfgen.h"
|
||||||
|
//#include "msdfgen-ext.h"
|
||||||
|
#include <msdf-atlas-gen/msdf-atlas-gen.h>
|
||||||
|
//#include <msdf-atlas-gen/types.h>
|
||||||
|
//#include "import-font.h"
|
||||||
#include "conversion.h"
|
#include "conversion.h"
|
||||||
|
//#include "BitmapRef.hpp"
|
||||||
|
//#include "GlyphBox.h"
|
||||||
|
//#include "conversion.h"
|
||||||
|
//#include "edge-coloring.h"
|
||||||
|
//#include "import-font.h"
|
||||||
|
//#include "ofFileUtils.h"
|
||||||
|
//#include "ofTrueTypeFont.h"
|
||||||
|
//#include <cstdlib>
|
||||||
|
//#include <set>
|
||||||
|
|
||||||
namespace ofxMsdfgen {
|
namespace ofxMsdfgen {
|
||||||
struct AtlasSettings {
|
struct AtlasSettings {
|
||||||
|
@ -16,6 +26,7 @@ struct AtlasSettings {
|
||||||
float minimumScale = 24.0;
|
float minimumScale = 24.0;
|
||||||
float pixelRange = 2.0;
|
float pixelRange = 2.0;
|
||||||
float miterLimit = 1.0;
|
float miterLimit = 1.0;
|
||||||
|
float maxInterpolationStepSize = 42.0;
|
||||||
string characters = "charset::ascii";
|
string characters = "charset::ascii";
|
||||||
#ifdef TARGET_EMSCRIPTEN
|
#ifdef TARGET_EMSCRIPTEN
|
||||||
int threadCount = 1;
|
int threadCount = 1;
|
||||||
|
@ -23,24 +34,78 @@ struct AtlasSettings {
|
||||||
int threadCount = 4;
|
int threadCount = 4;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
struct FontVariation {
|
||||||
|
string name;
|
||||||
|
float value;
|
||||||
|
bool operator==(const FontVariation & other) const {
|
||||||
|
return (name == other.name
|
||||||
|
&& value == other.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct FontVariationAxis {
|
||||||
|
string name;
|
||||||
|
float minValue;
|
||||||
|
float maxValue;
|
||||||
|
float defaultValue;
|
||||||
|
};
|
||||||
|
struct GlyphVariationKey {
|
||||||
|
unsigned char character;
|
||||||
|
FontVariation variation;
|
||||||
|
|
||||||
|
bool operator==(const GlyphVariationKey & other) const {
|
||||||
|
return (character == other.character
|
||||||
|
&& variation.name == other.variation.name
|
||||||
|
&& variation.value == other.variation.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bool compareFontVariations(const FontVariation & a, const FontVariation & b);
|
||||||
|
|
||||||
|
}
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash <ofxMsdfgen::GlyphVariationKey> {
|
||||||
|
std::size_t operator()(const ofxMsdfgen::GlyphVariationKey & k) const {
|
||||||
|
using std::size_t;
|
||||||
|
using std::hash;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// Compute individual hash values for first,
|
||||||
|
// second and third and combine them using XOR
|
||||||
|
// and bit shifting:
|
||||||
|
|
||||||
|
return ((hash <unsigned char>()(k.character)
|
||||||
|
^ (hash <string>()(k.variation.name) << 1)) >> 1)
|
||||||
|
^ (hash <float>()(k.variation.value) << 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace ofxMsdfgen {
|
||||||
class Atlas {
|
class Atlas {
|
||||||
public:
|
public:
|
||||||
Atlas();
|
Atlas();
|
||||||
~Atlas();
|
~Atlas();
|
||||||
void setup(string _fontPath);
|
void setup(string _fontPath);
|
||||||
void setup(string _fontPath, AtlasSettings _settings);
|
void setup(string _fontPath, AtlasSettings _settings);
|
||||||
|
void addVariations(vector <FontVariation> variations);
|
||||||
bool generate();
|
bool generate();
|
||||||
const ofImage & getAtlasImage();
|
const ofImage & getAtlasImage();
|
||||||
const vector <GlyphGeometry> & getGlyphGeometries();
|
const vector <GlyphGeometry> & getGlyphGeometries();
|
||||||
const GlyphGeometry & getGlyphGeometry(unsigned char character);
|
const GlyphGeometry & getGlyphGeometry(unsigned char character);
|
||||||
|
const GlyphGeometry & getGlyphGeometry(unsigned char character,
|
||||||
|
FontVariation variation);
|
||||||
|
//const GlyphGeometry & getGlyphGeometry(GlyphVariationKey key);
|
||||||
const FontGeometry & getFontGeometry();
|
const FontGeometry & getFontGeometry();
|
||||||
AtlasSettings settings;
|
AtlasSettings settings;
|
||||||
|
msdfgen::FontHandle * font;
|
||||||
|
msdfgen::FreetypeHandle * ft;
|
||||||
private:
|
private:
|
||||||
string fontPath;
|
string fontPath;
|
||||||
ofImage atlasImage;
|
ofImage atlasImage;
|
||||||
vector <GlyphGeometry> glyphGeometries;
|
vector <GlyphGeometry> glyphGeometries;
|
||||||
|
unordered_map <GlyphVariationKey, int> glyphGeometryMap;
|
||||||
|
vector <FontVariationAxis> variationAxesAvailable;
|
||||||
|
vector <FontVariation> variationExtremes;
|
||||||
|
vector <FontVariation> variationSteps;
|
||||||
FontGeometry fontGeometry;
|
FontGeometry fontGeometry;
|
||||||
msdfgen::FontHandle * font;
|
|
||||||
msdfgen::FreetypeHandle * ft;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue