diff --git a/src/AtlasLayerCombo.h b/src/AtlasLayerCombo.h index 8e37f7a..cfcebd0 100644 --- a/src/AtlasLayerCombo.h +++ b/src/AtlasLayerCombo.h @@ -35,6 +35,7 @@ class AtlasLayerCombo { virtual void update() = 0; virtual void careForChild(shared_ptr layer) = 0; virtual const ComboIdentifier & getIdentifier() const = 0; + virtual void setVFlip(VFlipState vFlipState) = 0; bool operator==(const AtlasLayerCombo & other) const { return (this->getIdentifier() == other.getIdentifier()); diff --git a/src/GPUFontAtlasLayerCombo.cpp b/src/GPUFontAtlasLayerCombo.cpp index 01306d6..de76501 100644 --- a/src/GPUFontAtlasLayerCombo.cpp +++ b/src/GPUFontAtlasLayerCombo.cpp @@ -1,18 +1,157 @@ #include "GPUFontAtlasLayerCombo.h" +#include "Utils.h" +#include "ofColor.h" namespace ofxVariableLab { void GPUFontAtlasLayerCombo::setup(const ComboIdentifier & identifier){ + this->identifier = identifier; + #ifdef TARGET_EMSCRIPTEN + string shaderDir = "data/ofxGPUFont/shaders/DEBUG_ES3"; + #else + string shaderDir = "data/ofxGPUFont/shaders/GL3"; + #endif + shaderCatalog = std::make_unique (shaderDir); + //backgroundShader = shaderCatalog->get("background"); + fontShader = shaderCatalog->get("font"); + + { + FT_Error error = FT_Init_FreeType(&library); + if(error){ + std::cerr << "ERROR: failed to initialize FreeType" << std::endl; + ofExit(); + } + } + currentFontPath = "data/celines-fonts/Version-2-var.ttf"; + mainText = "whatever"; + ofxGPUFont::tryUpdateMainFont(library, + currentFontPath, + mainText, + font, + bb); + + font->listFontVariationAxes(fontVariationAxesParameters, library); + cout << currentFontPath << " : fontVariationAxes :" << endl; + for(const auto & axis : fontVariationAxesParameters){ + cout << std::fixed << std::setprecision(10) << axis.name << " :\n" + << "\tmin: " << std::to_string(axis.minValue) + << "\tmax: " << std::to_string(axis.maxValue) + << "\tdefault: " << std::to_string(axis.defaultValue) << endl; + fontVariationAxes.push_back({axis.name, axis.defaultValue}); + } + + transform = Transform(); + + auto & r = ofGetCurrentRenderer(); + cout << "Render type " << r->getType() << endl; } void GPUFontAtlasLayerCombo::update(){ + float animationSpeed = ofMap(sin(ofGetElapsedTimef() * 0.01), -1, 1, 0.0, 2); + float threshold = 5.0; + for(int i = 0; i < fontVariationAxes.size(); i++){ + ofxGPUFont::Font::FontVariationAxis & axis = fontVariationAxes[i]; + ofxGPUFont::Font::FontVariationAxisParameters & axisParams = fontVariationAxesParameters[i]; + double newValue = ofMap(sin(ofGetElapsedTimef() * animationSpeed), + -1, 1, + axisParams.minValue, axisParams.maxValue); + if(abs(newValue - axis.value) > threshold){ + font->setFontVariationAxis(library, axis.name, newValue); + axis.value = newValue; + font->prepareGlyphsForText(mainText, true); + } + } } void GPUFontAtlasLayerCombo::careForChild(shared_ptr layer){ } const ComboIdentifier & GPUFontAtlasLayerCombo::getIdentifier() const { return identifier; } +void GPUFontAtlasLayerCombo::setVFlip(VFlipState vFlipState){ + vFlip = vFlipState; +} const vector > & GPUFontAtlasLayerCombo::getLayers(){ return layers; } +void GPUFontAtlasLayerCombo::draw(){ + GLuint location; + + int width = ofGetWidth(); + int height = ofGetHeight(); + + //ofClear(125, 255, 125, 255); + + glm::mat4 projection = transform.getProjectionMatrix((float)width / height); + glm::mat4 view = transform.getViewMatrix(); + glm::mat4 model = glm::mat4(1.0f); + + //{ // Draw background. + //GLuint program = backgroundShader->program; + //glUseProgram(program); + //glBindVertexArray(emptyVAO); + //glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + //glBindVertexArray(0); + //glUseProgram(0); + //} + + // Uses premultiplied-alpha. + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + int currentProgram; + glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); + + float cx = FLT_MAX; + float cy = FLT_MAX; + if(font){ + fontShaderProgram = fontShader->program; + glUseProgram(fontShaderProgram); + + font->program = fontShaderProgram; + font->drawSetup(); + + location = glGetUniformLocation(fontShaderProgram, "projection"); + glUniformMatrix4fv(location, 1, false, glm::value_ptr(projection)); + + location = glGetUniformLocation(fontShaderProgram, "view"); + glUniformMatrix4fv(location, 1, false, glm::value_ptr(view)); + location = glGetUniformLocation(fontShaderProgram, "model"); + glUniformMatrix4fv(location, 1, false, glm::value_ptr(model)); + float z = 0; + location = glGetUniformLocation(fontShaderProgram, "z"); + glUniform1f(location, z); + + location = glGetUniformLocation(fontShaderProgram, "color"); + glUniform4f(location, 1.0f, 0.0f, 1.0f, 1.0f); + + location = glGetUniformLocation(fontShaderProgram, "antiAliasingWindowSize"); + glUniform1f(location, (float)antiAliasingWindowSize); + location = glGetUniformLocation(fontShaderProgram, "enableSuperSamplingAntiAliasing"); + glUniform1i(location, enableSuperSamplingAntiAliasing); + location = glGetUniformLocation(fontShaderProgram, "enableControlPointsVisualization"); + glUniform1i(location, enableControlPointsVisualization); + + + cx = 0.5f * (bb.minX + bb.maxX); + cy = 0.5f * (bb.minY + bb.maxY); + //ofRectangle rectangle(0, 0, width, height); + //ofDrawRectangle(rectangle); + font->draw(-cx, -cy, 0, mainText); + glUseProgram(currentProgram); + } + + glDisable(GL_BLEND); + + ofDrawBitmapStringHighlight( + "this is where your font could be" + , -cx, -cy, ofFloatColor::pink, ofFloatColor::black); + + ofDrawBitmapStringHighlight( + "fps: " + ofToString(ofGetFrameRate()) + "\n" + + "font: " + currentFontPath + "\n" + + "cx: " + ofToString(cx) + "\n" + + "cy: " + ofToString(cy) + "\n" + , 20, 20); +} } diff --git a/src/GPUFontAtlasLayerCombo.h b/src/GPUFontAtlasLayerCombo.h index 3bd2dce..5d52583 100644 --- a/src/GPUFontAtlasLayerCombo.h +++ b/src/GPUFontAtlasLayerCombo.h @@ -1,24 +1,76 @@ #pragma once +#include "Utils.h" #include "ofMain.h" #include "AtlasLayerCombo.h" #include "GPUFontLayer.h" +#ifdef TARGET_EMSCRIPTEN + #include + #include +#endif namespace ofxVariableLab { class GPUFontAtlasLayerCombo : public AtlasLayerCombo { + struct Transform { + float fovy = glm::radians(60.0f); + float distance = 0.42f; + glm::mat3 rotation = glm::mat3(1.0f); + glm::vec3 position = glm::vec3(0.0f); + + glm::mat4 getProjectionMatrix(float aspect){ + return glm::perspective( /* fovy = */ glm::radians(60.0f), aspect, 0.002f, 12.000f); + } + + glm::mat4 getViewMatrix(){ + auto translation = glm::translate(position); + return glm::lookAt(glm::vec3(0, 0, distance), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)) * glm::mat4(rotation) * translation; + } + }; public: void setup(const ComboIdentifier & identifier) override; void update() override; void careForChild(shared_ptr layer) override; const ComboIdentifier & getIdentifier() const override; + void setVFlip(VFlipState vFlipState) override; + const vector > & getLayers(); + void draw(); + shared_ptr font; private: FT_Library library; vector > layers; - shared_ptr gpuFontShader; ComboIdentifier identifier; +// Empty VAO used when the vertex shader has no input and only uses gl_VertexID, +// because OpenGL still requires a non-zero VAO to be bound for the draw call. + GLuint emptyVAO; + + std::unique_ptr shaderCatalog; + //std::shared_ptr backgroundShader; + std::shared_ptr fontShader; + + ofxGPUFont::Font::BoundingBox bb; + + Transform transform; + + string currentFontPath; + string mainText; +// Size of the window (in pixels) used for 1-dimensional anti-aliasing along each rays. +// 0 - no anti-aliasing +// 1 - normal anti-aliasing +// >=2 - exaggerated effect + int antiAliasingWindowSize = 1; +// Enable a second ray along the y-axis to achieve 2-dimensional anti-aliasing. + bool enableSuperSamplingAntiAliasing = true; +// Draw control points for debugging (green - on curve, magenta - off curve). + bool enableControlPointsVisualization = false; + GLuint fontShaderProgram; + + std::vector fontVariationAxesParameters; + std::vector fontVariationAxes; + + VFlipState vFlip; bool isDirty = false; }; diff --git a/src/LayerComposition.cpp b/src/LayerComposition.cpp index 6fc3f07..4975634 100644 --- a/src/LayerComposition.cpp +++ b/src/LayerComposition.cpp @@ -8,6 +8,10 @@ namespace ofxVariableLab { void LayerComposition::setup(){ + auto combo = make_shared (); + ComboIdentifier comboIdentifier = {"lol", Layer::GPUFONT}; + combo->setup(comboIdentifier); + atlasLayerCombos[comboIdentifier] = combo; } void LayerComposition::update(){ @@ -71,7 +75,16 @@ shared_ptr LayerComposition::getLayer(const LayerID & layerID){ void LayerComposition::draw() const { for(const auto & layer_it : layers){ - layer_it.second->draw(); + if(layer_it.second->getType() == Layer::MSDFGEN){ + layer_it.second->draw(glm::vec3(200, 200, 0)); + } + } + for(const auto & combo_it : atlasLayerCombos){ + if(combo_it.first.type == Layer::GPUFONT){ + auto combo = + static_pointer_cast (combo_it.second); + combo->draw(); + } } } diff --git a/src/MsdfAtlasLayerCombo.cpp b/src/MsdfAtlasLayerCombo.cpp index 7cc3a15..0fd33db 100644 --- a/src/MsdfAtlasLayerCombo.cpp +++ b/src/MsdfAtlasLayerCombo.cpp @@ -1,4 +1,5 @@ #include "MsdfAtlasLayerCombo.h" +#include "Utils.h" namespace ofxVariableLab { @@ -49,6 +50,13 @@ const ComboIdentifier & MsdfAtlasLayerCombo::getIdentifier() const { return identifier; } +void MsdfAtlasLayerCombo::setVFlip(VFlipState vFlipState){ + vFlip = vFlipState; + for(const auto & layer : layers){ + layer->setVFlip(vFlip); + } +} + const ofImage & MsdfAtlasLayerCombo::getAtlasImage(){ return atlas->getAtlasImage(); } diff --git a/src/MsdfAtlasLayerCombo.h b/src/MsdfAtlasLayerCombo.h index a07d1c8..6615eff 100644 --- a/src/MsdfAtlasLayerCombo.h +++ b/src/MsdfAtlasLayerCombo.h @@ -2,6 +2,7 @@ #include "AtlasLayerCombo.h" #include "MsdfLayer.h" +#include "Utils.h" namespace ofxVariableLab { class MsdfAtlasLayerCombo : public AtlasLayerCombo { @@ -10,6 +11,7 @@ class MsdfAtlasLayerCombo : public AtlasLayerCombo { void update() override; void careForChild(shared_ptr layer) override; const ComboIdentifier & getIdentifier() const override; + void setVFlip(VFlipState vFlipState) override; const ofImage & getAtlasImage(); string getAtlasImagePath(); shared_ptr getLayer(); // TODO: is this used @@ -19,6 +21,7 @@ class MsdfAtlasLayerCombo : public AtlasLayerCombo { vector > layers; vector glyphGeometries; shared_ptr msdfShader; + VFlipState vFlip; ComboIdentifier identifier; bool isDirty = false; };