ofxVariableLab/src/MsdfLayer.cpp

472 lines
17 KiB
C++

#include "MsdfLayer.h"
#include "Atlas.h"
#include "Utils.h"
#include "fwd.hpp"
#include "ofGraphics.h"
#include "ofGraphicsConstants.h"
#include "ofUtils.h"
namespace ofxVariableLab {
void MsdfLayer::setup(const LayerSettings & settings){
this->settings = settings;
if(id == ""){
id = "layer-" + ofToString(Layer::n_layers);
n_layers++;
}
innerNode.setParent(outerNode);
}
void MsdfLayer::update(){
}
void MsdfLayer::draw(glm::vec3 position){
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);
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);
}
//if(settings.vFlip){
//ofTranslate(0, -1 * pt * magic, 0);
//}else{
//ofTranslate(0, -1 * h, 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,
glm::vec4 color,
float rotation,
float scale,
ofxVariableLab::FontVariation fontVariation){
const ofImage & atlasImage = atlas->getAtlasImage();
ofDisableAlphaBlending();
ofEnableDepthTest();
scale *= scaleFactor;
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;
ofxMsdfgen::FontVariation fv{
fontVariation.name,
fontVariation.value
};
bool success = atlas->getGlyphGeometryPair(character,
fv,
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));
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);
}
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();
uboParameters.unitRange = unitRange;
uboParameters.fontColor = color;
uboParameters.translation_a = translation_a;
uboParameters.translation_b = translation_b;
uboParameters.scale_a = scale_a;
uboParameters.scale_b = scale_b;
uboParameters.mix = mix;
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboName);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UboParameters), &uboParameters);
ofRotateDeg(rotation, 0, 0, 1);
atlasImage.draw(0, 0, w * scale, h * scale);
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 LayerType & MsdfLayer::getType() const {
return type;
}
void MsdfLayer::setVFlip(const VFlipState vFlip){
this->vFlip = vFlip;
}
bool MsdfLayer::isDirtyDirty() const {
return isDirty;
}
void MsdfLayer::setDirtyDirty(bool dirtyDirty){
isDirty = dirtyDirty;
}
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;
}
ofNode & MsdfLayer::getOuterNode(){
return outerNode;
}
ofNode & MsdfLayer::getInnerNode(){
return innerNode;
}
const Layer::BoundingBox & MsdfLayer::getBoundingBox(){
return this->boundingBox;
}
void MsdfLayer::setBoundingBox(const Layer::BoundingBox & boundingBox){
this->boundingBox = boundingBox;
}
void MsdfLayer::collectCharacter(const char character,
const ofNode & node,
glm::vec4 color,
ofxVariableLab::FontVariation fontVariation){
const ofImage & atlasImage = atlas->getAtlasImage();
ofNode n = node;
n.setScale(n.getScale() * scaleFactor);
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);
float mix = -1;
ofxMsdfgen::GlyphGeometry gg_a;
ofxMsdfgen::GlyphGeometry gg_b;
ofxMsdfgen::FontVariation fv{
fontVariation.name,
fontVariation.value
};
bool success = atlas->getGlyphGeometryPair(character,
fv,
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;
}
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));
getVFlip(settings.vFlipBehaviour,
ofGetCurrentOrientationMatrix(),
vFlip);
if(vFlip == V_FLIP_OFF){
n.move(pl * magic, (pt * magic) + (-1 * h), 0.0f);
}else{
n.move(pl * magic, -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));
BufferVertex v[4];
glm::vec4 p0 = n.getGlobalTransformMatrix() * glm::vec4(0, 0, 0, 1);
glm::vec4 p1 = n.getGlobalTransformMatrix() * glm::vec4(w, 0, 0, 1);
glm::vec4 p2 = n.getGlobalTransformMatrix() * glm::vec4(w, h, 0, 1);
glm::vec4 p3 = n.getGlobalTransformMatrix() * glm::vec4(0, h, 0, 1);
glm::vec2 uv0_a = glm::vec2();
glm::vec2 uv0_b = glm::vec2();
glm::vec2 uv1_a = glm::vec2();
glm::vec2 uv1_b = glm::vec2();
glm::vec2 uv2_a = glm::vec2();
glm::vec2 uv2_b = glm::vec2();
glm::vec2 uv3_a = glm::vec2();
glm::vec2 uv3_b = glm::vec2();
vertices.push_back(BufferVertex{
{p0.x, p0.y, p0.z, p0.w},
{uv0_a.x, uv0_a.y},
{uv0_b.x, uv0_b.y}
});
vertices.push_back(BufferVertex{
{p1.x, p1.y, p1.z, p1.w},
{uv1_a.x, uv1_a.y},
{uv1_b.x, uv1_b.y}
});
vertices.push_back(BufferVertex{
{p2.x, p2.y, p2.z, p2.w},
{uv2_a.x, uv2_a.y},
{uv2_b.x, uv2_b.y}
});
vertices.push_back(BufferVertex{
{p3.x, p3.y, p3.z, p3.w},
{uv3_a.x, uv3_a.y},
{uv3_b.x, uv3_b.y}
});
CharacterDrawParameters characterDrawParameters;
characterDrawParameters.unitRange = unitRange;
characterDrawParameters.fontColor = color;
characterDrawParameters.bgColor = uboParameters.bgColor;
characterDrawParameters.translation_a = translation_a;
characterDrawParameters.translation_b = translation_b;
characterDrawParameters.scale_a = scale_a;
characterDrawParameters.scale_b = scale_b;
characterDrawParameters.mix = mix;
parameters.push_back(characterDrawParameters);
}
void MsdfLayer::setAtlas(shared_ptr <ofxMsdfgen::Atlas> _atlas){
atlas = _atlas;
// TODO: this does not seem proper
propsBuffer[0].fontSize_px = atlas->settings.scale;
}
shared_ptr <ofxMsdfgen::Atlas> MsdfLayer::getAtlas() const {
return atlas;
}
void MsdfLayer::setProps(const Props & props){
// 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);
}
int maxPropsBufferSize = max(0, int(props.letterDelay * settings.letterDelayRatio * props.text.size()));
cout << "maxPropsBufferSize: " << ofToString(maxPropsBufferSize) << endl;
if(maxPropsBufferSize > 0){
propsBuffer.push_front(props);
}
while(propsBuffer.size() > maxPropsBufferSize){
propsBuffer.pop_back();
}
lastProps = props;
}
const Layer::Props & MsdfLayer::getProps(float delay_seconds){
if(delay_seconds != 0 && propsBuffer.size() > 0){
int index = max(0, min(int(propsBuffer.size() - 1), int(delay_seconds * settings.letterDelayRatio)));
return propsBuffer[index]; // gets newest
}else{
return lastProps;
}
}
void MsdfLayer::clearPropsBuffer(){
propsBuffer.clear();
}
void MsdfLayer::setId(const LayerID & id){
this->id = id;
}
const LayerID & MsdfLayer::getId(){
return id;
}
}