add bounding boxes
This commit is contained in:
parent
133b74699e
commit
c37609f3f7
1 changed files with 172 additions and 74 deletions
|
@ -194,6 +194,36 @@ class Font {
|
|||
float r, g, b, a;
|
||||
};
|
||||
|
||||
//
|
||||
// p0----------p1
|
||||
// | |
|
||||
// | /\ |
|
||||
// | / \ |
|
||||
// | /____\ |
|
||||
// | / \ |
|
||||
// | |
|
||||
// p3----------p2
|
||||
//
|
||||
// also has bufferIndex & uv coords
|
||||
struct BoundingBox {
|
||||
glm::vec4 p0;
|
||||
glm::vec4 p1;
|
||||
glm::vec4 p2;
|
||||
glm::vec4 p3;
|
||||
float u0;
|
||||
float u1;
|
||||
float v0;
|
||||
float v1;
|
||||
int32_t bufferIndex;
|
||||
|
||||
void multiply(const glm::mat4 & mat){
|
||||
p0 = mat * p0;
|
||||
p1 = mat * p1;
|
||||
p2 = mat * p2;
|
||||
p3 = mat * p3;
|
||||
}
|
||||
};
|
||||
|
||||
/// A structure to model a given axis of a variable font.
|
||||
struct FontVariationAxisParameters {
|
||||
/// The name of the variation axis.
|
||||
|
@ -873,6 +903,148 @@ class Font {
|
|||
|
||||
}
|
||||
|
||||
float getLineHeight(float fontSize_px = 1){
|
||||
float out = ((float)face->height * fontSize_px) / (float)face->units_per_EM * worldSize;
|
||||
return out;
|
||||
}
|
||||
|
||||
float getAscender(float fontSize_px = 1){
|
||||
float out = ((float)face->ascender * fontSize_px) / (float)face->units_per_EM * worldSize;
|
||||
return out;
|
||||
}
|
||||
|
||||
float getDescender(float fontSize_px = 1){
|
||||
float out = ((float)face->descender * fontSize_px) / (float)face->units_per_EM * worldSize;
|
||||
return out;
|
||||
}
|
||||
|
||||
void collectBoundingBoxes(const std::vector <GlyphIdentity> & variationText,
|
||||
BoundingBox & boundingBox,
|
||||
std::vector <BoundingBox> & boundingBoxes,
|
||||
float & advanceY,
|
||||
const bool vFlip = false,
|
||||
const float fontSize_px = 42){
|
||||
|
||||
float advanceX = 0;
|
||||
|
||||
FT_UInt previous = 0;
|
||||
float minX = FLT_MAX;
|
||||
float minY = FLT_MAX;
|
||||
float maxX = -FLT_MAX;
|
||||
float maxY = -FLT_MAX;
|
||||
for(const GlyphIdentity & glyphIdentity : variationText){
|
||||
if(glyphIdentity.charcode == '\0'){
|
||||
break;
|
||||
}
|
||||
float letterFontSize_px = fontSize_px; // can be individual
|
||||
const uint32_t & charcode = glyphIdentity.charcode;
|
||||
|
||||
if(charcode == '\r'){
|
||||
continue;
|
||||
}
|
||||
|
||||
if(charcode == '\n' || charcode == 'n'){
|
||||
advanceX = 0;
|
||||
advanceY += getLineHeight(fontSize_px);
|
||||
if(!vFlip){
|
||||
advanceY *= -1;
|
||||
}
|
||||
if(hinting){
|
||||
advanceY = std::round(advanceY);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto glyphIt = glyphs.find(glyphIdentity);
|
||||
Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs.begin()->second : glyphIt->second; // in case we have no glyph, draw first one?
|
||||
// NOTE: should we do this?
|
||||
|
||||
if(previous != 0 && glyph.index != 0){
|
||||
FT_Vector kerning;
|
||||
FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning);
|
||||
if(!error){
|
||||
advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not emit quad for empty glyphs (whitespace).
|
||||
if(glyph.curveCount){
|
||||
FT_Pos d = (FT_Pos)(emSize * dilation);
|
||||
|
||||
float u0 = (float)(glyph.bearingX - d) / emSize;
|
||||
float v0 = (float)(glyph.bearingY - glyph.height - d) / emSize;
|
||||
float u1 = (float)(glyph.bearingX + glyph.width + d) / emSize;
|
||||
float v1 = (float)(glyph.bearingY + d) / emSize;
|
||||
|
||||
float x0 = advanceX + u0 * worldSize * letterFontSize_px;
|
||||
float y0 = v0 * worldSize * letterFontSize_px;
|
||||
float x1 = advanceX + u1 * worldSize * letterFontSize_px;
|
||||
float y1 = v1 * worldSize * letterFontSize_px;
|
||||
|
||||
if(vFlip){
|
||||
float _v = v0;
|
||||
v0 = v1;
|
||||
v1 = _v;
|
||||
|
||||
y0 = -v0 * worldSize * letterFontSize_px;
|
||||
y1 = -v1 * worldSize * letterFontSize_px;
|
||||
}
|
||||
|
||||
y0 += advanceY;
|
||||
y1 += advanceY;
|
||||
minX = min(x0, min(x1, minX));
|
||||
maxX = max(x0, max(x1, maxX));
|
||||
minY = min(y0, min(y1, minY));
|
||||
maxY = max(y0, max(y1, maxY));
|
||||
|
||||
boundingBoxes.push_back({
|
||||
glm::vec4(x0, y0, 0, 1),
|
||||
glm::vec4(x1, y0, 0, 1),
|
||||
glm::vec4(x1, y1, 0, 1),
|
||||
glm::vec4(x0, y1, 0, 1),
|
||||
u0, u1, v0, v1,
|
||||
glyph.bufferIndex
|
||||
});
|
||||
}
|
||||
|
||||
advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize;
|
||||
previous = glyph.index;
|
||||
}
|
||||
boundingBox.p0 = glm::vec4(minX, minY, 0, 1);
|
||||
boundingBox.p1 = glm::vec4(maxX, minY, 0, 1);
|
||||
boundingBox.p2 = glm::vec4(maxX, maxY, 0, 1);
|
||||
boundingBox.p3 = glm::vec4(minX, maxY, 0, 1);
|
||||
advanceY += getLineHeight(fontSize_px);
|
||||
if(!vFlip){
|
||||
advanceY *= -1;
|
||||
}
|
||||
if(hinting){
|
||||
advanceY = std::round(advanceY);
|
||||
}
|
||||
}
|
||||
|
||||
void collectVerticesAndIndices(const ofNode & node,
|
||||
std::vector <BoundingBox> & boundingBoxes,
|
||||
std::vector <BufferVertex> & vertices,
|
||||
std::vector <int32_t> & indices,
|
||||
const glm::vec4 & color = glm::vec4(1),
|
||||
const float fontSize_px = 42){
|
||||
|
||||
for(BoundingBox & bb : boundingBoxes){
|
||||
|
||||
bb.multiply(node.getGlobalTransformMatrix());
|
||||
|
||||
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});
|
||||
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});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void collectVerticesAndIndices(const ofNode & node,
|
||||
const std::vector <GlyphIdentity> & variationText,
|
||||
std::vector <BufferVertex> & vertices,
|
||||
|
@ -975,80 +1147,6 @@ class Font {
|
|||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
struct BoundingBox {
|
||||
float minX, minY, maxX, maxY;
|
||||
};
|
||||
|
||||
BoundingBox measure(float x, float y, const std::string & text){
|
||||
//BoundingBox bb;
|
||||
cerr << "ofxGPUFont::Font::BoundingBox not implemented" << endl;
|
||||
//bb.minX = +std::numeric_limits <float>::infinity();
|
||||
//bb.minY = +std::numeric_limits <float>::infinity();
|
||||
//bb.maxX = -std::numeric_limits <float>::infinity();
|
||||
//bb.maxY = -std::numeric_limits <float>::infinity();
|
||||
|
||||
//float originalX = x;
|
||||
|
||||
//FT_UInt previous = 0;
|
||||
//for(const char * textIt = text.c_str(); *textIt != '\0';){
|
||||
//uint32_t charcode = decodeCharcodes(&textIt);
|
||||
|
||||
//if(charcode == '\r'){
|
||||
//continue;
|
||||
//}
|
||||
|
||||
//if(charcode == '\n'){
|
||||
//x = originalX;
|
||||
//y -= (float)face->height / (float)face->units_per_EM * worldSize;
|
||||
//if(hinting){
|
||||
//y = std::round(y);
|
||||
//}
|
||||
//continue;
|
||||
//}
|
||||
|
||||
//auto glyphIt = glyphs.find(charcode);
|
||||
//Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs[0] : glyphIt->second;
|
||||
|
||||
//if(previous != 0 && glyph.index != 0){
|
||||
//FT_Vector kerning;
|
||||
//FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning);
|
||||
//if(!error){
|
||||
//x += (float)kerning.x / emSize * worldSize;
|
||||
//}
|
||||
//}
|
||||
|
||||
//// Note: Do not apply dilation here, we want to calculate exact bounds.
|
||||
//float u0 = (float)(glyph.bearingX) / emSize;
|
||||
//float v0 = (float)(glyph.bearingY - glyph.height) / emSize;
|
||||
//float u1 = (float)(glyph.bearingX + glyph.width) / emSize;
|
||||
//float v1 = (float)(glyph.bearingY) / emSize;
|
||||
|
||||
//float x0 = x + u0 * worldSize;
|
||||
//float y0 = y + v0 * worldSize;
|
||||
//float x1 = x + u1 * worldSize;
|
||||
//float y1 = y + v1 * worldSize;
|
||||
|
||||
//if(x0 < bb.minX){
|
||||
//bb.minX = x0;
|
||||
//}
|
||||
//if(y0 < bb.minY){
|
||||
//bb.minY = y0;
|
||||
//}
|
||||
//if(x1 > bb.maxX){
|
||||
//bb.maxX = x1;
|
||||
//}
|
||||
//if(y1 > bb.maxY){
|
||||
//bb.maxY = y1;
|
||||
//}
|
||||
|
||||
//x += (float)glyph.advance / emSize * worldSize;
|
||||
//previous = glyph.index;
|
||||
//}
|
||||
|
||||
//return bb;
|
||||
return BoundingBox();
|
||||
}
|
||||
|
||||
private:
|
||||
FT_Face face;
|
||||
|
||||
|
|
Loading…
Reference in a new issue