ofxMsdfgen/src/Atlas.cpp

289 lines
11 KiB
C++
Raw Normal View History

2023-02-21 18:41:53 +01:00
#include "Atlas.h"
2023-02-27 16:24:14 +01:00
#include "conversion.h"
#include "import-font.h"
namespace ofxMsdfgen {
2023-03-29 20:45:39 +02:00
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(){
2023-03-29 20:45:39 +02:00
if(font){
msdfgen::destroyFont(font);
}
msdfgen::deinitializeFreetype(ft);
}
2023-02-21 18:41:53 +01:00
void Atlas::setup(string _fontPath){
2023-02-21 18:41:53 +01:00
fontPath = _fontPath;
2023-03-29 20:45:39 +02:00
ft = msdfgen::initializeFreetype();
font = loadFont(ft, fontPath.c_str());
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";
2023-02-21 18:41:53 +01:00
}else{
2023-03-29 20:45:39 +02:00
ofLogNotice("Atlas::setup()") << "font does not have variation axes";
2023-02-21 18:41:53 +01:00
}
2023-03-29 20:45:39 +02:00
//if(generate()){
//ofLogNotice("Atlas::setup()") << "generated Atlas";
//}else{
//ofLogError("Atlas::setup()") << "whoops, could not generate Atlas";
//}
2023-02-21 18:41:53 +01:00
}
void Atlas::setup(string _fontPath,
AtlasSettings _settings){
2023-02-21 18:41:53 +01:00
settings = _settings;
setup(_fontPath);
}
2023-03-29 20:45:39 +02:00
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(){
2023-02-21 18:41:53 +01:00
bool success = false;
//{
if(ft){
if(font){
2023-02-21 18:41:53 +01:00
// Storage for glyph geometry and their coordinates in the atlas
std::vector <msdf_atlas::GlyphGeometry> glyphs;
2023-03-29 20:45:39 +02:00
for(const FontVariation & variation : variationSteps){
std::vector <msdf_atlas::GlyphGeometry> variationGlyphs;
msdf_atlas::FontGeometry _fontGeometry(&variationGlyphs);
fontGeometry = _fontGeometry;
msdfgen::setFontVariationAxis(ft,
font,
variation.name.c_str(),
variation.value);
// Load a set of character glyphs:
// 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.
// To load specific glyph indices, use loadGlyphs instead.
if(settings.characters == "charset::ascii"
|| settings.characters == ""){
fontGeometry.loadCharset(font, 1.0, msdf_atlas::Charset::ASCII);
}else{
msdf_atlas::Charset charset;
for(const unsigned char c : settings.characters){
msdf_atlas::unicode_t ut(c);
charset.add(ut);
}
//fontGeometry.loadCharset(font, 1.0, charset);
//if(glyphs.size() != settings.characters.length()){
//fontGeometry.getGlyphs().empty();
2023-03-19 12:00:39 +01:00
fontGeometry.loadCharset(font,
2023-03-29 20:45:39 +02:00
1.0, // fontScale
charset, // charset
false, // preprocess geometry
true); // kerning
//}
2023-02-27 16:24:14 +01:00
}
2023-03-29 20:45:39 +02:00
glyphs.insert(glyphs.end(),
variationGlyphs.begin(),
variationGlyphs.end());
2023-02-27 16:24:14 +01:00
}
2023-02-21 18:41:53 +01:00
// Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies.
for(msdf_atlas::GlyphGeometry & glyph : glyphs){
2023-02-27 16:24:14 +01:00
//FIXME: we do not need to inverse y axis, something else is wrong
2023-03-19 12:01:06 +01:00
// msdfgen::Shape & shape = const_cast <msdfgen::Shape &>(glyph.getShape());
// shape.inverseYAxis = true;
glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, // strategy
settings.maxCornerAngle, // angleThreshold
0); // seed
2023-02-21 18:41:53 +01:00
}
// TightAtlasPacker class computes the layout of the atlas.
msdf_atlas::TightAtlasPacker packer;
// Set atlas parameters:
// setDimensions or setDimensionsConstraint to find the best value
packer.setDimensionsConstraint(msdf_atlas::TightAtlasPacker::DimensionsConstraint::SQUARE);
// setScale for a fixed size or setMinimumScale to use the largest that fits
2023-02-27 16:24:14 +01:00
//packer.setMinimumScale(settings.minimumScale);
packer.setScale(settings.scale);
2023-02-21 18:41:53 +01:00
// setPixelRange or setUnitRange
packer.setPixelRange(settings.pixelRange);
packer.setMiterLimit(settings.miterLimit);
// Compute atlas layout - pack glyphs
packer.pack(glyphs.data(), glyphs.size());
// Get final atlas dimensions
int width = 0, height = 0;
packer.getDimensions(width, height);
// The ImmediateAtlasGenerator class facilitates the generation of the atlas bitmap.
msdf_atlas::ImmediateAtlasGenerator <
float, // pixel type of buffer for individual glyphs depends on generator function
3, // number of atlas color channels
& msdf_atlas::msdfGenerator, // function to generate bitmaps for individual glyphs
msdf_atlas::BitmapAtlasStorage <float, 3> // class that stores the atlas bitmap
2023-02-21 18:41:53 +01:00
// For example, a custom atlas storage class that stores it in VRAM can be used.
> generator(width, height);
// GeneratorAttributes can be modified to change the generator's default settings.
msdf_atlas::GeneratorAttributes attributes;
generator.setAttributes(attributes);
generator.setThreadCount(settings.threadCount);
// Generate atlas bitmap
generator.generate(glyphs.data(), glyphs.size());
// The atlas bitmap can now be retrieved via atlasStorage as a BitmapConstRef.
// The glyphs array (or fontGeometry) contains positioning data for typesetting text.
msdfgen::Bitmap <float, 3> bitmap(generator.atlasStorage());
toOfImage(bitmap, atlasImage);
atlasImage.update();
2023-02-21 18:41:53 +01:00
std::vector <msdf_atlas::GlyphBox> layout = generator.getLayout();
int i = 0;
for(const msdf_atlas::GlyphBox & gb : layout){
msdf_atlas::GlyphGeometry gg = glyphs[i];
i++;
2023-02-27 16:24:14 +01:00
glyphGeometries.push_back(gg);
}
2023-02-21 18:41:53 +01:00
// Cleanup
//msdfgen::destroyFont(font);
2023-02-21 18:41:53 +01:00
success = true; // FIXME: always turns true, why do we have this
2023-02-21 18:41:53 +01:00
}
//msdfgen::deinitializeFreetype(ft);
2023-02-21 18:41:53 +01:00
}
return success;
}
const ofImage & Atlas::getAtlasImage(){
2023-02-21 18:41:53 +01:00
return atlasImage;
}
2023-02-27 16:24:14 +01:00
const vector <GlyphGeometry> & Atlas::getGlyphGeometries(){
2023-02-27 16:24:14 +01:00
return glyphGeometries;
}
const GlyphGeometry & Atlas::getGlyphGeometry(unsigned char character){
for(const GlyphGeometry & gg : glyphGeometries){
if(gg.getCodepoint() == static_cast <msdf_atlas::unicode_t>(character)){
return gg;
}
}
// not found!
ofLogError("Atlas::getGlyphGeometry")
<< "glyph(" << character << ") not found!" << endl
<< "returning first glyph. this is bad." << endl;
// FIXME: proper error handling
return glyphGeometries[0];
}
2023-03-29 20:45:39 +02:00
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(){
return fontGeometry;
}
}