#include "GPUFontAtlasLayerCombo.h" #include "GPUFontLayer.h" #include "Utils.h" #include "font.hpp" #include "ofAppRunner.h" #include "ofColor.h" #include "ofEvents.h" #include "ofGraphics.h" #include "ofRectangle.h" #include "ofUtils.h" #include "quaternion.hpp" #include namespace ofxVariableLab { void GPUFontAtlasLayerCombo::setup(const ComboIdentifier & identifier, AtlasLayerComboSettings settings){ this->identifier = identifier; this->settings = static_cast (settings); #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(); } } ofxGPUFont::initializeFont(library, this->identifier.fontPath, font, this->settings.gpuTextureOffset); font->listFontVariationAxes(fontVariationAxesParameters, library); //cout << this->identifier.fontPath << " : 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(); } void GPUFontAtlasLayerCombo::update(){ OFX_PROFILER_FUNCTION(); for(const auto & layer : layers){ layer->update(); if(layer->isDirtyDirty()){ isDirty = true; break; } } if(isDirty){ std::string text = ""; totalCharacters = 0; std::vector _variationText; for(const auto & layer : layers){ std::string layerText = layer->getProps().text; int mirrorMultiplier = 1; if(layer->getProps().mirror_x){ mirrorMultiplier += 1; } if(layer->getProps().mirror_y){ mirrorMultiplier += 1; } if(layer->getProps().mirror_xy){ mirrorMultiplier += 1; } totalCharacters += layerText.length() * mirrorMultiplier; _variationText.insert(_variationText.end(), layer->getVariationText().begin(), layer->getVariationText().end()); text += layerText; layer->setDirtyDirty(false); // technically not clean yet // but this is synchronous // and will happen, so we can avoid // another loop } removeDuplicateCharacters(text); mainText = text; variationText = std::move(_variationText); font->prepareGlyphsForText(variationText, library, true); isDirty = false; } } void GPUFontAtlasLayerCombo::careForChild(shared_ptr layer){ if(layer->getType() == LayerType::GPUFONT){ shared_ptr gpuFontLayer = static_pointer_cast (layer); gpuFontLayer->setMomsComboIdentifier(identifier); gpuFontLayer->isWithNewMom(); gpuFontLayer->setDirtyDirty(true); std::string oldText = mainText; std::string layerText = gpuFontLayer->getProps().text; std::string text = oldText + layerText; totalCharacters += layerText.length(); removeDuplicateCharacters(text); // check if we added any characters // TODO: check for variation variations if(text.length() != oldText.length()){ mainText = text; isDirty = true; } layers.push_back(std::move(gpuFontLayer)); }else{ ofLogError("GPUFontAtlasLayerCombo::careForChild()") << __LINE__ << ": child is not recognized as Layer::GPUFONT"; } } void GPUFontAtlasLayerCombo::abandonChild(shared_ptr layer){ // TODO: handle removing child text from buffer shared_ptr gpuFontLayer = static_pointer_cast (layer); layers.erase( std::remove_if( layers.begin(), layers.end(), [gpuFontLayer](shared_ptr const & l) { return l == gpuFontLayer; }), layers.end()); isDirty = true; } const ComboIdentifier & GPUFontAtlasLayerCombo::getIdentifier() const { return identifier; } void GPUFontAtlasLayerCombo::setVFlip(VFlipState vFlipState){ vFlip = vFlipState; } bool GPUFontAtlasLayerCombo::hasChildren(){ return layers.size() > 0; } const vector > & GPUFontAtlasLayerCombo::getLayers(){ return layers; } void GPUFontAtlasLayerCombo::draw(int width, int height){ OFX_PROFILER_FUNCTION(); GLuint location; glm::vec2 mouse = glm::vec2(ofGetMouseX(), ofGetMouseY()); //glm::mat4 projection = transform.getProjectionMatrix((float)width / height); glm::mat4 projection = transform.getOrthoProjectionMatrix(width, height, Transform::TOP_LEFT); //Transform::CENTERED); glm::mat4 view = transform.getViewMatrix(); glm::mat4 model = glm::mat4(1.0f); //glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // background color //glClear(GL_COLOR_BUFFER_BIT); // clear background with background color // Uses premultiplied-alpha. ofDisableDepthTest(); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); //ofEnableAlphaBlending(); int currentProgram; glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); //antiAliasingWindowSize = ofMap(ofGetMouseX(), 0, ofGetWidth(), 1, 3); //enableSuperSamplingAntiAliasing = ofGetMouseY() > ofGetHeight() / 2; if(font){ OFX_PROFILER_SCOPE("draw 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, "antiAliasingWindowSize"); glUniform1f(location, (float)antiAliasingWindowSize); location = glGetUniformLocation(fontShaderProgram, "enableSuperSamplingAntiAliasing"); glUniform1i(location, enableSuperSamplingAntiAliasing); location = glGetUniformLocation(fontShaderProgram, "enableControlPointsVisualization"); glUniform1i(location, enableControlPointsVisualization); std::vector vertices; std::vector indices; vertices.resize(totalCharacters * 4); indices.resize(totalCharacters * 6); std::vector outerBoundingBoxes; ofRectangle r; for(const auto & layer : layers){ OFX_PROFILER_SCOPE("draw layer"); float ascender = font->getAscender(layer->getProps().fontSize_px); ofxGPUFont::Font::BoundingBox bb; std::vector bbs; std::vector mirror_bbs; float advanceY = 0; font->collectBoundingBoxes(layer->getVariationText(), layer->getVariationTextAppearance(), bb, bbs, advanceY, true, layer->getProps().fontSize_px, layer->getProps().lineHeight); float lineHeight = font->getLineHeight(layer->getProps().fontSize_px) * layer->getProps().lineHeight; if(layer->getProps().width > 0){ int n_wraps = wrapBoundingBoxes(bbs, layer->getVariationText(), layer->getProps().width, lineHeight); float min_x = FLT_MAX; float min_y = FLT_MAX; float max_x = -FLT_MAX; float max_y = -FLT_MAX; for(const auto & sbb : bbs){ min_x = min(sbb.p0.x, min_x); min_y = min(sbb.p0.y, min_y); max_x = max(sbb.p2.x, max_x); max_y = max(sbb.p2.y, max_y); } bb.p0.x = min_x; bb.p0.y = min_y; bb.p1.x = max_x; bb.p1.y = min_y; bb.p2.x = max_x; bb.p2.y = max_y; bb.p3.x = min_x; bb.p3.y = max_y; if(ofGetFrameNum() % 600 == 0){ cout << "n_wraps: " << ofToString(n_wraps) << endl << "layer->getProps().width: " << ofToString(layer->getProps().width) << endl ; } } glm::vec4 transformOrigin; getAndApplyTransformOrigin(transformOrigin, layer->getOuterNode(), layer->getInnerNode(), bb, ascender, advanceY, layer->getProps()); auto bb_mirror_none = bb; bb_mirror_none.multiply(layer->getInnerNode().getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_none)); //layer->setBoundingBox(bb); ofVboMesh mesh; mesh.addVertices({bb_mirror_none.p0, bb_mirror_none.p1, bb_mirror_none.p2, bb_mirror_none.p3, glm::vec4(layer->getProps().x, layer->getProps().y, 0, 1), transformOrigin }); mesh.addColors({ ofColor::red, ofColor::red, ofColor::red, ofColor::red, ofColor::white, ofColor::green, }); outerBoundingBoxes.push_back(mesh); if(layer->getProps().mirror_x){ auto bbs_mirror_x = bbs; ofNode mirrorOuterNode = layer->getOuterNode(); ofNode mirrorInnerNode = layer->getInnerNode(); mirrorInnerNode.setParent(mirrorOuterNode); mirrorOuterNode.setOrientation(glm::quat(1, 0, 0, 0)); mirrorOuterNode.rotateDeg(layer->getProps().rotation * -1, glm::vec3(0, 0, 1)); mirrorOuterNode.setPosition(transformOrigin); mirrorOuterNode.move(layer->getProps().mirror_x_distance * -1, 0, 0); mirrorOuterNode.setScale(-1, 1, 1); auto bb_mirror_x = bb; bb_mirror_x.multiply(mirrorInnerNode.getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_x)); font->collectVerticesAndIndices(mirrorInnerNode, layer->getVariationTextAppearance(), bbs_mirror_x, vertices, indices); } if(layer->getProps().mirror_y){ auto bbs_mirror_y = bbs; ofNode mirrorOuterNode = layer->getOuterNode(); ofNode mirrorInnerNode = layer->getInnerNode(); mirrorInnerNode.setParent(mirrorOuterNode); mirrorOuterNode.setOrientation(glm::quat(1, 0, 0, 0)); mirrorOuterNode.rotateDeg(layer->getProps().rotation * -1, glm::vec3(0, 0, 1)); mirrorOuterNode.setPosition(transformOrigin); mirrorOuterNode.move(0, layer->getProps().mirror_y_distance * -1, 0); mirrorOuterNode.setScale(1, -1, 1); auto bb_mirror_y = bb; bb_mirror_y.multiply(mirrorInnerNode.getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_y)); font->collectVerticesAndIndices(mirrorInnerNode, layer->getVariationTextAppearance(), bbs_mirror_y, vertices, indices); } if(layer->getProps().mirror_xy){ auto bbs_mirror_xy = bbs; ofNode mirrorOuterNode = layer->getOuterNode(); ofNode mirrorInnerNode = layer->getInnerNode(); mirrorInnerNode.setParent(mirrorOuterNode); mirrorOuterNode.setOrientation(glm::quat(1, 0, 0, 0)); mirrorOuterNode.rotateDeg(layer->getProps().rotation * 1, glm::vec3(0, 0, 1)); mirrorOuterNode.setPosition(transformOrigin); mirrorOuterNode.move(layer->getProps().mirror_x_distance * -1, layer->getProps().mirror_y_distance * -1, 0); mirrorOuterNode.setScale(-1, -1, 1); auto bb_mirror_xy = bb; bb_mirror_xy.multiply(mirrorInnerNode.getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_xy)); font->collectVerticesAndIndices(mirrorInnerNode, layer->getVariationTextAppearance(), bbs_mirror_xy, vertices, indices); } font->collectVerticesAndIndices(layer->getInnerNode(), layer->getVariationTextAppearance(), bbs, vertices, indices); float min_x = FLT_MAX; float max_x = -FLT_MAX; float min_y = FLT_MAX; float max_y = -FLT_MAX; for(const auto & mbb : mirror_bbs){ min_x = min(min_x, min(mbb.p0.x, min(mbb.p1.x, min(mbb.p2.x, mbb.p3.x)))); max_x = max(max_x, max(mbb.p0.x, max(mbb.p1.x, max(mbb.p2.x, mbb.p3.x)))); min_y = min(min_y, min(mbb.p0.y, min(mbb.p1.y, min(mbb.p2.y, mbb.p3.y)))); max_y = max(max_y, max(mbb.p0.y, max(mbb.p1.y, max(mbb.p2.y, mbb.p3.y)))); } float width = max_x - min_x; float height = max_y - min_y; layer->setBoundingBox(Layer::BoundingBox{min_x, min_y, width, height}); r = ofRectangle(layer->getProps().x, layer->getProps().y, layer->getProps().width, 800); } { OFX_PROFILER_SCOPE("font->draw()"); font->draw(vertices, indices); } glUseProgram(currentProgram); //ofPushStyle(); //ofSetColor(ofColor::green); //ofNoFill(); //ofDrawRectangle(r); //ofPopStyle(); //ofPushStyle(); //ofSetColor(ofColor::white); //for(const auto & b : outerBoundingBoxes){ //int i = 0; //for(const auto & v : b.getVertices()){ //ofSetColor(b.getColors()[i]); //ofDrawCircle(v, 2); //ofDrawBitmapString(ofToString(i), 0, 0); //i++; //} //b.drawVertices(); //} //ofFill(); //ofPopStyle(); } glDisable(GL_BLEND); } void GPUFontAtlasLayerCombo::draw(int width, int height, const shared_ptr & layer){ OFX_PROFILER_FUNCTION(); GLuint location; glm::vec2 mouse = glm::vec2(ofGetMouseX(), ofGetMouseY()); //glm::mat4 projection = transform.getProjectionMatrix((float)width / height); glm::mat4 projection = transform.getOrthoProjectionMatrix(width, height, Transform::TOP_LEFT); //Transform::CENTERED); glm::mat4 view = transform.getViewMatrix(); glm::mat4 model = glm::mat4(1.0f); //glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // background color //glClear(GL_COLOR_BUFFER_BIT); // clear background with background color // Uses premultiplied-alpha. ofDisableDepthTest(); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); //ofEnableAlphaBlending(); int currentProgram; glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); //antiAliasingWindowSize = ofMap(ofGetMouseX(), 0, ofGetWidth(), 1, 3); //enableSuperSamplingAntiAliasing = ofGetMouseY() > ofGetHeight() / 2; if(font){ OFX_PROFILER_SCOPE("draw 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, "antiAliasingWindowSize"); glUniform1f(location, (float)antiAliasingWindowSize); location = glGetUniformLocation(fontShaderProgram, "enableSuperSamplingAntiAliasing"); glUniform1i(location, enableSuperSamplingAntiAliasing); location = glGetUniformLocation(fontShaderProgram, "enableControlPointsVisualization"); glUniform1i(location, enableControlPointsVisualization); std::vector vertices; std::vector indices; vertices.resize(totalCharacters * 4); indices.resize(totalCharacters * 6); std::vector outerBoundingBoxes; ofRectangle r; //for(const auto & layer : layers) { OFX_PROFILER_SCOPE("draw layer"); float ascender = font->getAscender(layer->getProps().fontSize_px); ofxGPUFont::Font::BoundingBox bb; std::vector bbs; std::vector mirror_bbs; float advanceY = 0; font->collectBoundingBoxes(layer->getVariationText(), layer->getVariationTextAppearance(), bb, bbs, advanceY, true, layer->getProps().fontSize_px, layer->getProps().lineHeight); float lineHeight = font->getLineHeight(layer->getProps().fontSize_px) * layer->getProps().lineHeight; if(layer->getProps().width > 0){ int n_wraps = wrapBoundingBoxes(bbs, layer->getVariationText(), layer->getProps().width, lineHeight); // could be optimized by: // - min_x = bbs[0].p0.x // - max_x = min_x + layer->getProps().width // - min_y = bbs[0].p0.y // - max_y = lineHeight * (n_wraps + 1) float min_x = FLT_MAX; float min_y = FLT_MAX; float max_x = -FLT_MAX; float max_y = -FLT_MAX; for(const auto & sbb : bbs){ min_x = min(sbb.p0.x, min_x); min_y = min(sbb.p0.y, min_y); max_x = max(sbb.p2.x, max_x); max_y = max(sbb.p2.y, max_y); } bb.p0.x = min_x; bb.p0.y = min_y; bb.p1.x = max_x; bb.p1.y = min_y; bb.p2.x = max_x; bb.p2.y = max_y; bb.p3.x = min_x; bb.p3.y = max_y; if(ofGetFrameNum() % 600 == 0){ cout << "n_wraps: " << ofToString(n_wraps) << endl << "layer->getProps().width: " << ofToString(layer->getProps().width) << endl ; } } glm::vec4 transformOrigin; getAndApplyTransformOrigin(transformOrigin, layer->getOuterNode(), layer->getInnerNode(), bb, ascender, advanceY, layer->getProps()); auto bb_mirror_none = bb; bb_mirror_none.multiply(layer->getInnerNode().getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_none)); //layer->setBoundingBox(bb); ofVboMesh mesh; mesh.addVertices({bb_mirror_none.p0, bb_mirror_none.p1, bb_mirror_none.p2, bb_mirror_none.p3, glm::vec4(layer->getProps().x, layer->getProps().y, 0, 1), transformOrigin }); mesh.addColors({ ofColor::red, ofColor::red, ofColor::red, ofColor::red, ofColor::white, ofColor::green, }); outerBoundingBoxes.push_back(mesh); if(layer->getProps().mirror_x){ auto bbs_mirror_x = bbs; ofNode mirrorOuterNode = layer->getOuterNode(); ofNode mirrorInnerNode = layer->getInnerNode(); mirrorInnerNode.setParent(mirrorOuterNode); mirrorOuterNode.setOrientation(glm::quat(1, 0, 0, 0)); mirrorOuterNode.rotateDeg(layer->getProps().rotation * -1, glm::vec3(0, 0, 1)); mirrorOuterNode.setPosition(transformOrigin); mirrorOuterNode.move(layer->getProps().mirror_x_distance * -1, 0, 0); mirrorOuterNode.setScale(-1, 1, 1); auto bb_mirror_x = bb; bb_mirror_x.multiply(mirrorInnerNode.getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_x)); font->collectVerticesAndIndices(mirrorInnerNode, layer->getVariationTextAppearance(), bbs_mirror_x, vertices, indices); } if(layer->getProps().mirror_y){ auto bbs_mirror_y = bbs; ofNode mirrorOuterNode = layer->getOuterNode(); ofNode mirrorInnerNode = layer->getInnerNode(); mirrorInnerNode.setParent(mirrorOuterNode); mirrorOuterNode.setOrientation(glm::quat(1, 0, 0, 0)); mirrorOuterNode.rotateDeg(layer->getProps().rotation * -1, glm::vec3(0, 0, 1)); mirrorOuterNode.setPosition(transformOrigin); mirrorOuterNode.move(0, layer->getProps().mirror_y_distance * -1, 0); mirrorOuterNode.setScale(1, -1, 1); auto bb_mirror_y = bb; bb_mirror_y.multiply(mirrorInnerNode.getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_y)); font->collectVerticesAndIndices(mirrorInnerNode, layer->getVariationTextAppearance(), bbs_mirror_y, vertices, indices); } if(layer->getProps().mirror_xy){ auto bbs_mirror_xy = bbs; ofNode mirrorOuterNode = layer->getOuterNode(); ofNode mirrorInnerNode = layer->getInnerNode(); mirrorInnerNode.setParent(mirrorOuterNode); mirrorOuterNode.setOrientation(glm::quat(1, 0, 0, 0)); mirrorOuterNode.rotateDeg(layer->getProps().rotation * 1, glm::vec3(0, 0, 1)); mirrorOuterNode.setPosition(transformOrigin); mirrorOuterNode.move(layer->getProps().mirror_x_distance * -1, layer->getProps().mirror_y_distance * -1, 0); mirrorOuterNode.setScale(-1, -1, 1); auto bb_mirror_xy = bb; bb_mirror_xy.multiply(mirrorInnerNode.getGlobalTransformMatrix()); mirror_bbs.push_back(std::move(bb_mirror_xy)); font->collectVerticesAndIndices(mirrorInnerNode, layer->getVariationTextAppearance(), bbs_mirror_xy, vertices, indices); } font->collectVerticesAndIndices(layer->getInnerNode(), layer->getVariationTextAppearance(), bbs, vertices, indices); float min_x = FLT_MAX; float max_x = -FLT_MAX; float min_y = FLT_MAX; float max_y = -FLT_MAX; for(const auto & mbb : mirror_bbs){ min_x = min(min_x, min(mbb.p0.x, min(mbb.p1.x, min(mbb.p2.x, mbb.p3.x)))); max_x = max(max_x, max(mbb.p0.x, max(mbb.p1.x, max(mbb.p2.x, mbb.p3.x)))); min_y = min(min_y, min(mbb.p0.y, min(mbb.p1.y, min(mbb.p2.y, mbb.p3.y)))); max_y = max(max_y, max(mbb.p0.y, max(mbb.p1.y, max(mbb.p2.y, mbb.p3.y)))); } float width = max_x - min_x; float height = max_y - min_y; layer->setBoundingBox(Layer::BoundingBox{min_x, min_y, width, height}); r = ofRectangle(layer->getProps().x, layer->getProps().y, layer->getProps().width, 800); } { OFX_PROFILER_SCOPE("font->draw()"); font->draw(vertices, indices); } glUseProgram(currentProgram); //ofPushStyle(); //ofSetColor(ofColor::green); //ofNoFill(); //ofDrawRectangle(r); //ofPopStyle(); //ofPushStyle(); //ofSetColor(ofColor::white); //for(const auto & b : outerBoundingBoxes){ //int i = 0; //for(const auto & v : b.getVertices()){ //ofSetColor(b.getColors()[i]); //ofDrawCircle(v, 2); //ofDrawBitmapString(ofToString(i), 0, 0); //i++; //} //b.drawVertices(); //} //ofFill(); //ofPopStyle(); } glDisable(GL_BLEND); } void GPUFontAtlasLayerCombo::getAndApplyTransformOrigin(glm::vec4 & transformOrigin, ofNode & momNode, ofNode & node, const ofxGPUFont::Font::BoundingBox & bb, const float ascender, const float advanceY, const Layer::Props & props){ switch(props.transformOrigin){ default: case Layer::TransformOrigin::TOP_LEFT: { node.setPosition(glm::vec3(0, ascender, 0)); transformOrigin = glm::vec4(props.x, props.y - ascender, 0, 1); break; } case Layer::TransformOrigin::TOP_RIGHT: { float moveX = bb.p1.x - bb.p0.x; node.setPosition(glm::vec3(-moveX, ascender, 0)); transformOrigin = glm::vec4(props.x + moveX, props.y - ascender, 0, 1); break; } case Layer::TransformOrigin::CENTER: { float moveX = (bb.p2.x - bb.p0.x) * 0.5 + bb.p0.x; float moveY = (bb.p2.y - bb.p0.y) * 0.5 - bb.p2.y; node.setPosition(glm::vec3(-moveX, moveY, 0)); transformOrigin = glm::vec4(props.x + moveX, props.y - moveY, 0, 1); break; } case Layer::TransformOrigin::BOTTOM_LEFT: { float moveY = ascender - advanceY; node.setPosition(glm::vec3(0, moveY, 0)); transformOrigin = glm::vec4(props.x, props.y - moveY, 0, 1); break; } case Layer::TransformOrigin::BOTTOM_RIGHT: { float moveY = ascender - (advanceY); float moveX = (bb.p2.x - bb.p0.x); node.setPosition(glm::vec3(-moveX, moveY, 0)); transformOrigin = glm::vec4(props.x + moveX, props.y - moveY, 0, 1); break; } } momNode.setOrientation(glm::quat(1, 0, 0, 0)); momNode.rotateDeg(props.rotation, glm::vec3(0, 0, 1)); momNode.setPosition(transformOrigin); } int GPUFontAtlasLayerCombo::wrapBoundingBoxes(std::vector & bbs, const std::vector & _variationText, int width, float advanceY){ int i = 0; int vi = 0; int wrapIndex = -1; int n_wraps = 0; bool firstToBreak = true; float collectedWrapWidth = 0; for(ofxGPUFont::Font::BoundingBox & bb : bbs){ bool hasGoodCharacter = false; while(!hasGoodCharacter && vi < variationText.size() - 1){ if(variationText[vi].charcode == '\0' || variationText[vi].charcode == '\r' || variationText[vi].charcode == '\n'){ wrapIndex = -1; collectedWrapWidth = 0; vi++; }else if(variationText[vi].charcode == ' '){ // TODO: any whitespace wrapIndex = i; vi++; }else{ hasGoodCharacter = true; } } if(variationText[vi].charcode == '-'){ wrapIndex = i; } //float xxx = bb.p1.x - collectedWrapWidth; //if(ofGetFrameNum() % 600 == 0){ //cout << "WRAP INDEX " << char(variationText[vi].charcode) << ":" << ofToString(wrapIndex) << " xxx: " << ofToString(xxx) << " cww: " << ofToString(collectedWrapWidth) << endl; //} if(bb.p1.x - collectedWrapWidth > width){ if(wrapIndex >= 0){ if(wrapIndex == i){ float wrapWidth = bb.p0.x; collectedWrapWidth = wrapWidth; n_wraps++; bb.p0.x -= wrapWidth; bb.p1.x -= wrapWidth; bb.p2.x -= wrapWidth; bb.p3.x -= wrapWidth; bb.p0.y += (n_wraps) * advanceY; bb.p1.y += (n_wraps) * advanceY; bb.p2.y += (n_wraps) * advanceY; bb.p3.y += (n_wraps) * advanceY; }else{ if(firstToBreak){ collectedWrapWidth = bbs[wrapIndex].p0.x; n_wraps++; for(int w = wrapIndex; w <= i; w++){ bbs[w].p0.x -= collectedWrapWidth; bbs[w].p1.x -= collectedWrapWidth; bbs[w].p2.x -= collectedWrapWidth; bbs[w].p3.x -= collectedWrapWidth; bbs[w].p0.y += (n_wraps) * advanceY; bbs[w].p1.y += (n_wraps) * advanceY; bbs[w].p2.y += (n_wraps) * advanceY; bbs[w].p3.y += (n_wraps) * advanceY; } }else{ bb.p0.x -= collectedWrapWidth; bb.p1.x -= collectedWrapWidth; bb.p2.x -= collectedWrapWidth; bb.p3.x -= collectedWrapWidth; bb.p0.y += (n_wraps) * advanceY; bb.p1.y += (n_wraps) * advanceY; bb.p2.y += (n_wraps) * advanceY; bb.p3.y += (n_wraps) * advanceY; } } firstToBreak = false; } }else{ bb.p0.x -= collectedWrapWidth; bb.p1.x -= collectedWrapWidth; bb.p2.x -= collectedWrapWidth; bb.p3.x -= collectedWrapWidth; bb.p0.y += (n_wraps) * advanceY; bb.p1.y += (n_wraps) * advanceY; bb.p2.y += (n_wraps) * advanceY; bb.p3.y += (n_wraps) * advanceY; } vi++; i++; } return n_wraps; } //void GPUFontAtlasLayerCombo::cullBoundingBoxes(std::vector & bbs, //int width, int height){ //} //bool GPUFontAtlasLayerCombo::isInside(const ofxGPUFont::Font::BoundingBox & bb, //int width, int height){ //} //bool GPUFontAtlasLayerCombo::isInside(const glm::vec4 & vertex, //int width, int height){ //} }