From e6a1ecd971550398250587646aaad8de1caf05bd Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Thu, 6 Apr 2023 11:17:22 +0200 Subject: [PATCH] make LayerComposition more flexible ... unstable implementation --- src/Layer.cpp | 172 +------------------------ src/Layer.h | 66 +++------- src/LayerComposition.cpp | 119 ++++++++++++++---- src/LayerComposition.h | 87 +++++++++++-- src/MsdfLayer.cpp | 266 +++++++++++++++++++++++++++++++++++++++ src/MsdfLayer.h | 43 +++++++ src/Utils.h | 25 ++++ src/ofxVariableLab.h | 2 + 8 files changed, 527 insertions(+), 253 deletions(-) create mode 100644 src/MsdfLayer.cpp create mode 100644 src/MsdfLayer.h create mode 100644 src/Utils.h diff --git a/src/Layer.cpp b/src/Layer.cpp index b112fc5..b256135 100644 --- a/src/Layer.cpp +++ b/src/Layer.cpp @@ -1,173 +1,3 @@ #include "Layer.h" -#include "conversion.h" -#include "ofAppRunner.h" -#include "ofGraphics.h" -#include "ofUtils.h" -namespace ofxVariableLab { - -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 & 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 (previous_c); - //msdf_atlas::unicode_t b = static_cast (c); - 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 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; -} -} +// Layer is virtual diff --git a/src/Layer.h b/src/Layer.h index 0754a97..e960600 100644 --- a/src/Layer.h +++ b/src/Layer.h @@ -1,25 +1,20 @@ #pragma once +#include "Atlas.h" #include "ofMain.h" //uuid #include "random_id.h" #include "ofxMsdfgen.h" +#include namespace ofxVariableLab { - class Layer { - protected: - Layer(); public: - ~Layer(); - enum TransformOrigin { - TOP_LEFT, - TOP_RIGHT, - CENTER, - BOTTOM_LEFT, - BOTTOM_RIGHT + enum Type { + MSDFGEN = 0, + GPUFONT }; struct Props { float x = 0; @@ -27,54 +22,31 @@ class Layer { float rotation = 0; float fontSize_px = 24; float * color[4]; - TransformOrigin transformOrigin = TransformOrigin::CENTER; bool mirror_x = false; float mirror_x_distance = 0; bool mirror_y = false; float mirror_y_distance = 0; float letterDelay = 0; - string text = "Variable Font Editor"; + string text = "abcdefghijklmnoprstuvqxyzABUIWERJSD"; }; struct Settings { 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; - void setProps(const Props & props); - const Props & getProps() const; - //void setProps(float _x, - //float _y, - //float _rotation, - //float _wght, - //float _fontSize_px, - //float * _color[4], - //int _transformOrigin, - //bool _mirror_x, - //float _mirror_x_distance, - //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 propsBuffer; - shared_ptr 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 atlas; + virtual void drawCharacter(const char character, + glm::vec3 position = glm::vec3(0, 0, 0), + ofxMsdfgen::FontVariation fontVariation = ofxMsdfgen::FontVariation()) const = 0; + virtual void setProps(const Props & props) = 0; + virtual const Props & getProps() const = 0; + virtual void clearPropsBuffer() = 0; + virtual void setId(const string & id) = 0; + virtual const string & getId() = 0; + virtual void setShader(shared_ptr _shader) = 0; + virtual shared_ptr getShader() const = 0; + virtual const Type & getType() const = 0; }; } diff --git a/src/LayerComposition.cpp b/src/LayerComposition.cpp index 714f8de..eef379f 100644 --- a/src/LayerComposition.cpp +++ b/src/LayerComposition.cpp @@ -1,18 +1,26 @@ #include "LayerComposition.h" +#include "Atlas.h" +#include "MsdfLayer.h" #include "ofUtils.h" #include namespace ofxVariableLab { -void LayerComposition::setup(){ - ofxMsdfgen::AtlasSettings settings; +void MsdfAtlasLayerCombo::setup(const ComboIdentifier & layerIdentifier){ + this->identifier = layerIdentifier; + ofxMsdfgen::AtlasSettings atlasSettings; //settings.characters = "ABCDEFGHIJKL"; - settings.scale = 64; - settings.characters = ""; + atlasSettings.scale = 64; + atlasSettings.minimumScale = 64; + atlasSettings.characters = ""; + //string fontName = "RobotoFlex.ttf"; //string fontPath = "data/fonts/" + fontName; //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-3-var.ttf"; + //string fontPath = "data/celines-fonts/Version-4-var.ttf"; //string fontPath = "data/celines-fonts/Alfarn2.otf"; //string fontPath = "data/celines-fonts/Cottagecore.ttf"; atlas = make_shared (); @@ -24,33 +32,92 @@ void LayerComposition::setup(){ msdfShader->load("ofxMsdfgen/shaders/mix/GL3/shader"); #endif - auto layer = make_unique (); - 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 (atlas->getAtlasImage()); - glyphGeometries = atlas->getGlyphGeometries(); - + atlas->setup(fontPath, atlasSettings); } -void LayerComposition::update(){ -} - -void LayerComposition::draw() const { - for(const auto & layer : layers){ - layer->draw(glm::vec3(400, 200, 0)); +void MsdfAtlasLayerCombo::update(){ + if(isDirty){ + atlas->generate(); + isDirty = false; } } -shared_ptr LayerComposition::getAtlasImage(){ - return atlasImage; +void MsdfAtlasLayerCombo::careForChild(shared_ptr layer){ + shared_ptr msdfLayer = dynamic_pointer_cast (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 & 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 (); + combo->setup(identifier); // TODO: add here text and variations + auto layer = make_shared (); + 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 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)); + } } } diff --git a/src/LayerComposition.h b/src/LayerComposition.h index a761837..9fb9644 100644 --- a/src/LayerComposition.h +++ b/src/LayerComposition.h @@ -1,29 +1,98 @@ #pragma once +#include "Utils.h" #include "ofMain.h" #include "ofxMsdfgen.h" #include "Layer.h" +#include "MsdfLayer.h" +#include "Utils.h" +#include #include 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) = 0; + virtual const ComboIdentifier & getIdentifier() const = 0; + + bool operator==(const AtlasLayerCombo & other) const { + return (this->getIdentifier() == other.getIdentifier()); + } +}; +} +namespace std { +template <> +struct hash { + 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 { + 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) override; + const ComboIdentifier & getIdentifier() const override; + shared_ptr atlas; + + private: + vector glyphGeometries; + shared_ptr msdfShader; + ComboIdentifier identifier; + bool isDirty = false; +}; + class LayerComposition { public: void setup(); void update(); void draw() const; - shared_ptr getAtlasImage(); - #ifdef TARGET_EMSCRIPTEN - #else - #endif + void addLayer(const ComboIdentifier & identifier, + const string & text, + const std::vector & variations); private: - shared_ptr atlas; - shared_ptr atlasImage; - vector glyphGeometries; - shared_ptr msdfShader; - vector > layers; + vector > layers; + unordered_map > atlasLayerCombos; + //unordered_map > layers; }; } diff --git a/src/MsdfLayer.cpp b/src/MsdfLayer.cpp new file mode 100644 index 0000000..c2c620b --- /dev/null +++ b/src/MsdfLayer.cpp @@ -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 & 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 , 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, + 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 _shader){ + shader = _shader; +} +shared_ptr MsdfLayer::getShader() const { + return shader; +} +const Layer::Type & MsdfLayer::getType() const { + return type; +} + +void MsdfLayer::setAtlas(shared_ptr _atlas){ + atlas = _atlas; +} +shared_ptr 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; +} +} diff --git a/src/MsdfLayer.h b/src/MsdfLayer.h new file mode 100644 index 0000000..398b20f --- /dev/null +++ b/src/MsdfLayer.h @@ -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 _shader) override; + shared_ptr getShader() const override; + const Type & getType() const override; + + void setAtlas(shared_ptr _atlas); + shared_ptr getAtlas() const; + + shared_ptr atlas; + + Settings settings; + std::deque propsBuffer; + shared_ptr shader; + /// \brief are props updated but not drawn yet + bool isDirty = true; + /// \brief hashed id + string id; + + private: + Layer::Type type = MSDFGEN; +}; +} diff --git a/src/Utils.h b/src/Utils.h new file mode 100644 index 0000000..017fe3b --- /dev/null +++ b/src/Utils.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace ofxVariableLab { + +struct FontVariationAxis { + char * name; + float minValue; + float maxValue; + float defaultValue; +}; + +struct FontVariation { + char * name; + float value; +}; + +template +inline void hash_combine(std::size_t & seed, const T & v){ + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +} diff --git a/src/ofxVariableLab.h b/src/ofxVariableLab.h index 680ddf9..5679503 100644 --- a/src/ofxVariableLab.h +++ b/src/ofxVariableLab.h @@ -1,5 +1,7 @@ #pragma once #include "random_id.h" +#include "Utils.h" #include "Layer.h" +#include "MsdfLayer.h" #include "LayerComposition.h"