#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 & 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 , double> kerning = fontGeometry.getKerning(); ofxMsdfgen::GlyphGeometry gg_previous = atlas->getGlyphGeometry(c); std::map , double>::const_iterator it = kerning.find(std::make_pair (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 _shader){ shader = _shader; } shared_ptr 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 _atlas){ atlas = _atlas; // TODO: this does not seem proper propsBuffer[0].fontSize_px = atlas->settings.scale; } shared_ptr 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; } }