glyph appearance and color

This commit is contained in:
jrkb 2023-04-19 16:52:56 +02:00
parent c37609f3f7
commit 2f506000ab

View file

@ -143,6 +143,12 @@ struct GlyphIdentity {
return this->charcode == other.charcode && this->coords == other.coords; return this->charcode == other.charcode && this->coords == other.coords;
} }
}; };
struct GlyphAppearance {
uint32_t charcode;
glm::vec4 color;
float fontSize_px;
};
} }
// create hash for GlyphIdentity, so we can use it in our unordered_map as key // create hash for GlyphIdentity, so we can use it in our unordered_map as key
namespace std { namespace std {
@ -919,6 +925,7 @@ class Font {
} }
void collectBoundingBoxes(const std::vector <GlyphIdentity> & variationText, void collectBoundingBoxes(const std::vector <GlyphIdentity> & variationText,
const std::vector <GlyphAppearance> & variationTextAppearance,
BoundingBox & boundingBox, BoundingBox & boundingBox,
std::vector <BoundingBox> & boundingBoxes, std::vector <BoundingBox> & boundingBoxes,
float & advanceY, float & advanceY,
@ -932,18 +939,21 @@ class Font {
float minY = FLT_MAX; float minY = FLT_MAX;
float maxX = -FLT_MAX; float maxX = -FLT_MAX;
float maxY = -FLT_MAX; float maxY = -FLT_MAX;
int i = 0;
for(const GlyphIdentity & glyphIdentity : variationText){ for(const GlyphIdentity & glyphIdentity : variationText){
const GlyphAppearance & glyphAppearance = variationTextAppearance[i];
if(glyphIdentity.charcode == '\0'){ if(glyphIdentity.charcode == '\0'){
break; break;
} }
float letterFontSize_px = fontSize_px; // can be individual float letterFontSize_px = glyphAppearance.fontSize_px; // can be individual
const uint32_t & charcode = glyphIdentity.charcode; const uint32_t & charcode = glyphIdentity.charcode;
if(charcode == '\r'){ if(charcode == '\r'){
i++;
continue; continue;
} }
if(charcode == '\n' || charcode == 'n'){ if(charcode == '\n'){
advanceX = 0; advanceX = 0;
advanceY += getLineHeight(fontSize_px); advanceY += getLineHeight(fontSize_px);
if(!vFlip){ if(!vFlip){
@ -952,6 +962,7 @@ class Font {
if(hinting){ if(hinting){
advanceY = std::round(advanceY); advanceY = std::round(advanceY);
} }
i++;
continue; continue;
} }
@ -963,7 +974,7 @@ class Font {
FT_Vector kerning; FT_Vector kerning;
FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning); FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning);
if(!error){ if(!error){
advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize; advanceX += ((float)kerning.x * letterFontSize_px) / emSize * worldSize;
} }
} }
@ -1009,6 +1020,7 @@ class Font {
advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize; advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize;
previous = glyph.index; previous = glyph.index;
i++;
} }
boundingBox.p0 = glm::vec4(minX, minY, 0, 1); boundingBox.p0 = glm::vec4(minX, minY, 0, 1);
boundingBox.p1 = glm::vec4(maxX, minY, 0, 1); boundingBox.p1 = glm::vec4(maxX, minY, 0, 1);
@ -1024,114 +1036,144 @@ class Font {
} }
void collectVerticesAndIndices(const ofNode & node, void collectVerticesAndIndices(const ofNode & node,
const std::vector <GlyphAppearance> & variationTextAppearance,
std::vector <BoundingBox> & boundingBoxes, std::vector <BoundingBox> & boundingBoxes,
std::vector <BufferVertex> & vertices, std::vector <BufferVertex> & vertices,
std::vector <int32_t> & indices, std::vector <int32_t> & indices){
const glm::vec4 & color = glm::vec4(1),
const float fontSize_px = 42){
int i = 0;
for(BoundingBox & bb : boundingBoxes){ for(BoundingBox & bb : boundingBoxes){
bool hasGoodCharacter = false;
while(!hasGoodCharacter && i < variationTextAppearance.size() - 1){
if(variationTextAppearance[i].charcode == '\0'
|| variationTextAppearance[i].charcode == '\r'
|| variationTextAppearance[i].charcode == '\n'){
i++;
}else{
hasGoodCharacter = true;
}
}
bb.multiply(node.getGlobalTransformMatrix()); bb.multiply(node.getGlobalTransformMatrix());
int32_t base = static_cast <int32_t>(vertices.size()); int32_t base = static_cast <int32_t>(vertices.size());
vertices.push_back(BufferVertex{bb.p0.x, bb.p0.y, bb.u0, bb.v0, bb.bufferIndex, color.r, color.g, color.b, color.a}); const glm::vec4 & color = variationTextAppearance[i].color;
vertices.push_back(BufferVertex{bb.p1.x, bb.p1.y, bb.u1, bb.v0, bb.bufferIndex, color.r, color.g, color.b, color.a}); vertices.push_back(BufferVertex{bb.p0.x, bb.p0.y, bb.u0, bb.v0, bb.bufferIndex,
vertices.push_back(BufferVertex{bb.p2.x, bb.p2.y, bb.u1, bb.v1, bb.bufferIndex, color.r, color.g, color.b, color.a}); color.r,
vertices.push_back(BufferVertex{bb.p3.x, bb.p3.y, bb.u0, bb.v1, bb.bufferIndex, color.r, color.g, color.b, color.a}); color.g,
color.b,
color.a});
vertices.push_back(BufferVertex{bb.p1.x, bb.p1.y, bb.u1, bb.v0, bb.bufferIndex,
color.r,
color.g,
color.b,
color.a});
vertices.push_back(BufferVertex{bb.p2.x, bb.p2.y, bb.u1, bb.v1, bb.bufferIndex,
color.r,
color.g,
color.b,
color.a});
vertices.push_back(BufferVertex{bb.p3.x, bb.p3.y, bb.u0, bb.v1, bb.bufferIndex,
color.r,
color.g,
color.b,
color.a});
indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base}); indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base});
i++;
} }
} }
void collectVerticesAndIndices(const ofNode & node, // NOTE: following only exists for nostalgic reason
const std::vector <GlyphIdentity> & variationText, //
std::vector <BufferVertex> & vertices, //void collectVerticesAndIndices(const ofNode & node,
std::vector <int32_t> & indices, //const std::vector <GlyphIdentity> & variationText,
const glm::vec4 & color = glm::vec4(1), //std::vector <BufferVertex> & vertices,
const bool vFlip = false, //std::vector <int32_t> & indices,
const float fontSize_px = 42){ //const glm::vec4 & color = glm::vec4(1),
float advanceX = 0; //const bool vFlip = false,
float advanceY = 0; //const float fontSize_px = 42){
//float advanceX = 0;
//float advanceY = 0;
FT_UInt previous = 0; //FT_UInt previous = 0;
for(const GlyphIdentity & glyphIdentity : variationText){ //for(const GlyphIdentity & glyphIdentity : variationText){
if(glyphIdentity.charcode == '\0'){ //if(glyphIdentity.charcode == '\0'){
break; //break;
} //}
float letterFontSize_px = fontSize_px; // can be individual //float letterFontSize_px = fontSize_px; // can be individual
const uint32_t & charcode = glyphIdentity.charcode; //const uint32_t & charcode = glyphIdentity.charcode;
if(charcode == '\r'){ //if(charcode == '\r'){
continue; //continue;
} //}
if(charcode == '\n' || charcode == 'n'){ //if(charcode == '\n' || charcode == 'n'){
advanceX = 0; //advanceX = 0;
advanceY += ((float)face->height * fontSize_px) / (float)face->units_per_EM * worldSize; //advanceY += ((float)face->height * fontSize_px) / (float)face->units_per_EM * worldSize;
if(!vFlip){ //if(!vFlip){
advanceY *= -1; //advanceY *= -1;
} //}
if(hinting){ //if(hinting){
advanceY = std::round(advanceY); //advanceY = std::round(advanceY);
} //}
continue; //continue;
} //}
auto glyphIt = glyphs.find(glyphIdentity); //auto glyphIt = glyphs.find(glyphIdentity);
Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs.begin()->second : glyphIt->second; // in case we have no glyph, draw first one? //Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs.begin()->second : glyphIt->second; // in case we have no glyph, draw first one?
// NOTE: should we do this? //// NOTE: should we do this?
if(previous != 0 && glyph.index != 0){ //if(previous != 0 && glyph.index != 0){
FT_Vector kerning; //FT_Vector kerning;
FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning); //FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning);
if(!error){ //if(!error){
advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize; //advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize;
} //}
} //}
// Do not emit quad for empty glyphs (whitespace). //// Do not emit quad for empty glyphs (whitespace).
if(glyph.curveCount){ //if(glyph.curveCount){
FT_Pos d = (FT_Pos)(emSize * dilation); //FT_Pos d = (FT_Pos)(emSize * dilation);
float u0 = (float)(glyph.bearingX - d) / emSize; //float u0 = (float)(glyph.bearingX - d) / emSize;
float v0 = (float)(glyph.bearingY - glyph.height - d) / emSize; //float v0 = (float)(glyph.bearingY - glyph.height - d) / emSize;
float u1 = (float)(glyph.bearingX + glyph.width + d) / emSize; //float u1 = (float)(glyph.bearingX + glyph.width + d) / emSize;
float v1 = (float)(glyph.bearingY + d) / emSize; //float v1 = (float)(glyph.bearingY + d) / emSize;
float x0 = advanceX + u0 * worldSize * letterFontSize_px; //float x0 = advanceX + u0 * worldSize * letterFontSize_px;
float y0 = v0 * worldSize * letterFontSize_px; //float y0 = v0 * worldSize * letterFontSize_px;
float x1 = advanceX + u1 * worldSize * letterFontSize_px; //float x1 = advanceX + u1 * worldSize * letterFontSize_px;
float y1 = v1 * worldSize * letterFontSize_px; //float y1 = v1 * worldSize * letterFontSize_px;
if(vFlip){ //if(vFlip){
float _v = v0; //float _v = v0;
v0 = v1; //v0 = v1;
v1 = _v; //v1 = _v;
y0 = -v0 * worldSize * letterFontSize_px; //y0 = -v0 * worldSize * letterFontSize_px;
y1 = -v1 * worldSize * letterFontSize_px; //y1 = -v1 * worldSize * letterFontSize_px;
} //}
glm::vec4 p0 = node.getGlobalTransformMatrix() * glm::vec4(x0, y0 + advanceY, 0, 1); //glm::vec4 p0 = node.getGlobalTransformMatrix() * glm::vec4(x0, y0 + advanceY, 0, 1);
glm::vec4 p1 = node.getGlobalTransformMatrix() * glm::vec4(x1, y0 + advanceY, 0, 1); //glm::vec4 p1 = node.getGlobalTransformMatrix() * glm::vec4(x1, y0 + advanceY, 0, 1);
glm::vec4 p2 = node.getGlobalTransformMatrix() * glm::vec4(x1, y1 + advanceY, 0, 1); //glm::vec4 p2 = node.getGlobalTransformMatrix() * glm::vec4(x1, y1 + advanceY, 0, 1);
glm::vec4 p3 = node.getGlobalTransformMatrix() * glm::vec4(x0, y1 + advanceY, 0, 1); //glm::vec4 p3 = node.getGlobalTransformMatrix() * glm::vec4(x0, y1 + advanceY, 0, 1);
int32_t base = static_cast <int32_t>(vertices.size()); //int32_t base = static_cast <int32_t>(vertices.size());
vertices.push_back(BufferVertex{p0.x, p0.y, u0, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a}); //vertices.push_back(BufferVertex{p0.x, p0.y, u0, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a});
vertices.push_back(BufferVertex{p1.x, p1.y, u1, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a}); //vertices.push_back(BufferVertex{p1.x, p1.y, u1, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a});
vertices.push_back(BufferVertex{p2.x, p2.y, u1, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a}); //vertices.push_back(BufferVertex{p2.x, p2.y, u1, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a});
vertices.push_back(BufferVertex{p3.x, p3.y, u0, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a}); //vertices.push_back(BufferVertex{p3.x, p3.y, u0, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a});
indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base}); //indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base});
} //}
advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize; //advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize;
previous = glyph.index; //previous = glyph.index;
} //}
} //}
void draw(const std::vector <BufferVertex> & vertices, void draw(const std::vector <BufferVertex> & vertices,
const std::vector <int32_t> & indices){ const std::vector <int32_t> & indices){