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-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"
|
|
|
|
#include "ofUtils.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();
|
|
|
|
}
|
|
|
|
}
|
2023-04-16 14:52:37 +02:00
|
|
|
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-13 17:15:35 +02:00
|
|
|
//float animationSpeed = 1.0;
|
|
|
|
//float threshold = 1.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);
|
2023-04-12 17:37:45 +02:00
|
|
|
//}
|
2023-04-13 17:15:35 +02:00
|
|
|
//}
|
2023-04-14 16:55:15 +02:00
|
|
|
for(const auto & layer : layers){
|
|
|
|
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;
|
2023-04-16 14:52:37 +02:00
|
|
|
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();
|
2023-04-16 14:52:37 +02:00
|
|
|
_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;
|
2023-04-16 14:52:37 +02:00
|
|
|
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){
|
2023-04-13 17:15:35 +02:00
|
|
|
if(layer->getType() == Layer::GPUFONT){
|
|
|
|
shared_ptr <GPUFontLayer> gpuFontLayer = static_pointer_cast <GPUFontLayer>(layer);
|
|
|
|
layers.push_back(gpuFontLayer);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}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());
|
|
|
|
|
|
|
|
// update the text
|
|
|
|
// this doesn't happen very often, so let's just
|
|
|
|
// iterate over all layers and calculate fresh
|
|
|
|
std::string text = "";
|
|
|
|
totalCharacters = 0;
|
|
|
|
for(const auto & layer : layers){
|
|
|
|
std::string layerText = layer->getProps().text;
|
|
|
|
totalCharacters += layerText.length();
|
|
|
|
text += layerText;
|
|
|
|
}
|
|
|
|
removeDuplicateCharacters(text);
|
|
|
|
mainText = text;
|
|
|
|
// NOTE: we do not want to update buffers now,
|
|
|
|
// as it's probably more costly than just keeping
|
|
|
|
// the old glyphs around...
|
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;
|
|
|
|
}
|
2023-04-12 10:58:53 +02:00
|
|
|
const vector <shared_ptr <GPUFontLayer> > & GPUFontAtlasLayerCombo::getLayers(){
|
|
|
|
return layers;
|
|
|
|
}
|
2023-04-12 13:59:09 +02:00
|
|
|
void GPUFontAtlasLayerCombo::draw(){
|
|
|
|
GLuint location;
|
|
|
|
|
|
|
|
int width = ofGetWidth();
|
|
|
|
int height = ofGetHeight();
|
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);
|
2023-04-12 17:37:45 +02:00
|
|
|
//Transform::CENTERED);
|
2023-04-12 13:59:09 +02:00
|
|
|
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);
|
2023-04-12 16:25:43 +02:00
|
|
|
ofDisableDepthTest();
|
|
|
|
ofEnableAlphaBlending();
|
2023-04-12 13:59:09 +02:00
|
|
|
|
|
|
|
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");
|
2023-04-13 12:56:17 +02:00
|
|
|
glUniform4f(location, 1.0f, 1.0f, 1.0f, 0.5f);
|
2023-04-12 13:59:09 +02:00
|
|
|
|
|
|
|
location = glGetUniformLocation(fontShaderProgram, "antiAliasingWindowSize");
|
|
|
|
glUniform1f(location, (float)antiAliasingWindowSize);
|
|
|
|
location = glGetUniformLocation(fontShaderProgram, "enableSuperSamplingAntiAliasing");
|
|
|
|
glUniform1i(location, enableSuperSamplingAntiAliasing);
|
|
|
|
location = glGetUniformLocation(fontShaderProgram, "enableControlPointsVisualization");
|
|
|
|
glUniform1i(location, enableControlPointsVisualization);
|
|
|
|
|
|
|
|
|
2023-04-12 17:37:45 +02:00
|
|
|
//mouse.x = 0;
|
|
|
|
//mouse.y = 0;
|
2023-04-13 12:56:17 +02:00
|
|
|
std::vector <ofxGPUFont::Font::BufferVertex> vertices;
|
|
|
|
std::vector <int32_t> indices;
|
2023-04-13 17:15:35 +02:00
|
|
|
|
|
|
|
for(const auto & layer : layers){
|
|
|
|
font->collectVerticesAndIndices(glm::vec3(layer->getProps().x,
|
|
|
|
layer->getProps().y,
|
|
|
|
0),
|
2023-04-16 14:52:37 +02:00
|
|
|
layer->getVariationText(),
|
2023-04-13 17:15:35 +02:00
|
|
|
vertices, indices, true,
|
|
|
|
layer->getProps().fontSize_px);
|
2023-04-13 12:56:17 +02:00
|
|
|
}
|
2023-04-13 17:15:35 +02:00
|
|
|
vertices.resize(totalCharacters * 4);
|
|
|
|
indices.resize(totalCharacters * 6);
|
|
|
|
//cx = 0.5f * (bb.minX + bb.maxX);
|
|
|
|
//cy = 0.5f * (bb.minY + bb.maxY);
|
|
|
|
|
2023-04-13 12:56:17 +02:00
|
|
|
font->draw(vertices, indices);
|
2023-04-12 13:59:09 +02:00
|
|
|
//ofRectangle rectangle(0, 0, width, height);
|
|
|
|
//ofDrawRectangle(rectangle);
|
2023-04-13 12:56:17 +02:00
|
|
|
//font->draw(mouse.x, mouse.y - (200 * sin(ofGetElapsedTimef() * 0.25)), 0, "what", vFlip == V_FLIP_ON, 42.0f);
|
|
|
|
//location = glGetUniformLocation(fontShaderProgram, "color");
|
|
|
|
//glUniform4f(location, 0.0f, 1.0f, 0.0f, 0.5f);
|
|
|
|
//font->draw(mouse.x, mouse.y, 0, "ever", vFlip == V_FLIP_ON, 420.0f);
|
|
|
|
|
2023-04-12 13:59:09 +02:00
|
|
|
glUseProgram(currentProgram);
|
|
|
|
}
|
|
|
|
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
2023-04-12 15:47:40 +02:00
|
|
|
//ofDrawBitmapStringHighlight(
|
|
|
|
//(ofToString("and we know:") + ofToString("everything"))
|
|
|
|
//, 100 + mouse.x, mouse.y, ofFloatColor::pink, ofFloatColor::black);
|
2023-04-12 13:59:09 +02:00
|
|
|
|
|
|
|
ofDrawBitmapStringHighlight(
|
|
|
|
"fps: " + ofToString(ofGetFrameRate()) + "\n"
|
2023-04-13 17:15:35 +02:00
|
|
|
+ "font: " + this->identifier.fontPath + "\n"
|
2023-04-12 13:59:09 +02:00
|
|
|
, 20, 20);
|
|
|
|
}
|
2023-04-12 10:58:53 +02:00
|
|
|
|
|
|
|
}
|