glyph appearance and color
This commit is contained in:
parent
c37609f3f7
commit
2f506000ab
1 changed files with 125 additions and 83 deletions
|
@ -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){
|
||||||
|
|
Loading…
Reference in a new issue