ofxVariableLab/src/GPUFontAtlasLayerCombo.cpp

388 lines
16 KiB
C++
Raw Normal View History

2023-04-12 10:58:53 +02:00
#include "GPUFontAtlasLayerCombo.h"
2023-04-12 13:59:09 +02:00
#include "Utils.h"
2023-04-13 17:15:35 +02:00
#include "font.hpp"
2023-04-22 16:01:40 +02:00
#include "ofAppRunner.h"
2023-04-12 13:59:09 +02:00
#include "ofColor.h"
2023-04-12 15:47:40 +02:00
#include "ofEvents.h"
2023-04-12 16:25:43 +02:00
#include "ofGraphics.h"
2023-04-18 13:22:06 +02:00
#include "ofRectangle.h"
2023-04-12 16:25:43 +02:00
#include "ofUtils.h"
#include "quaternion.hpp"
2023-04-22 16:01:40 +02:00
#include <GL/gl.h>
2023-04-12 10:58:53 +02:00
namespace ofxVariableLab {
2023-04-13 17:15:35 +02:00
void GPUFontAtlasLayerCombo::setup(const ComboIdentifier & identifier,
AtlasLayerComboSettings settings){
2023-04-12 13:59:09 +02:00
this->identifier = identifier;
2023-04-13 17:15:35 +02:00
this->settings = static_cast <GPUFontAtlasLayerComboSettings &>(settings);
2023-04-12 13:59:09 +02:00
#ifdef TARGET_EMSCRIPTEN
string shaderDir = "data/ofxGPUFont/shaders/DEBUG_ES3";
#else
string shaderDir = "data/ofxGPUFont/shaders/GL3";
#endif
shaderCatalog = std::make_unique <ofxGPUFont::ShaderCatalog>(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);
2023-04-12 13:59:09 +02:00
font->listFontVariationAxes(fontVariationAxesParameters, library);
2023-04-13 17:15:35 +02:00
cout << this->identifier.fontPath << " : fontVariationAxes :" << endl;
2023-04-12 13:59:09 +02:00
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;
2023-04-12 10:58:53 +02:00
}
void GPUFontAtlasLayerCombo::update(){
2023-04-19 13:51:41 +02:00
OFX_PROFILER_FUNCTION();
2023-04-14 16:55:15 +02:00
for(const auto & layer : layers){
2023-04-17 20:14:39 +02:00
layer->update();
2023-04-14 16:55:15 +02:00
if(layer->isDirtyDirty()){
isDirty = true;
break;
}
}
2023-04-13 17:15:35 +02:00
if(isDirty){
2023-04-14 16:55:15 +02:00
std::string text = "";
totalCharacters = 0;
std::vector <ofxGPUFont::GlyphIdentity> _variationText;
2023-04-14 16:55:15 +02:00
for(const auto & layer : layers){
std::string layerText = layer->getProps().text;
totalCharacters += layerText.length();
_variationText.insert(_variationText.end(),
layer->getVariationText().begin(),
layer->getVariationText().end());
2023-04-14 16:55:15 +02:00
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);
2023-04-13 17:15:35 +02:00
isDirty = false;
2023-04-12 16:25:43 +02:00
}
2023-04-12 10:58:53 +02:00
}
void GPUFontAtlasLayerCombo::careForChild(shared_ptr <Layer> layer){
if(layer->getType() == LayerType::GPUFONT){
2023-04-13 17:15:35 +02:00
shared_ptr <GPUFontLayer> gpuFontLayer = static_pointer_cast <GPUFontLayer>(layer);
gpuFontLayer->setMomsComboIdentifier(identifier);
gpuFontLayer->isWithNewMom();
gpuFontLayer->setDirtyDirty(true);
2023-04-13 17:15:35 +02:00
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));
2023-04-13 17:15:35 +02:00
}else{
ofLogError("GPUFontAtlasLayerCombo::careForChild()") << __LINE__ << ": child is not recognized as Layer::GPUFONT";
}
}
void GPUFontAtlasLayerCombo::abandonChild(shared_ptr <Layer> layer){
// TODO: handle removing child text from buffer
shared_ptr <GPUFontLayer> gpuFontLayer = static_pointer_cast <GPUFontLayer>(layer);
layers.erase(
std::remove_if(
layers.begin(),
layers.end(),
[gpuFontLayer](shared_ptr <GPUFontLayer> const & l)
{
return l == gpuFontLayer;
}), layers.end());
isDirty = true;
2023-04-12 10:58:53 +02:00
}
const ComboIdentifier & GPUFontAtlasLayerCombo::getIdentifier() const {
return identifier;
}
2023-04-12 13:59:09 +02:00
void GPUFontAtlasLayerCombo::setVFlip(VFlipState vFlipState){
vFlip = vFlipState;
}
bool GPUFontAtlasLayerCombo::hasChildren(){
return layers.size() > 0;
}
2023-04-12 10:58:53 +02:00
const vector <shared_ptr <GPUFontLayer> > & GPUFontAtlasLayerCombo::getLayers(){
return layers;
}
void GPUFontAtlasLayerCombo::draw(int width, int height){
2023-04-19 13:51:41 +02:00
OFX_PROFILER_FUNCTION();
2023-04-12 13:59:09 +02:00
GLuint location;
2023-04-12 15:47:40 +02:00
glm::vec2 mouse = glm::vec2(ofGetMouseX(), ofGetMouseY());
//glm::mat4 projection = transform.getProjectionMatrix((float)width / height);
2023-04-12 16:06:51 +02:00
glm::mat4 projection = transform.getOrthoProjectionMatrix(width,
height,
Transform::TOP_LEFT);
//Transform::CENTERED);
2023-04-12 13:59:09 +02:00
glm::mat4 view = transform.getViewMatrix();
glm::mat4 model = glm::mat4(1.0f);
2023-04-22 16:01:40 +02:00
//glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // background color
//glClear(GL_COLOR_BUFFER_BIT); // clear background with background color
2023-04-12 13:59:09 +02:00
// Uses premultiplied-alpha.
2023-04-22 16:01:40 +02:00
ofDisableDepthTest();
2023-04-12 13:59:09 +02:00
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
2023-04-22 16:01:40 +02:00
//glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
//ofEnableAlphaBlending();
2023-04-12 13:59:09 +02:00
int currentProgram;
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
//antiAliasingWindowSize = ofMap(ofGetMouseX(), 0, ofGetWidth(), 1, 3);
//enableSuperSamplingAntiAliasing = ofGetMouseY() > ofGetHeight() / 2;
2023-04-12 13:59:09 +02:00
if(font){
2023-04-19 13:51:41 +02:00
OFX_PROFILER_SCOPE("draw font");
2023-04-12 13:59:09 +02:00
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 <ofxGPUFont::Font::BufferVertex> vertices;
std::vector <int32_t> indices;
2023-04-13 17:15:35 +02:00
2023-04-18 13:22:06 +02:00
vertices.resize(totalCharacters * 4);
indices.resize(totalCharacters * 6);
std::vector <ofVboMesh> outerBoundingBoxes;
2023-04-13 17:15:35 +02:00
for(const auto & layer : layers){
2023-04-19 13:51:41 +02:00
OFX_PROFILER_SCOPE("draw layer");
2023-04-18 13:22:06 +02:00
float ascender = font->getAscender(layer->getProps().fontSize_px);
ofxGPUFont::Font::BoundingBox bb;
std::vector <ofxGPUFont::Font::BoundingBox> bbs;
float advanceY = 0;
font->collectBoundingBoxes(layer->getVariationText(),
2023-04-19 16:51:02 +02:00
layer->getVariationTextAppearance(),
2023-04-18 13:22:06 +02:00
bb, bbs, advanceY,
true, layer->getProps().fontSize_px);
glm::vec4 transformOrigin;
getAndApplyTransformOrigin(transformOrigin,
layer->getOuterNode(),
layer->getInnerNode(),
bb,
ascender,
advanceY,
layer->getProps());
bb.multiply(layer->getInnerNode().getGlobalTransformMatrix());
2023-04-18 13:22:06 +02:00
ofVboMesh mesh;
mesh.addVertices({bb.p0, bb.p1, bb.p2, bb.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);
2023-04-18 16:04:13 +02:00
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);
font->collectVerticesAndIndices(mirrorInnerNode,
2023-04-19 16:51:02 +02:00
layer->getVariationTextAppearance(),
2023-04-18 16:04:13 +02:00
bbs_mirror_x,
vertices,
2023-04-19 16:51:02 +02:00
indices);
2023-04-18 16:04:13 +02:00
}
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);
font->collectVerticesAndIndices(mirrorInnerNode,
2023-04-19 16:51:02 +02:00
layer->getVariationTextAppearance(),
2023-04-18 16:04:13 +02:00
bbs_mirror_y,
vertices,
2023-04-19 16:51:02 +02:00
indices);
2023-04-18 16:04:13 +02:00
}
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);
font->collectVerticesAndIndices(mirrorInnerNode,
2023-04-19 16:51:02 +02:00
layer->getVariationTextAppearance(),
2023-04-18 16:04:13 +02:00
bbs_mirror_xy,
vertices,
2023-04-19 16:51:02 +02:00
indices);
2023-04-18 16:04:13 +02:00
}
font->collectVerticesAndIndices(layer->getInnerNode(),
2023-04-19 16:51:02 +02:00
layer->getVariationTextAppearance(),
2023-04-18 13:22:06 +02:00
bbs,
vertices,
2023-04-19 16:51:02 +02:00
indices);
}
2023-04-13 17:15:35 +02:00
2023-04-19 16:51:02 +02:00
{
OFX_PROFILER_SCOPE("font->draw()");
font->draw(vertices, indices);
}
2023-04-12 13:59:09 +02:00
glUseProgram(currentProgram);
2023-04-26 16:11:59 +02:00
//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();
2023-04-12 13:59:09 +02:00
}
glDisable(GL_BLEND);
}
2023-04-12 10:58:53 +02:00
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);
}
2023-04-12 10:58:53 +02:00
}