identify glyphs by character and variations
This commit is contained in:
parent
3a156be801
commit
1af76d8726
1 changed files with 293 additions and 221 deletions
|
@ -27,6 +27,13 @@
|
|||
|
||||
namespace ofxGPUFont {
|
||||
|
||||
inline FT_Fixed double2f16dot16(double x){
|
||||
return DOUBLE_TO_F16DOT16(x);
|
||||
}
|
||||
inline FT_Fixed float2f16dot16(float x){
|
||||
return DOUBLE_TO_F16DOT16(x);
|
||||
}
|
||||
|
||||
inline int32_t calculateUpperPowerOfTwo(int32_t v){
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
|
@ -41,6 +48,122 @@ inline int32_t calculateUpperPowerOfTwo(int32_t v){
|
|||
inline bool isPowerOfTwo(int i){
|
||||
return (i & (i - 1)) == 0;
|
||||
}
|
||||
// Decodes the first Unicode code point from the null-terminated UTF-8 string *text and advances *text to point at the next code point.
|
||||
// If the encoding is invalid, advances *text by one byte and returns 0.
|
||||
// *text should not be empty, because it will be advanced past the null terminator.
|
||||
inline uint32_t decodeCharcodes(const char * * text){
|
||||
uint8_t first = static_cast <uint8_t>((*text)[0]);
|
||||
|
||||
// Fast-path for ASCII.
|
||||
if(first < 128){
|
||||
(*text)++;
|
||||
return static_cast <uint32_t>(first);
|
||||
}
|
||||
|
||||
// This could probably be optimized a bit.
|
||||
uint32_t result;
|
||||
int size;
|
||||
if((first & 0xE0) == 0xC0){ // 110xxxxx
|
||||
result = first & 0x1F;
|
||||
size = 2;
|
||||
}else if((first & 0xF0) == 0xE0){ // 1110xxxx
|
||||
result = first & 0x0F;
|
||||
size = 3;
|
||||
}else if((first & 0xF8) == 0xF0){ // 11110xxx
|
||||
result = first & 0x07;
|
||||
size = 4;
|
||||
}else{
|
||||
// Invalid encoding.
|
||||
(*text)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int i = 1; i < size; i++){
|
||||
uint8_t value = static_cast <uint8_t>((*text)[i]);
|
||||
// Invalid encoding (also catches a null terminator in the middle of a code point).
|
||||
if((value & 0xC0) != 0x80){ // 10xxxxxx
|
||||
(*text)++;
|
||||
return 0;
|
||||
}
|
||||
result = (result << 6) | (value & 0x3F);
|
||||
}
|
||||
|
||||
(*text) += size;
|
||||
return result;
|
||||
}
|
||||
inline uint32_t decodeCharcode(const char * text){
|
||||
uint8_t first = static_cast <uint8_t>((text)[0]);
|
||||
|
||||
// Fast-path for ASCII.
|
||||
if(first < 128){
|
||||
return static_cast <uint32_t>(first);
|
||||
}
|
||||
|
||||
// This could probably be optimized a bit.
|
||||
uint32_t result;
|
||||
int size;
|
||||
if((first & 0xE0) == 0xC0){ // 110xxxxx
|
||||
result = first & 0x1F;
|
||||
size = 2;
|
||||
}else if((first & 0xF0) == 0xE0){ // 1110xxxx
|
||||
result = first & 0x0F;
|
||||
size = 3;
|
||||
}else if((first & 0xF8) == 0xF0){ // 11110xxx
|
||||
result = first & 0x07;
|
||||
size = 4;
|
||||
}else{
|
||||
// Invalid encoding.
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int i = 1; i < size; i++){
|
||||
uint8_t value = static_cast <uint8_t>((text)[i]);
|
||||
// Invalid encoding (also catches a null terminator in the middle of a code point).
|
||||
if((value & 0xC0) != 0x80){ // 10xxxxxx
|
||||
return 0;
|
||||
}
|
||||
result = (result << 6) | (value & 0x3F);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t & seed, const T & v){
|
||||
std::hash <T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
typedef std::vector <FT_Fixed> FontVariationCoords;
|
||||
struct GlyphIdentity {
|
||||
uint32_t charcode;
|
||||
FontVariationCoords coords;
|
||||
// we need a comparison operator, to use GlyphIdentity in our unordered_map as key
|
||||
bool operator==(const GlyphIdentity & other) const {
|
||||
return this->charcode == other.charcode && this->coords == other.coords;
|
||||
}
|
||||
};
|
||||
}
|
||||
// create hash for GlyphIdentity, so we can use it in our unordered_map as key
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash <ofxGPUFont::GlyphIdentity> {
|
||||
std::size_t operator()(const ofxGPUFont::GlyphIdentity & k) const {
|
||||
using std::size_t;
|
||||
using std::hash;
|
||||
using std::string;
|
||||
|
||||
size_t seed = 0;
|
||||
ofxGPUFont::hash_combine(seed, k.charcode);
|
||||
for(const auto & coord : k.coords){
|
||||
ofxGPUFont::hash_combine(seed, coord);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
namespace ofxGPUFont {
|
||||
|
||||
class Font {
|
||||
struct Glyph {
|
||||
|
@ -87,7 +210,68 @@ class Font {
|
|||
double value;
|
||||
};
|
||||
|
||||
static bool setFontVariationAxis(FT_Library & library, FT_Face & face, const char * name, double coordinate){
|
||||
static bool setFontVariationAxes(FT_Library & library,
|
||||
FT_Face & face,
|
||||
FontVariationCoords & coords){
|
||||
bool success = false;
|
||||
if(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS){
|
||||
FT_MM_Var * master = NULL;
|
||||
if(FT_Get_MM_Var(face, &master) != 0){
|
||||
return false;
|
||||
}
|
||||
if(master && master->num_axis){
|
||||
if(FT_Set_Var_Design_Coordinates(face, FT_UInt(coords.size()), &coords[0]) != 0){
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
FT_Done_MM_Var(library, master);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool setFontVariationAxes(FT_Library & library, FontVariationCoords & coords){
|
||||
return Font::setFontVariationAxes(library, face, coords);
|
||||
}
|
||||
|
||||
static bool setFontVariationAxes(FT_Library & library,
|
||||
FT_Face & face,
|
||||
const std::vector <FontVariationAxis> & variationAxes){
|
||||
bool success = false;
|
||||
if(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS){
|
||||
FT_MM_Var * master = NULL;
|
||||
if(FT_Get_MM_Var(face, &master) != 0){
|
||||
return false;
|
||||
}
|
||||
if(master && master->num_axis){
|
||||
std::vector <FT_Fixed> coords(master->num_axis);
|
||||
if(FT_Get_Var_Design_Coordinates(face, FT_UInt(coords.size()), &coords[0]) == 0){
|
||||
for(FT_UInt i = 0; i < master->num_axis; ++i){
|
||||
for(const auto & variationAxis : variationAxes){
|
||||
if(strcmp(variationAxis.name, master->axis[i].name) == 0){
|
||||
coords[i] = DOUBLE_TO_F16DOT16(variationAxis.value);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(FT_Set_Var_Design_Coordinates(face, FT_UInt(coords.size()), &coords[0]) != 0){
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
FT_Done_MM_Var(library, master);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool setFontVariationAxes(FT_Library & library,
|
||||
const std::vector <FontVariationAxis> & variationAxes){
|
||||
return Font::setFontVariationAxes(library, face, variationAxes);
|
||||
}
|
||||
|
||||
static bool setFontVariationAxis(FT_Library & library,
|
||||
FT_Face & face,
|
||||
const char * name, double coordinate){
|
||||
bool success = false;
|
||||
if(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS){
|
||||
FT_MM_Var * master = NULL;
|
||||
|
@ -260,7 +444,7 @@ class Font {
|
|||
}
|
||||
|
||||
public:
|
||||
void setWorldSize(float worldSize){
|
||||
void setWorldSize(FT_Library & library, float worldSize){
|
||||
if(worldSize == this->worldSize){
|
||||
return;
|
||||
}
|
||||
|
@ -274,18 +458,22 @@ class Font {
|
|||
// change because of hinting.
|
||||
|
||||
emSize = worldSize * 64;
|
||||
{ // error scope
|
||||
FT_Error error = FT_Set_Pixel_Sizes(face, 0, static_cast <FT_UInt>(std::ceil(worldSize)));
|
||||
if(error){
|
||||
std::cerr << "[font] error while setting pixel size: " << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bufferGlyphs.clear();
|
||||
bufferCurves.clear();
|
||||
|
||||
for(auto it = glyphs.begin(); it != glyphs.end();){
|
||||
uint32_t charcode = it->first;
|
||||
uint32_t charcode = it->first.charcode;
|
||||
FT_UInt glyphIndex = it->second.index;
|
||||
|
||||
setFontVariationAxes(library,
|
||||
const_cast <FontVariationCoords &>(it->first.coords)); // danger?
|
||||
FT_Error error = FT_Load_Glyph(face, glyphIndex, loadFlags);
|
||||
if(error){
|
||||
std::cerr << "[font] error while loading glyph for character " << charcode << ": " << error << std::endl;
|
||||
|
@ -296,14 +484,15 @@ class Font {
|
|||
// This call will overwrite the glyph in the glyphs map. However, it
|
||||
// cannot invalidate the iterator because the glyph is already in
|
||||
// the map if we are here.
|
||||
buildGlyph(charcode, glyphIndex);
|
||||
buildGlyph(GlyphIdentity{charcode, it->first.coords}, glyphIndex);
|
||||
it++;
|
||||
}
|
||||
|
||||
uploadBuffers();
|
||||
}
|
||||
|
||||
void prepareGlyphsForText(const std::string & text, bool forceChange = false){
|
||||
void prepareGlyphsForText(const std::vector <GlyphIdentity> & variationText,
|
||||
FT_Library & library,
|
||||
bool forceChange = false){
|
||||
bool changed = false;
|
||||
|
||||
if(forceChange){
|
||||
|
@ -312,18 +501,25 @@ class Font {
|
|||
glyphs.clear();
|
||||
}
|
||||
|
||||
for(const char * textIt = text.c_str(); *textIt != '\0';){
|
||||
uint32_t charcode = decodeCharcode(&textIt);
|
||||
int i = 0;
|
||||
for(const auto & glyphIdentity : variationText){
|
||||
const uint32_t & charcode = glyphIdentity.charcode;
|
||||
if(charcode == '\0'){ // do we need this?
|
||||
break;
|
||||
}
|
||||
|
||||
//cout << "yes, this is running" << endl;
|
||||
if(charcode == '\r' || charcode == '\n'){
|
||||
//cout << "but charcode is r or n" << endl;
|
||||
continue;
|
||||
}
|
||||
if(glyphs.count(charcode) != 0){
|
||||
if(glyphs.count(glyphIdentity) != 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
setFontVariationAxes(library,
|
||||
const_cast <FontVariationCoords &>(glyphIdentity.coords)); // danger?
|
||||
|
||||
FT_UInt glyphIndex = FT_Get_Char_Index(face, charcode);
|
||||
if(!glyphIndex){
|
||||
continue;
|
||||
|
@ -335,8 +531,10 @@ class Font {
|
|||
continue;
|
||||
}
|
||||
|
||||
buildGlyph(charcode, glyphIndex);
|
||||
buildGlyph(glyphIdentity,
|
||||
glyphIndex);
|
||||
changed = true;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(changed){
|
||||
|
@ -422,7 +620,8 @@ class Font {
|
|||
#endif
|
||||
}
|
||||
|
||||
void buildGlyph(uint32_t charcode, FT_UInt glyphIndex){
|
||||
void buildGlyph(const GlyphIdentity & glyphIdentity,
|
||||
FT_UInt glyphIndex){
|
||||
BufferGlyph bufferGlyph;
|
||||
bufferGlyph.start = static_cast <int32_t>(bufferCurves.size());
|
||||
|
||||
|
@ -447,7 +646,7 @@ class Font {
|
|||
glyph.bearingX = face->glyph->metrics.horiBearingX;
|
||||
glyph.bearingY = face->glyph->metrics.horiBearingY;
|
||||
glyph.advance = face->glyph->metrics.horiAdvance;
|
||||
glyphs[charcode] = glyph;
|
||||
glyphs[glyphIdentity] = glyph;
|
||||
}
|
||||
|
||||
// This function takes a single contour (defined by firstIndex and
|
||||
|
@ -635,49 +834,6 @@ class Font {
|
|||
}
|
||||
}
|
||||
|
||||
// Decodes the first Unicode code point from the null-terminated UTF-8 string *text and advances *text to point at the next code point.
|
||||
// If the encoding is invalid, advances *text by one byte and returns 0.
|
||||
// *text should not be empty, because it will be advanced past the null terminator.
|
||||
uint32_t decodeCharcode(const char * * text){
|
||||
uint8_t first = static_cast <uint8_t>((*text)[0]);
|
||||
|
||||
// Fast-path for ASCII.
|
||||
if(first < 128){
|
||||
(*text)++;
|
||||
return static_cast <uint32_t>(first);
|
||||
}
|
||||
|
||||
// This could probably be optimized a bit.
|
||||
uint32_t result;
|
||||
int size;
|
||||
if((first & 0xE0) == 0xC0){ // 110xxxxx
|
||||
result = first & 0x1F;
|
||||
size = 2;
|
||||
}else if((first & 0xF0) == 0xE0){ // 1110xxxx
|
||||
result = first & 0x0F;
|
||||
size = 3;
|
||||
}else if((first & 0xF8) == 0xF0){ // 11110xxx
|
||||
result = first & 0x07;
|
||||
size = 4;
|
||||
}else{
|
||||
// Invalid encoding.
|
||||
(*text)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int i = 1; i < size; i++){
|
||||
uint8_t value = static_cast <uint8_t>((*text)[i]);
|
||||
// Invalid encoding (also catches a null terminator in the middle of a code point).
|
||||
if((value & 0xC0) != 0x80){ // 10xxxxxx
|
||||
(*text)++;
|
||||
return 0;
|
||||
}
|
||||
result = (result << 6) | (value & 0x3F);
|
||||
}
|
||||
|
||||
(*text) += size;
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
void drawSetup(){
|
||||
|
@ -715,7 +871,7 @@ class Font {
|
|||
}
|
||||
|
||||
void collectVerticesAndIndices(const glm::vec3 & position,
|
||||
const std::string & text,
|
||||
const std::vector <GlyphIdentity> & variationText,
|
||||
std::vector <BufferVertex> & vertices,
|
||||
std::vector <int32_t> & indices,
|
||||
const bool vFlip = false,
|
||||
|
@ -725,9 +881,12 @@ class Font {
|
|||
float originalX = x;
|
||||
|
||||
FT_UInt previous = 0;
|
||||
for(const char * textIt = text.c_str(); *textIt != '\0';){
|
||||
for(const GlyphIdentity & glyphIdentity : variationText){
|
||||
if(glyphIdentity.charcode == '\0'){
|
||||
break;
|
||||
}
|
||||
float letterFontSize_px = fontSize_px; // can be individual
|
||||
uint32_t charcode = decodeCharcode(&textIt);
|
||||
const uint32_t & charcode = glyphIdentity.charcode;
|
||||
|
||||
if(charcode == '\r'){
|
||||
continue;
|
||||
|
@ -742,8 +901,9 @@ class Font {
|
|||
continue;
|
||||
}
|
||||
|
||||
auto glyphIt = glyphs.find(charcode);
|
||||
Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs[0] : glyphIt->second;
|
||||
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;
|
||||
|
@ -805,159 +965,76 @@ class Font {
|
|||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void draw(float x, float y, float z, const std::string & text, bool vFlip = false, float fontSize_px = 42){
|
||||
float originalX = x;
|
||||
|
||||
glBindVertexArray(vao);
|
||||
|
||||
std::vector <BufferVertex> vertices;
|
||||
std::vector <int32_t> indices;
|
||||
|
||||
FT_UInt previous = 0;
|
||||
for(const char * textIt = text.c_str(); *textIt != '\0';){
|
||||
float letterFontSize_px = fontSize_px; // can be individual
|
||||
uint32_t charcode = decodeCharcode(&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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = x + u0 * worldSize * letterFontSize_px;
|
||||
float y0 = y + v0 * worldSize * letterFontSize_px;
|
||||
float x1 = x + u1 * worldSize * letterFontSize_px;
|
||||
float y1 = y + v1 * worldSize * letterFontSize_px;
|
||||
|
||||
if(vFlip){
|
||||
float _v = v0;
|
||||
v0 = v1;
|
||||
v1 = _v;
|
||||
|
||||
y0 = y - v0 * worldSize * letterFontSize_px;
|
||||
y1 = y - v1 * worldSize * letterFontSize_px;
|
||||
}
|
||||
|
||||
int32_t base = static_cast <int32_t>(vertices.size());
|
||||
vertices.push_back(BufferVertex{x0, y0, u0, v0, glyph.bufferIndex});
|
||||
vertices.push_back(BufferVertex{x1, y0, u1, v0, glyph.bufferIndex});
|
||||
vertices.push_back(BufferVertex{x1, y1, u1, v1, glyph.bufferIndex});
|
||||
vertices.push_back(BufferVertex{x0, y1, u0, v1, glyph.bufferIndex});
|
||||
|
||||
indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base});
|
||||
}
|
||||
|
||||
x += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize;
|
||||
previous = glyph.index;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(BufferVertex) * vertices.size(), vertices.data(), GL_STREAM_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * indices.size(), indices.data(), GL_STREAM_DRAW);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
struct BoundingBox {
|
||||
float minX, minY, maxX, maxY;
|
||||
};
|
||||
|
||||
BoundingBox measure(float x, float y, const std::string & text){
|
||||
BoundingBox bb;
|
||||
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();
|
||||
cerr << "ofxGPUFont::Font::BoundingBox not implemented" << endl;
|
||||
cout << "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;
|
||||
//float originalX = x;
|
||||
|
||||
FT_UInt previous = 0;
|
||||
for(const char * textIt = text.c_str(); *textIt != '\0';){
|
||||
uint32_t charcode = decodeCharcode(&textIt);
|
||||
//FT_UInt previous = 0;
|
||||
//for(const char * textIt = text.c_str(); *textIt != '\0';){
|
||||
//uint32_t charcode = decodeCharcodes(&textIt);
|
||||
|
||||
if(charcode == '\r'){
|
||||
continue;
|
||||
}
|
||||
//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;
|
||||
}
|
||||
//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;
|
||||
//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;
|
||||
}
|
||||
}
|
||||
//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;
|
||||
//// 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;
|
||||
//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;
|
||||
}
|
||||
//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;
|
||||
}
|
||||
//x += (float)glyph.advance / emSize * worldSize;
|
||||
//previous = glyph.index;
|
||||
//}
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
@ -996,7 +1073,8 @@ class Font {
|
|||
|
||||
std::vector <BufferGlyph> bufferGlyphs;
|
||||
std::vector <BufferCurve> bufferCurves;
|
||||
std::unordered_map <uint32_t, Glyph> glyphs;
|
||||
//std::unordered_map <uint32_t, Glyph> glyphs;
|
||||
std::unordered_map <GlyphIdentity, Glyph> glyphs;
|
||||
|
||||
public:
|
||||
// ID of the shader program to use.
|
||||
|
@ -1023,12 +1101,11 @@ static std::shared_ptr <Font> loadFont(FT_Library & library,
|
|||
return std::make_shared <Font>(face, gpuTextureOffset, worldSize, hinting);
|
||||
}
|
||||
|
||||
static void tryUpdateMainFont(FT_Library & library,
|
||||
|
||||
static void initializeFont(FT_Library & library,
|
||||
const std::string & filename,
|
||||
const string & mainText,
|
||||
shared_ptr <Font> & mainFont,
|
||||
int gpuTextureOffset){
|
||||
{
|
||||
cout << "tryUpdateMainFont" << endl;
|
||||
auto font = loadFont(library, filename, gpuTextureOffset);
|
||||
if(!font){
|
||||
|
@ -1037,11 +1114,6 @@ static void tryUpdateMainFont(FT_Library & library,
|
|||
|
||||
font->dilation = 0.1f;
|
||||
|
||||
if(mainText != ""){
|
||||
font->prepareGlyphsForText(mainText);
|
||||
}
|
||||
|
||||
mainFont = std::move(font);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue