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;
|
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.
|
/// A structure to model a given axis of a variable font.
|
||||||
struct FontVariationAxisParameters {
|
struct FontVariationAxisParameters {
|
||||||
/// The name of the variation axis.
|
/// 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,
|
void collectVerticesAndIndices(const ofNode & node,
|
||||||
const std::vector <GlyphIdentity> & variationText,
|
const std::vector <GlyphIdentity> & variationText,
|
||||||
std::vector <BufferVertex> & vertices,
|
std::vector <BufferVertex> & vertices,
|
||||||
|
@ -975,80 +1147,6 @@ class Font {
|
||||||
glBindVertexArray(0);
|
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:
|
private:
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue