2023-04-06 11:17:22 +02:00
|
|
|
#include "MsdfLayer.h"
|
2023-04-07 16:17:07 +02:00
|
|
|
#include "Atlas.h"
|
2023-04-07 09:48:37 +02:00
|
|
|
#include "Utils.h"
|
|
|
|
#include "fwd.hpp"
|
|
|
|
#include "ofGraphics.h"
|
|
|
|
#include "ofUtils.h"
|
2023-04-06 11:17:22 +02:00
|
|
|
|
|
|
|
namespace ofxVariableLab {
|
|
|
|
|
2023-04-07 16:17:07 +02:00
|
|
|
void MsdfLayer::setup(const LayerSettings & settings){
|
2023-04-06 11:17:22 +02:00
|
|
|
this->settings = settings;
|
2023-04-07 16:17:07 +02:00
|
|
|
if(id == ""){
|
2023-04-14 16:55:15 +02:00
|
|
|
id = "layer-" + ofToString(Layer::n_layers);
|
2023-04-07 16:17:07 +02:00
|
|
|
n_layers++;
|
|
|
|
}
|
2023-04-18 14:58:09 +02:00
|
|
|
innerNode.setParent(outerNode);
|
2023-04-06 11:17:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void MsdfLayer::update(){
|
2023-04-17 20:14:39 +02:00
|
|
|
if(propsBuffer.size() > 0){
|
|
|
|
color = glm::vec4(propsBuffer[0].color[0],
|
|
|
|
propsBuffer[0].color[1],
|
|
|
|
propsBuffer[0].color[2],
|
|
|
|
propsBuffer[0].color[3]);
|
|
|
|
}
|
2023-04-06 11:17:22 +02:00
|
|
|
}
|
|
|
|
|
2023-04-07 09:48:37 +02:00
|
|
|
void MsdfLayer::draw(glm::vec3 position){
|
2023-04-06 11:17:22 +02:00
|
|
|
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;
|
|
|
|
ofSetColor(ofFloatColor(1, 1, 1, 1));
|
|
|
|
ofTranslate(pl * magic, 0, 0);
|
2023-04-07 09:48:37 +02:00
|
|
|
getVFlip(settings.vFlipBehaviour,
|
|
|
|
ofGetCurrentOrientationMatrix(),
|
|
|
|
vFlip);
|
2023-04-12 09:28:47 +02:00
|
|
|
|
2023-04-07 09:48:37 +02:00
|
|
|
if(vFlip == V_FLIP_OFF){
|
|
|
|
ofTranslate(pl * magic, (pt * magic) + (-1 * h), 0);
|
|
|
|
}else{
|
|
|
|
ofTranslate(pl * magic, -1 * pt * magic, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//if(settings.vFlip){
|
2023-04-06 11:17:22 +02:00
|
|
|
//ofTranslate(0, -1 * pt * magic, 0);
|
2023-04-07 09:48:37 +02:00
|
|
|
//}else{
|
|
|
|
//ofTranslate(0, -1 * h, 0);
|
|
|
|
//ofTranslate(0, 1 * pt * magic, 0);
|
|
|
|
//}
|
|
|
|
|
2023-04-06 11:17:22 +02:00
|
|
|
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,
|
2023-04-07 16:17:07 +02:00
|
|
|
glm::vec4 color,
|
|
|
|
float rotation,
|
2023-04-08 13:40:17 +02:00
|
|
|
float scale,
|
2023-04-07 16:17:07 +02:00
|
|
|
ofxVariableLab::FontVariation fontVariation){
|
2023-04-06 11:17:22 +02:00
|
|
|
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->setUniform2f("unitRange", unitRange);
|
|
|
|
shader->end();
|
|
|
|
|
|
|
|
ofPushMatrix();
|
|
|
|
ofTranslate(position);
|
|
|
|
ofPushStyle();
|
|
|
|
|
|
|
|
float mix = -1;
|
|
|
|
ofxMsdfgen::GlyphGeometry gg_a;
|
|
|
|
ofxMsdfgen::GlyphGeometry gg_b;
|
|
|
|
|
2023-04-07 16:17:07 +02:00
|
|
|
ofxMsdfgen::FontVariation fv{
|
|
|
|
fontVariation.name,
|
|
|
|
fontVariation.value
|
|
|
|
};
|
|
|
|
|
2023-04-06 11:17:22 +02:00
|
|
|
bool success = atlas->getGlyphGeometryPair(character,
|
2023-04-07 16:17:07 +02:00
|
|
|
fv,
|
2023-04-06 11:17:22 +02:00
|
|
|
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));
|
2023-04-07 16:17:07 +02:00
|
|
|
getVFlip(settings.vFlipBehaviour,
|
|
|
|
ofGetCurrentOrientationMatrix(),
|
|
|
|
vFlip);
|
|
|
|
if(vFlip == V_FLIP_OFF){
|
|
|
|
ofTranslate(pl * magic, (pt * magic) + (-1 * h), 0);
|
|
|
|
}else{
|
|
|
|
ofTranslate(pl * magic, -1 * pt * magic, 0);
|
|
|
|
}
|
2023-04-06 11:17:22 +02:00
|
|
|
|
|
|
|
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();
|
2023-04-07 16:17:07 +02:00
|
|
|
shader->setUniform4f("fontColor", color);
|
2023-04-06 11:17:22 +02:00
|
|
|
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);
|
2023-04-08 17:15:57 +02:00
|
|
|
ofRotateDeg(rotation, 0, 0, 1);
|
2023-04-08 13:40:17 +02:00
|
|
|
atlasImage.draw(0, 0, w * scale, h * scale);
|
2023-04-06 11:17:22 +02:00
|
|
|
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;
|
|
|
|
}
|
2023-04-16 17:20:54 +02:00
|
|
|
const LayerType & MsdfLayer::getType() const {
|
2023-04-06 11:17:22 +02:00
|
|
|
return type;
|
|
|
|
}
|
2023-04-11 13:17:30 +02:00
|
|
|
void MsdfLayer::setVFlip(const VFlipState vFlip){
|
|
|
|
this->vFlip = vFlip;
|
|
|
|
}
|
2023-04-14 16:55:15 +02:00
|
|
|
bool MsdfLayer::isDirtyDirty() const {
|
|
|
|
return isDirty;
|
|
|
|
}
|
|
|
|
void MsdfLayer::setDirtyDirty(bool dirtyDirty){
|
|
|
|
isDirty = dirtyDirty;
|
|
|
|
}
|
2023-04-16 17:20:54 +02:00
|
|
|
bool MsdfLayer::wantsNewMom(){
|
|
|
|
return notHappyWithMom;
|
|
|
|
}
|
|
|
|
void MsdfLayer::isWithNewMom(){
|
|
|
|
notHappyWithMom = false;
|
|
|
|
}
|
|
|
|
const ComboIdentifier & MsdfLayer::getMomsComboIdentifier() const {
|
|
|
|
return momsComboIdentifier;
|
|
|
|
}
|
|
|
|
void MsdfLayer::setMomsComboIdentifier(const ComboIdentifier & identifier){
|
|
|
|
momsComboIdentifier = identifier;
|
|
|
|
}
|
2023-04-18 14:58:09 +02:00
|
|
|
ofNode & MsdfLayer::getOuterNode(){
|
|
|
|
return outerNode;
|
|
|
|
}
|
|
|
|
ofNode & MsdfLayer::getInnerNode(){
|
|
|
|
return innerNode;
|
|
|
|
}
|
2023-04-06 11:17:22 +02:00
|
|
|
void MsdfLayer::setAtlas(shared_ptr <ofxMsdfgen::Atlas> _atlas){
|
|
|
|
atlas = _atlas;
|
2023-04-08 13:40:17 +02:00
|
|
|
// TODO: this does not seem proper
|
|
|
|
propsBuffer[0].fontSize_px = atlas->settings.scale;
|
2023-04-06 11:17:22 +02:00
|
|
|
}
|
|
|
|
shared_ptr <ofxMsdfgen::Atlas> MsdfLayer::getAtlas() const {
|
|
|
|
return atlas;
|
|
|
|
}
|
|
|
|
void MsdfLayer::setProps(const Props & props){
|
2023-04-14 16:55:15 +02:00
|
|
|
// TODO: for now only check text,
|
|
|
|
// but we should of course check also variations
|
|
|
|
if(propsBuffer.size() == 0 || props.text != propsBuffer[0].text){
|
|
|
|
setDirtyDirty(true);
|
|
|
|
}
|
2023-04-06 11:17:22 +02:00
|
|
|
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];
|
|
|
|
}
|
2023-04-17 20:14:39 +02:00
|
|
|
const glm::vec4 & MsdfLayer::getColor() const {
|
|
|
|
return color;
|
|
|
|
}
|
2023-04-06 11:17:22 +02:00
|
|
|
void MsdfLayer::clearPropsBuffer(){
|
|
|
|
propsBuffer.clear();
|
|
|
|
}
|
2023-04-07 16:17:07 +02:00
|
|
|
void MsdfLayer::setId(const LayerID & id){
|
2023-04-06 11:17:22 +02:00
|
|
|
this->id = id;
|
|
|
|
}
|
2023-04-07 16:17:07 +02:00
|
|
|
const LayerID & MsdfLayer::getId(){
|
2023-04-06 11:17:22 +02:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|