make LayerComposition more flexible ... unstable implementation
This commit is contained in:
parent
207e2537b1
commit
e6a1ecd971
8 changed files with 527 additions and 253 deletions
172
src/Layer.cpp
172
src/Layer.cpp
|
@ -1,173 +1,3 @@
|
||||||
#include "Layer.h"
|
#include "Layer.h"
|
||||||
#include "conversion.h"
|
|
||||||
#include "ofAppRunner.h"
|
|
||||||
#include "ofGraphics.h"
|
|
||||||
#include "ofUtils.h"
|
|
||||||
|
|
||||||
namespace ofxVariableLab {
|
// Layer is virtual
|
||||||
|
|
||||||
Layer::Layer(){
|
|
||||||
}
|
|
||||||
Layer::~Layer(){
|
|
||||||
}
|
|
||||||
MsdfLayer::MsdfLayer(){
|
|
||||||
}
|
|
||||||
MsdfLayer::~MsdfLayer(){
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::update(){
|
|
||||||
if(isDirty){
|
|
||||||
|
|
||||||
isDirty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MsdfLayer::draw(glm::vec3 position) const {
|
|
||||||
const ofImage & atlasImage = atlas->getAtlasImage();
|
|
||||||
ofDisableAlphaBlending();
|
|
||||||
ofEnableDepthTest();
|
|
||||||
float pixelRange = 2;
|
|
||||||
int atlas_w = atlasImage.getWidth();
|
|
||||||
int atlas_h = atlasImage.getHeight();
|
|
||||||
int atlas_x = 0;
|
|
||||||
int atlas_y = 0;
|
|
||||||
glm::vec2 unitRange = glm::vec2(pixelRange) / glm::vec2(atlas_w, atlas_h);
|
|
||||||
|
|
||||||
shader->begin();
|
|
||||||
shader->setUniformTexture("msdf", atlasImage.getTexture(), 0);
|
|
||||||
shader->setUniform4f("fontColor", ofFloatColor::white);
|
|
||||||
shader->setUniform2f("unitRange", unitRange);
|
|
||||||
shader->end();
|
|
||||||
|
|
||||||
ofPushMatrix();
|
|
||||||
ofTranslate(position);
|
|
||||||
ofPushStyle();
|
|
||||||
ofSetColor(ofColor::pink);
|
|
||||||
ofDrawLine(glm::vec2(0, 0), glm::vec2(ofGetWidth(), 0));
|
|
||||||
ofPopStyle();
|
|
||||||
char previous_c;
|
|
||||||
bool firstLetter = true;
|
|
||||||
|
|
||||||
// set variation axis
|
|
||||||
const float swing_sin = sin(ofGetElapsedTimef() * 1);
|
|
||||||
const float swing_01 = ofMap(swing_sin, -1, 1, 0, 1);
|
|
||||||
const vector <ofxMsdfgen::FontVariationAxis> & variationAxisAvailable = atlas->getVariationAxesAvailable();
|
|
||||||
const string var_name = variationAxisAvailable[0].name;
|
|
||||||
const float var_value = ofMap(swing_01, 0, 1,
|
|
||||||
variationAxisAvailable[0].minValue,
|
|
||||||
variationAxisAvailable[0].maxValue);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for(const char c : propsBuffer[0].text){
|
|
||||||
float mix = -1;
|
|
||||||
ofxMsdfgen::GlyphGeometry gg_a;
|
|
||||||
ofxMsdfgen::GlyphGeometry gg_b;
|
|
||||||
|
|
||||||
bool success = atlas->getGlyphGeometryPair(c,
|
|
||||||
{var_name, var_value},
|
|
||||||
gg_a,
|
|
||||||
gg_b,
|
|
||||||
mix);
|
|
||||||
if(!success){
|
|
||||||
ofLogError("MsdfLayer::draw") << "could not get glyphGeometryPair" << endl;
|
|
||||||
}
|
|
||||||
int x_a, y_a, w_a, h_a;
|
|
||||||
int x_b, y_b, w_b, h_b;
|
|
||||||
gg_a.getBoxRect(x_a, y_a, w_a, h_a);
|
|
||||||
gg_b.getBoxRect(x_b, y_b, w_b, h_b);
|
|
||||||
if(y_a < 0 || y_b < 0){
|
|
||||||
// FIXME: make sure this does not happen
|
|
||||||
ofLogError("MsdfLayer::draw") << "y smaller 0, this is not good" << endl;
|
|
||||||
}
|
|
||||||
ofPushStyle();
|
|
||||||
double pl_a, pb_a, pr_a, pt_a;
|
|
||||||
double pl_b, pb_b, pr_b, pt_b;
|
|
||||||
gg_a.getQuadPlaneBounds(pl_a, pb_a, pr_a, pt_a);
|
|
||||||
gg_b.getQuadPlaneBounds(pl_b, pb_b, pr_b, pt_b);
|
|
||||||
|
|
||||||
double advance_a = gg_a.getAdvance();
|
|
||||||
double advance_b = gg_b.getAdvance();
|
|
||||||
|
|
||||||
float x = glm::mix(float(x_a), float(x_b), mix);
|
|
||||||
float y = glm::mix(float(y_a), float(y_b), mix);
|
|
||||||
float w = glm::mix(float(w_a), float(w_b), mix);
|
|
||||||
float h = glm::mix(float(h_a), float(h_b), mix);
|
|
||||||
float pl = glm::mix(float(pl_a), float(pl_b), mix);
|
|
||||||
//float pb = glm::mix(float(pb_a), float(pb_b), mix);
|
|
||||||
//float pr = glm::mix(float(pr_a), float(pr_b), mix);
|
|
||||||
float pt = glm::mix(float(pt_a), float(pt_b), mix);
|
|
||||||
double advance = glm::mix(advance_a, advance_b, mix);
|
|
||||||
|
|
||||||
ofPushMatrix();
|
|
||||||
float magic = atlas->settings.scale;
|
|
||||||
ofSetColor(ofFloatColor(1, 1, 1, 1));
|
|
||||||
ofTranslate(pl * magic, 0, 0);
|
|
||||||
ofTranslate(0, -1 * pt * magic, 0);
|
|
||||||
//msdf_atlas::unicode_t a = static_cast <msdf_atlas::unicode_t>(previous_c);
|
|
||||||
//msdf_atlas::unicode_t b = static_cast <msdf_atlas::unicode_t>(c);
|
|
||||||
if(!firstLetter){
|
|
||||||
//cout << "this is being printed" << endl;
|
|
||||||
auto & fontGeometry = atlas->getFontGeometry();
|
|
||||||
const std::map <std::pair <int, int>, double> kerning = fontGeometry.getKerning();
|
|
||||||
ofxMsdfgen::GlyphGeometry gg_previous = atlas->getGlyphGeometry(c);
|
|
||||||
|
|
||||||
std::map <std::pair <int, int>, double>::const_iterator it = kerning.find(std::make_pair <int, int>(gg_previous.getIndex(), gg_a.getIndex()));
|
|
||||||
if(it != kerning.end()){
|
|
||||||
advance += it->second;
|
|
||||||
ofDrawBitmapStringHighlight(ofToString(it->second), 0, 200, ofColor::black, ofColor::pink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
glm::vec2 translation_a = glm::vec2(float(x_a) / float(atlas_w),
|
|
||||||
float(y_a) / float(atlas_h));
|
|
||||||
glm::vec2 scale_a = glm::vec2(float(w_a) / float(atlas_w),
|
|
||||||
float(h_a) / float(atlas_h));
|
|
||||||
glm::vec2 translation_b = glm::vec2(float(x_b) / float(atlas_w),
|
|
||||||
float(y_b) / float(atlas_h));
|
|
||||||
glm::vec2 scale_b = glm::vec2(float(w_b) / float(atlas_w),
|
|
||||||
float(h_b) / float(atlas_h));
|
|
||||||
//if(firstLetter){
|
|
||||||
//cout << "translation_a: " << ofToString(translation_a) << endl;
|
|
||||||
//cout << "scale_a: " << ofToString(scale_a) << endl;
|
|
||||||
//}
|
|
||||||
shader->begin();
|
|
||||||
shader->setUniform4f("fontColor", ofFloatColor::yellow);
|
|
||||||
shader->setUniform2f("translation_a", translation_a);
|
|
||||||
shader->setUniform2f("scale_a", scale_a);
|
|
||||||
shader->setUniform2f("translation_b", translation_b);
|
|
||||||
shader->setUniform2f("scale_b", scale_b);
|
|
||||||
shader->setUniform1f("msdf_mix", mix);
|
|
||||||
atlasImage.draw(0, 0, w, h);
|
|
||||||
shader->end();
|
|
||||||
ofPopMatrix();
|
|
||||||
ofPopStyle();
|
|
||||||
ofTranslate(advance * magic, 0, 0);
|
|
||||||
ofTranslate(-1 * pl * magic, 0, 0);
|
|
||||||
previous_c = c;
|
|
||||||
if(firstLetter){
|
|
||||||
firstLetter = false;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
ofPopMatrix();
|
|
||||||
ofDisableDepthTest();
|
|
||||||
ofEnableAlphaBlending();
|
|
||||||
}
|
|
||||||
void Layer::setProps(const Props & props){
|
|
||||||
while(propsBuffer.size() > max(0, int(settings.maxBufferSize - 1))){
|
|
||||||
propsBuffer.pop_back();
|
|
||||||
}
|
|
||||||
propsBuffer.push_front(props);
|
|
||||||
}
|
|
||||||
const Layer::Props & Layer::getProps() const {
|
|
||||||
return propsBuffer[0];
|
|
||||||
}
|
|
||||||
void Layer::clearPropsBuffer(){
|
|
||||||
propsBuffer.clear();
|
|
||||||
}
|
|
||||||
void Layer::setId(const string & id){
|
|
||||||
this->id = id;
|
|
||||||
}
|
|
||||||
const string & Layer::getId(){
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
66
src/Layer.h
66
src/Layer.h
|
@ -1,25 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Atlas.h"
|
||||||
#include "ofMain.h"
|
#include "ofMain.h"
|
||||||
|
|
||||||
//uuid
|
//uuid
|
||||||
#include "random_id.h"
|
#include "random_id.h"
|
||||||
|
|
||||||
#include "ofxMsdfgen.h"
|
#include "ofxMsdfgen.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace ofxVariableLab {
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
class Layer {
|
class Layer {
|
||||||
protected:
|
|
||||||
Layer();
|
|
||||||
public:
|
public:
|
||||||
~Layer();
|
enum Type {
|
||||||
enum TransformOrigin {
|
MSDFGEN = 0,
|
||||||
TOP_LEFT,
|
GPUFONT
|
||||||
TOP_RIGHT,
|
|
||||||
CENTER,
|
|
||||||
BOTTOM_LEFT,
|
|
||||||
BOTTOM_RIGHT
|
|
||||||
};
|
};
|
||||||
struct Props {
|
struct Props {
|
||||||
float x = 0;
|
float x = 0;
|
||||||
|
@ -27,54 +22,31 @@ class Layer {
|
||||||
float rotation = 0;
|
float rotation = 0;
|
||||||
float fontSize_px = 24;
|
float fontSize_px = 24;
|
||||||
float * color[4];
|
float * color[4];
|
||||||
TransformOrigin transformOrigin = TransformOrigin::CENTER;
|
|
||||||
bool mirror_x = false;
|
bool mirror_x = false;
|
||||||
float mirror_x_distance = 0;
|
float mirror_x_distance = 0;
|
||||||
bool mirror_y = false;
|
bool mirror_y = false;
|
||||||
float mirror_y_distance = 0;
|
float mirror_y_distance = 0;
|
||||||
float letterDelay = 0;
|
float letterDelay = 0;
|
||||||
string text = "Variable Font Editor";
|
string text = "abcdefghijklmnoprstuvqxyzABUIWERJSD";
|
||||||
};
|
};
|
||||||
struct Settings {
|
struct Settings {
|
||||||
uint32_t maxBufferSize = 100;
|
uint32_t maxBufferSize = 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
void update();
|
virtual void setup(const Settings & settings) = 0;
|
||||||
|
virtual void update() = 0;
|
||||||
virtual void draw(glm::vec3 position = glm::vec3(0, 0, 0)) const = 0;
|
virtual void draw(glm::vec3 position = glm::vec3(0, 0, 0)) const = 0;
|
||||||
void setProps(const Props & props);
|
virtual void drawCharacter(const char character,
|
||||||
const Props & getProps() const;
|
glm::vec3 position = glm::vec3(0, 0, 0),
|
||||||
//void setProps(float _x,
|
ofxMsdfgen::FontVariation fontVariation = ofxMsdfgen::FontVariation()) const = 0;
|
||||||
//float _y,
|
virtual void setProps(const Props & props) = 0;
|
||||||
//float _rotation,
|
virtual const Props & getProps() const = 0;
|
||||||
//float _wght,
|
virtual void clearPropsBuffer() = 0;
|
||||||
//float _fontSize_px,
|
virtual void setId(const string & id) = 0;
|
||||||
//float * _color[4],
|
virtual const string & getId() = 0;
|
||||||
//int _transformOrigin,
|
virtual void setShader(shared_ptr <ofShader> _shader) = 0;
|
||||||
//bool _mirror_x,
|
virtual shared_ptr <ofShader> getShader() const = 0;
|
||||||
//float _mirror_x_distance,
|
virtual const Type & getType() const = 0;
|
||||||
//bool _mirror_y,
|
|
||||||
//float _mirror_y_distance,
|
|
||||||
//float _letterDelay,
|
|
||||||
//string _text);
|
|
||||||
void clearPropsBuffer();
|
|
||||||
void setId(const string & id);
|
|
||||||
const string & getId();
|
|
||||||
|
|
||||||
Settings settings;
|
|
||||||
std::deque <Props> propsBuffer;
|
|
||||||
shared_ptr <ofShader> shader;
|
|
||||||
/// \brief are props updated but not drawn yet
|
|
||||||
bool isDirty = true;
|
|
||||||
/// \brief hashed id
|
|
||||||
string id;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MsdfLayer : public Layer {
|
|
||||||
public:
|
|
||||||
MsdfLayer();
|
|
||||||
~MsdfLayer();
|
|
||||||
void draw(glm::vec3 position = glm::vec3(0, 0, 0)) const override;
|
|
||||||
shared_ptr <ofxMsdfgen::Atlas> atlas;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
#include "LayerComposition.h"
|
#include "LayerComposition.h"
|
||||||
|
#include "Atlas.h"
|
||||||
|
#include "MsdfLayer.h"
|
||||||
#include "ofUtils.h"
|
#include "ofUtils.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace ofxVariableLab {
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
void LayerComposition::setup(){
|
void MsdfAtlasLayerCombo::setup(const ComboIdentifier & layerIdentifier){
|
||||||
ofxMsdfgen::AtlasSettings settings;
|
this->identifier = layerIdentifier;
|
||||||
|
ofxMsdfgen::AtlasSettings atlasSettings;
|
||||||
//settings.characters = "ABCDEFGHIJKL";
|
//settings.characters = "ABCDEFGHIJKL";
|
||||||
settings.scale = 64;
|
atlasSettings.scale = 64;
|
||||||
settings.characters = "";
|
atlasSettings.minimumScale = 64;
|
||||||
|
atlasSettings.characters = "";
|
||||||
|
|
||||||
//string fontName = "RobotoFlex.ttf";
|
//string fontName = "RobotoFlex.ttf";
|
||||||
//string fontPath = "data/fonts/" + fontName;
|
//string fontPath = "data/fonts/" + fontName;
|
||||||
//string fontPath = "data/celines-fonts/testing2VF.ttf";
|
//string fontPath = "data/celines-fonts/testing2VF.ttf";
|
||||||
string fontPath = "data/celines-fonts/Version-2-var.ttf";
|
string fontPath = "data/celines-fonts/Version-2-var.ttf";
|
||||||
|
//string fontPath = "data/celines-fonts/Version-2-var.ttf";
|
||||||
|
//string fontPath = "data/celines-fonts/Version-3-var.ttf";
|
||||||
|
//string fontPath = "data/celines-fonts/Version-4-var.ttf";
|
||||||
//string fontPath = "data/celines-fonts/Alfarn2.otf";
|
//string fontPath = "data/celines-fonts/Alfarn2.otf";
|
||||||
//string fontPath = "data/celines-fonts/Cottagecore.ttf";
|
//string fontPath = "data/celines-fonts/Cottagecore.ttf";
|
||||||
atlas = make_shared <ofxMsdfgen::Atlas>();
|
atlas = make_shared <ofxMsdfgen::Atlas>();
|
||||||
|
@ -24,33 +32,92 @@ void LayerComposition::setup(){
|
||||||
msdfShader->load("ofxMsdfgen/shaders/mix/GL3/shader");
|
msdfShader->load("ofxMsdfgen/shaders/mix/GL3/shader");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto layer = make_unique <ofxVariableLab::MsdfLayer>();
|
atlas->setup(fontPath, atlasSettings);
|
||||||
layer->atlas = atlas;
|
|
||||||
layer->shader = msdfShader;
|
|
||||||
|
|
||||||
layer->setProps(Layer::Props());
|
|
||||||
|
|
||||||
settings.characters += layer->getProps().text;
|
|
||||||
layers.push_back(std::move(layer));
|
|
||||||
|
|
||||||
atlas->setup(fontPath, settings);
|
|
||||||
atlas->generate();
|
|
||||||
atlasImage = make_shared <ofImage>(atlas->getAtlasImage());
|
|
||||||
glyphGeometries = atlas->getGlyphGeometries();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayerComposition::update(){
|
void MsdfAtlasLayerCombo::update(){
|
||||||
}
|
if(isDirty){
|
||||||
|
atlas->generate();
|
||||||
void LayerComposition::draw() const {
|
isDirty = false;
|
||||||
for(const auto & layer : layers){
|
|
||||||
layer->draw(glm::vec3(400, 200, 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr <ofImage> LayerComposition::getAtlasImage(){
|
void MsdfAtlasLayerCombo::careForChild(shared_ptr <Layer> layer){
|
||||||
return atlasImage;
|
shared_ptr <MsdfLayer> msdfLayer = dynamic_pointer_cast <MsdfLayer>(layer);
|
||||||
|
msdfLayer->setAtlas(this->atlas);
|
||||||
|
msdfLayer->setShader(msdfShader);
|
||||||
|
auto & as = atlas->settings;
|
||||||
|
for(const char c : layer->getProps().text){
|
||||||
|
if(as.characters.find(c) == std::string::npos){
|
||||||
|
// not found
|
||||||
|
as.characters += c;
|
||||||
|
isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComboIdentifier & MsdfAtlasLayerCombo::getIdentifier() const {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerComposition::setup(){
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerComposition::update(){
|
||||||
|
for(const auto & atlasLayerCombo : atlasLayerCombos){
|
||||||
|
atlasLayerCombo.second->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerComposition::addLayer(const ComboIdentifier & identifier,
|
||||||
|
const string & text,
|
||||||
|
const std::vector <FontVariation> & variations){
|
||||||
|
if(atlasLayerCombos.count(identifier) <= 0){
|
||||||
|
switch(identifier.type){
|
||||||
|
case Layer::GPUFONT: {
|
||||||
|
ofLogError("LayerComposition::addLayer")
|
||||||
|
<< "GPUFont not implemented" << endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
case Layer::MSDFGEN: {
|
||||||
|
// TODO: put most stuff in combo setup
|
||||||
|
auto combo = make_shared <MsdfAtlasLayerCombo>();
|
||||||
|
combo->setup(identifier); // TODO: add here text and variations
|
||||||
|
auto layer = make_shared <MsdfLayer>();
|
||||||
|
auto props = Layer::Props();
|
||||||
|
props.text = text;
|
||||||
|
layer->setProps(props);
|
||||||
|
ofxMsdfgen::AtlasSettings as;
|
||||||
|
as.characters = "";
|
||||||
|
//for(const char c : text){
|
||||||
|
//if(as.characters.find(c) == std::string::npos){
|
||||||
|
//// not found
|
||||||
|
//as.characters += c;
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
combo->atlas->setup(identifier.fontPath, as);
|
||||||
|
std::vector <ofxMsdfgen::FontVariation> msdfVariations;
|
||||||
|
for(const auto & v : variations){
|
||||||
|
msdfVariations.push_back({v.name, v.value});
|
||||||
|
}
|
||||||
|
// TODO: do not add Variation to atlas, but to combo,
|
||||||
|
// so we know it's dirty
|
||||||
|
combo->atlas->addVariations(msdfVariations);
|
||||||
|
combo->careForChild(layer);
|
||||||
|
layers.push_back(layer);
|
||||||
|
atlasLayerCombos[identifier] = std::move(combo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerComposition::draw() const {
|
||||||
|
for(const auto & layer_it : layers){
|
||||||
|
layer_it->draw(glm::vec3(0, 0, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,98 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
#include "ofMain.h"
|
#include "ofMain.h"
|
||||||
#include "ofxMsdfgen.h"
|
#include "ofxMsdfgen.h"
|
||||||
#include "Layer.h"
|
#include "Layer.h"
|
||||||
|
#include "MsdfLayer.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace ofxVariableLab {
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
|
struct ComboIdentifier {
|
||||||
|
std::string fontPath = "data/celines-fonts/Version-2-var.ttf";
|
||||||
|
Layer::Type type = Layer::MSDFGEN;
|
||||||
|
|
||||||
|
bool operator==(const ComboIdentifier & other) const {
|
||||||
|
return (this->fontPath == other.fontPath
|
||||||
|
&& this->type == other.type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AtlasLayerCombo {
|
||||||
|
public:
|
||||||
|
virtual void setup(const ComboIdentifier & identifier) = 0;
|
||||||
|
virtual void update() = 0;
|
||||||
|
virtual void careForChild(shared_ptr <Layer> layer) = 0;
|
||||||
|
virtual const ComboIdentifier & getIdentifier() const = 0;
|
||||||
|
|
||||||
|
bool operator==(const AtlasLayerCombo & other) const {
|
||||||
|
return (this->getIdentifier() == other.getIdentifier());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash <ofxVariableLab::ComboIdentifier> {
|
||||||
|
std::size_t operator()(const ofxVariableLab::ComboIdentifier & k) const {
|
||||||
|
using std::size_t;
|
||||||
|
using std::hash;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
size_t seed = 0;
|
||||||
|
ofxVariableLab::hash_combine(seed, k.fontPath);
|
||||||
|
ofxVariableLab::hash_combine(seed, k.type);
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct hash <ofxVariableLab::AtlasLayerCombo> {
|
||||||
|
std::size_t operator()(const ofxVariableLab::AtlasLayerCombo & k) const {
|
||||||
|
using std::size_t;
|
||||||
|
using std::hash;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
size_t seed = 0;
|
||||||
|
ofxVariableLab::hash_combine(seed, k.getIdentifier());
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
|
class MsdfAtlasLayerCombo : public AtlasLayerCombo {
|
||||||
|
public:
|
||||||
|
void setup(const ComboIdentifier & identifier) override;
|
||||||
|
void update() override;
|
||||||
|
void careForChild(shared_ptr <Layer> layer) override;
|
||||||
|
const ComboIdentifier & getIdentifier() const override;
|
||||||
|
shared_ptr <ofxMsdfgen::Atlas> atlas;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector <ofxMsdfgen::GlyphGeometry> glyphGeometries;
|
||||||
|
shared_ptr <ofShader> msdfShader;
|
||||||
|
ComboIdentifier identifier;
|
||||||
|
bool isDirty = false;
|
||||||
|
};
|
||||||
|
|
||||||
class LayerComposition {
|
class LayerComposition {
|
||||||
public:
|
public:
|
||||||
void setup();
|
void setup();
|
||||||
void update();
|
void update();
|
||||||
void draw() const;
|
void draw() const;
|
||||||
shared_ptr <ofImage> getAtlasImage();
|
void addLayer(const ComboIdentifier & identifier,
|
||||||
#ifdef TARGET_EMSCRIPTEN
|
const string & text,
|
||||||
#else
|
const std::vector <FontVariation> & variations);
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
shared_ptr <ofxMsdfgen::Atlas> atlas;
|
|
||||||
shared_ptr <ofImage> atlasImage;
|
|
||||||
vector <ofxMsdfgen::GlyphGeometry> glyphGeometries;
|
|
||||||
shared_ptr <ofShader> msdfShader;
|
|
||||||
|
|
||||||
vector <unique_ptr <ofxVariableLab::Layer> > layers;
|
vector <shared_ptr <ofxVariableLab::Layer> > layers;
|
||||||
|
unordered_map <ComboIdentifier, shared_ptr <AtlasLayerCombo> > atlasLayerCombos;
|
||||||
|
//unordered_map <LayerIdentifier, shared_ptr <ofxVariableLab::Layer> > layers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
266
src/MsdfLayer.cpp
Normal file
266
src/MsdfLayer.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
#include "MsdfLayer.h"
|
||||||
|
|
||||||
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
|
void MsdfLayer::setup(const Settings & settings){
|
||||||
|
this->settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MsdfLayer::update(){
|
||||||
|
if(isDirty){
|
||||||
|
isDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MsdfLayer::draw(glm::vec3 position) const {
|
||||||
|
const ofImage & atlasImage = atlas->getAtlasImage();
|
||||||
|
ofDisableAlphaBlending();
|
||||||
|
ofEnableDepthTest();
|
||||||
|
float pixelRange = 2;
|
||||||
|
int atlas_w = atlasImage.getWidth();
|
||||||
|
int atlas_h = atlasImage.getHeight();
|
||||||
|
glm::vec2 unitRange = glm::vec2(pixelRange) / glm::vec2(atlas_w, atlas_h);
|
||||||
|
|
||||||
|
shader->begin();
|
||||||
|
shader->setUniformTexture("msdf", atlasImage.getTexture(), 0);
|
||||||
|
shader->setUniform4f("fontColor", ofFloatColor::white);
|
||||||
|
shader->setUniform2f("unitRange", unitRange);
|
||||||
|
shader->end();
|
||||||
|
|
||||||
|
ofPushMatrix();
|
||||||
|
ofTranslate(position);
|
||||||
|
ofPushStyle();
|
||||||
|
ofSetColor(ofColor::pink);
|
||||||
|
ofDrawLine(glm::vec2(0, 0), glm::vec2(ofGetWidth(), 0));
|
||||||
|
ofPopStyle();
|
||||||
|
char previous_c;
|
||||||
|
bool firstLetter = true;
|
||||||
|
|
||||||
|
// set variation axis
|
||||||
|
const float swing_sin = sin(ofGetElapsedTimef() * 1);
|
||||||
|
const float swing_01 = ofMap(swing_sin, -1, 1, 0, 1);
|
||||||
|
const vector <ofxMsdfgen::FontVariationAxis> & variationAxisAvailable = atlas->getVariationAxesAvailable();
|
||||||
|
const string var_name = variationAxisAvailable[0].name;
|
||||||
|
const float var_value = ofMap(swing_01, 0, 1,
|
||||||
|
variationAxisAvailable[0].minValue,
|
||||||
|
variationAxisAvailable[0].maxValue);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for(const char c : propsBuffer[0].text){
|
||||||
|
float mix = -1;
|
||||||
|
ofxMsdfgen::GlyphGeometry gg_a;
|
||||||
|
ofxMsdfgen::GlyphGeometry gg_b;
|
||||||
|
|
||||||
|
bool success = atlas->getGlyphGeometryPair(c,
|
||||||
|
{var_name, var_value},
|
||||||
|
gg_a,
|
||||||
|
gg_b,
|
||||||
|
mix);
|
||||||
|
if(!success){
|
||||||
|
ofLogError("MsdfLayer::draw") << "could not get glyphGeometryPair" << endl;
|
||||||
|
}
|
||||||
|
int x_a, y_a, w_a, h_a;
|
||||||
|
int x_b, y_b, w_b, h_b;
|
||||||
|
gg_a.getBoxRect(x_a, y_a, w_a, h_a);
|
||||||
|
gg_b.getBoxRect(x_b, y_b, w_b, h_b);
|
||||||
|
if(y_a < 0 || y_b < 0){
|
||||||
|
// FIXME: make sure this does not happen
|
||||||
|
ofLogError("MsdfLayer::draw") << "y smaller 0, this is not good" << endl;
|
||||||
|
}
|
||||||
|
ofPushStyle();
|
||||||
|
double pl_a, pb_a, pr_a, pt_a;
|
||||||
|
double pl_b, pb_b, pr_b, pt_b;
|
||||||
|
gg_a.getQuadPlaneBounds(pl_a, pb_a, pr_a, pt_a);
|
||||||
|
gg_b.getQuadPlaneBounds(pl_b, pb_b, pr_b, pt_b);
|
||||||
|
|
||||||
|
double advance_a = gg_a.getAdvance();
|
||||||
|
double advance_b = gg_b.getAdvance();
|
||||||
|
|
||||||
|
float w = glm::mix(float(w_a), float(w_b), mix);
|
||||||
|
float h = glm::mix(float(h_a), float(h_b), mix);
|
||||||
|
float pl = glm::mix(float(pl_a), float(pl_b), mix);
|
||||||
|
//float pb = glm::mix(float(pb_a), float(pb_b), mix);
|
||||||
|
//float pr = glm::mix(float(pr_a), float(pr_b), mix);
|
||||||
|
float pt = glm::mix(float(pt_a), float(pt_b), mix);
|
||||||
|
double advance = glm::mix(advance_a, advance_b, mix);
|
||||||
|
|
||||||
|
ofPushMatrix();
|
||||||
|
float magic = atlas->settings.scale;
|
||||||
|
cout << "magic number << " << magic << endl;
|
||||||
|
ofSetColor(ofFloatColor(1, 1, 1, 1));
|
||||||
|
ofTranslate(pl * magic, 0, 0);
|
||||||
|
//ofTranslate(0, -1 * pt * magic, 0);
|
||||||
|
ofTranslate(0, 1 * pt * magic, 0);
|
||||||
|
if(!firstLetter){
|
||||||
|
//cout << "this is being printed" << endl;
|
||||||
|
auto & fontGeometry = atlas->getFontGeometry();
|
||||||
|
const std::map <std::pair <int, int>, double> kerning = fontGeometry.getKerning();
|
||||||
|
ofxMsdfgen::GlyphGeometry gg_previous = atlas->getGlyphGeometry(c);
|
||||||
|
|
||||||
|
std::map <std::pair <int, int>, double>::const_iterator it = kerning.find(std::make_pair <int, int>(gg_previous.getIndex(), gg_a.getIndex()));
|
||||||
|
if(it != kerning.end()){
|
||||||
|
advance += it->second;
|
||||||
|
ofDrawBitmapStringHighlight(ofToString(it->second), 0, 200, ofColor::black, ofColor::pink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glm::vec2 translation_a = glm::vec2(float(x_a) / float(atlas_w),
|
||||||
|
float(y_a) / float(atlas_h));
|
||||||
|
glm::vec2 scale_a = glm::vec2(float(w_a) / float(atlas_w),
|
||||||
|
float(h_a) / float(atlas_h));
|
||||||
|
glm::vec2 translation_b = glm::vec2(float(x_b) / float(atlas_w),
|
||||||
|
float(y_b) / float(atlas_h));
|
||||||
|
glm::vec2 scale_b = glm::vec2(float(w_b) / float(atlas_w),
|
||||||
|
float(h_b) / float(atlas_h));
|
||||||
|
//if(firstLetter){
|
||||||
|
//cout << "translation_a: " << ofToString(translation_a) << endl;
|
||||||
|
//cout << "scale_a: " << ofToString(scale_a) << endl;
|
||||||
|
//}
|
||||||
|
shader->begin();
|
||||||
|
shader->setUniform4f("fontColor", ofFloatColor::yellow);
|
||||||
|
shader->setUniform2f("translation_a", translation_a);
|
||||||
|
shader->setUniform2f("scale_a", scale_a);
|
||||||
|
shader->setUniform2f("translation_b", translation_b);
|
||||||
|
shader->setUniform2f("scale_b", scale_b);
|
||||||
|
shader->setUniform1f("msdf_mix", mix);
|
||||||
|
atlasImage.draw(0, 0, w, h);
|
||||||
|
shader->end();
|
||||||
|
ofPopMatrix();
|
||||||
|
ofPopStyle();
|
||||||
|
ofTranslate(advance * magic, 0, 0);
|
||||||
|
ofTranslate(-1 * pl * magic, 0, 0);
|
||||||
|
previous_c = c;
|
||||||
|
if(firstLetter){
|
||||||
|
firstLetter = false;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ofPopMatrix();
|
||||||
|
ofDisableDepthTest();
|
||||||
|
ofEnableAlphaBlending();
|
||||||
|
}
|
||||||
|
void MsdfLayer::drawCharacter(const char character,
|
||||||
|
glm::vec3 position,
|
||||||
|
ofxMsdfgen::FontVariation fontVariation) const {
|
||||||
|
const ofImage & atlasImage = atlas->getAtlasImage();
|
||||||
|
ofDisableAlphaBlending();
|
||||||
|
ofEnableDepthTest();
|
||||||
|
float pixelRange = 2;
|
||||||
|
int atlas_w = atlasImage.getWidth();
|
||||||
|
int atlas_h = atlasImage.getHeight();
|
||||||
|
glm::vec2 unitRange = glm::vec2(pixelRange) / glm::vec2(atlas_w, atlas_h);
|
||||||
|
|
||||||
|
shader->begin();
|
||||||
|
shader->setUniformTexture("msdf", atlasImage.getTexture(), 0);
|
||||||
|
shader->setUniform4f("fontColor", ofFloatColor::white);
|
||||||
|
shader->setUniform2f("unitRange", unitRange);
|
||||||
|
shader->end();
|
||||||
|
|
||||||
|
ofPushMatrix();
|
||||||
|
ofTranslate(position);
|
||||||
|
ofPushStyle();
|
||||||
|
ofSetColor(ofColor::pink);
|
||||||
|
|
||||||
|
float mix = -1;
|
||||||
|
ofxMsdfgen::GlyphGeometry gg_a;
|
||||||
|
ofxMsdfgen::GlyphGeometry gg_b;
|
||||||
|
|
||||||
|
bool success = atlas->getGlyphGeometryPair(character,
|
||||||
|
fontVariation,
|
||||||
|
gg_a,
|
||||||
|
gg_b,
|
||||||
|
mix);
|
||||||
|
if(!success){
|
||||||
|
ofLogError("MsdfLayer::draw") << "could not get glyphGeometryPair" << endl;
|
||||||
|
}
|
||||||
|
int x_a, y_a, w_a, h_a;
|
||||||
|
int x_b, y_b, w_b, h_b;
|
||||||
|
gg_a.getBoxRect(x_a, y_a, w_a, h_a);
|
||||||
|
gg_b.getBoxRect(x_b, y_b, w_b, h_b);
|
||||||
|
if(y_a < 0 || y_b < 0){
|
||||||
|
// FIXME: make sure this does not happen
|
||||||
|
ofLogError("MsdfLayer::draw") << "y smaller 0, this is not good" << endl;
|
||||||
|
}
|
||||||
|
ofPushStyle();
|
||||||
|
double pl_a, pb_a, pr_a, pt_a;
|
||||||
|
double pl_b, pb_b, pr_b, pt_b;
|
||||||
|
gg_a.getQuadPlaneBounds(pl_a, pb_a, pr_a, pt_a);
|
||||||
|
gg_b.getQuadPlaneBounds(pl_b, pb_b, pr_b, pt_b);
|
||||||
|
|
||||||
|
double advance_a = gg_a.getAdvance();
|
||||||
|
double advance_b = gg_b.getAdvance();
|
||||||
|
|
||||||
|
float w = glm::mix(float(w_a), float(w_b), mix);
|
||||||
|
float h = glm::mix(float(h_a), float(h_b), mix);
|
||||||
|
float pl = glm::mix(float(pl_a), float(pl_b), mix);
|
||||||
|
float pt = glm::mix(float(pt_a), float(pt_b), mix);
|
||||||
|
double advance = glm::mix(advance_a, advance_b, mix);
|
||||||
|
|
||||||
|
ofPushMatrix();
|
||||||
|
float magic = atlas->settings.scale;
|
||||||
|
ofSetColor(ofFloatColor(1, 1, 1, 1));
|
||||||
|
ofTranslate(pl * magic, 0, 0);
|
||||||
|
ofTranslate(0, -1 * pt * magic, 0);
|
||||||
|
|
||||||
|
glm::vec2 translation_a = glm::vec2(float(x_a) / float(atlas_w),
|
||||||
|
float(y_a) / float(atlas_h));
|
||||||
|
glm::vec2 scale_a = glm::vec2(float(w_a) / float(atlas_w),
|
||||||
|
float(h_a) / float(atlas_h));
|
||||||
|
glm::vec2 translation_b = glm::vec2(float(x_b) / float(atlas_w),
|
||||||
|
float(y_b) / float(atlas_h));
|
||||||
|
glm::vec2 scale_b = glm::vec2(float(w_b) / float(atlas_w),
|
||||||
|
float(h_b) / float(atlas_h));
|
||||||
|
shader->begin();
|
||||||
|
shader->setUniform4f("fontColor", ofFloatColor::yellow);
|
||||||
|
shader->setUniform2f("translation_a", translation_a);
|
||||||
|
shader->setUniform2f("scale_a", scale_a);
|
||||||
|
shader->setUniform2f("translation_b", translation_b);
|
||||||
|
shader->setUniform2f("scale_b", scale_b);
|
||||||
|
shader->setUniform1f("msdf_mix", mix);
|
||||||
|
atlasImage.draw(0, 0, w, h);
|
||||||
|
shader->end();
|
||||||
|
ofPopMatrix();
|
||||||
|
ofPopStyle();
|
||||||
|
ofTranslate(advance * magic, 0, 0);
|
||||||
|
ofTranslate(-1 * pl * magic, 0, 0);
|
||||||
|
|
||||||
|
ofPopStyle();
|
||||||
|
ofPopMatrix();
|
||||||
|
ofDisableDepthTest();
|
||||||
|
ofEnableAlphaBlending();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MsdfLayer::setShader(shared_ptr <ofShader> _shader){
|
||||||
|
shader = _shader;
|
||||||
|
}
|
||||||
|
shared_ptr <ofShader> MsdfLayer::getShader() const {
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
const Layer::Type & MsdfLayer::getType() const {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MsdfLayer::setAtlas(shared_ptr <ofxMsdfgen::Atlas> _atlas){
|
||||||
|
atlas = _atlas;
|
||||||
|
}
|
||||||
|
shared_ptr <ofxMsdfgen::Atlas> MsdfLayer::getAtlas() const {
|
||||||
|
return atlas;
|
||||||
|
}
|
||||||
|
void MsdfLayer::setProps(const Props & props){
|
||||||
|
while(propsBuffer.size() > max(0, int(settings.maxBufferSize - 1))){
|
||||||
|
propsBuffer.pop_back();
|
||||||
|
}
|
||||||
|
propsBuffer.push_front(props);
|
||||||
|
}
|
||||||
|
const Layer::Props & MsdfLayer::getProps() const {
|
||||||
|
return propsBuffer[0];
|
||||||
|
}
|
||||||
|
void MsdfLayer::clearPropsBuffer(){
|
||||||
|
propsBuffer.clear();
|
||||||
|
}
|
||||||
|
void MsdfLayer::setId(const string & id){
|
||||||
|
this->id = id;
|
||||||
|
}
|
||||||
|
const string & MsdfLayer::getId(){
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
43
src/MsdfLayer.h
Normal file
43
src/MsdfLayer.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ofMain.h"
|
||||||
|
#include "ofxMsdfgen.h"
|
||||||
|
#include "Atlas.h"
|
||||||
|
#include "Layer.h"
|
||||||
|
|
||||||
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
|
class MsdfLayer : public Layer {
|
||||||
|
public:
|
||||||
|
void setup(const Settings & settings);
|
||||||
|
void update() override;
|
||||||
|
void draw(glm::vec3 position = glm::vec3(0, 0, 0)) const override;
|
||||||
|
void drawCharacter(const char character,
|
||||||
|
glm::vec3 position = glm::vec3(0, 0, 0),
|
||||||
|
ofxMsdfgen::FontVariation fontVariation = ofxMsdfgen::FontVariation()) const override;
|
||||||
|
void setProps(const Props & props) override;
|
||||||
|
const Props & getProps() const override;
|
||||||
|
void clearPropsBuffer() override;
|
||||||
|
void setId(const string & id) override;
|
||||||
|
const string & getId() override;
|
||||||
|
void setShader(shared_ptr <ofShader> _shader) override;
|
||||||
|
shared_ptr <ofShader> getShader() const override;
|
||||||
|
const Type & getType() const override;
|
||||||
|
|
||||||
|
void setAtlas(shared_ptr <ofxMsdfgen::Atlas> _atlas);
|
||||||
|
shared_ptr <ofxMsdfgen::Atlas> getAtlas() const;
|
||||||
|
|
||||||
|
shared_ptr <ofxMsdfgen::Atlas> atlas;
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
std::deque <Props> propsBuffer;
|
||||||
|
shared_ptr <ofShader> shader;
|
||||||
|
/// \brief are props updated but not drawn yet
|
||||||
|
bool isDirty = true;
|
||||||
|
/// \brief hashed id
|
||||||
|
string id;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Layer::Type type = MSDFGEN;
|
||||||
|
};
|
||||||
|
}
|
25
src/Utils.h
Normal file
25
src/Utils.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ofxVariableLab {
|
||||||
|
|
||||||
|
struct FontVariationAxis {
|
||||||
|
char * name;
|
||||||
|
float minValue;
|
||||||
|
float maxValue;
|
||||||
|
float defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FontVariation {
|
||||||
|
char * name;
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void hash_combine(std::size_t & seed, const T & v){
|
||||||
|
std::hash <T> hasher;
|
||||||
|
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "random_id.h"
|
#include "random_id.h"
|
||||||
|
#include "Utils.h"
|
||||||
#include "Layer.h"
|
#include "Layer.h"
|
||||||
|
#include "MsdfLayer.h"
|
||||||
#include "LayerComposition.h"
|
#include "LayerComposition.h"
|
||||||
|
|
Loading…
Reference in a new issue