void TextureFont::MeasureCharacterPos(const std::string &str, int charIndex, float &charX, float &charY) { assert(charIndex >= 0); float x = 0.0f, y = GetHeight(); int i = 0; Uint32 chr; int len = utf8_decode_char(&chr, &str[i]); while (str[i] && (i < charIndex)) { Uint32 nextChar; i += len; len = utf8_decode_char(&nextChar, &str[i]); assert(!str[i] || len); // assert valid encoding if (chr == '\n') { x = 0.0f; y += GetHeight(); } else { const Glyph &glyph = GetGlyph(chr); float advance = glyph.advX; if (nextChar != '\n' && nextChar != '\0') advance += GetKern(glyph, GetGlyph(nextChar)); x += advance; } chr = nextChar; } charX = x; charY = y; }
int TextureFont::PickCharacter(const std::string &str, float mouseX, float mouseY) { assert(mouseX >= 0.0f && mouseY >= 0.0f); // at the point of the mouse in-box test, the vars have the following values: // i1: the index of the character being tested // i2: the index of the next character // charBytes: the number of bytes used to encode the next character // right: the right edge of the box being tested // bottom: the bottom of the box being tested // x: the x-coordinate of the next character // chr1: the Unicode value of the character being tested // chr2: the Unicode value of the next character Uint32 chr2 = '\n'; // pretend we've just had a new line float bottom = 0.0f, x = 0.0f; int i2 = 0, charBytes = 0; do { int i1 = i2; Uint32 chr1 = chr2; // read the next character i2 += charBytes; charBytes = utf8_decode_char(&chr2, &str[i2]); assert(!str[i2] || charBytes); // assert valid encoding float right; if (chr1 == '\n') { right = std::numeric_limits<float>::max(); x = 0.0f; } else { const Glyph &glyph = GetGlyph(chr1); float advance = glyph.advX; if (chr2 != '\n' && chr2 != '\0') advance += GetKern(glyph, GetGlyph(chr2)); right = x + (advance / 2.0f); x += advance; } if ((mouseY < bottom) && (mouseX < right)) return i1; if (chr1 == '\n') bottom += GetHeight(); } while (charBytes); return i2; }
void TextureFont::RenderString(const char *str, float x, float y, const Color &color) { PROFILE_SCOPED() m_vertices.Clear(); float alpha_f = color.a / 255.0f; const Color premult_color = Color(color.r * alpha_f, color.g * alpha_f, color.b * alpha_f, color.a); float px = x; float py = y; int i = 0; while (str[i]) { if (str[i] == '\n') { px = x; py += GetHeight(); i++; } else { Uint32 chr; int n = utf8_decode_char(&chr, &str[i]); assert(n); i += n; const Glyph &glyph = GetGlyph(chr); AddGlyphGeometry(&m_vertices, glyph, roundf(px), py, premult_color); if (str[i]) { Uint32 chr2; n = utf8_decode_char(&chr2, &str[i]); assert(n); px += GetKern(glyph, GetGlyph(chr2)); } px += glyph.advX; } } m_renderer->DrawTriangles(&m_vertices, m_renderState, m_mat.get()); }
void FormatText::RenderLine(FTTextureFont* font, float x, float y, const char* text, int start, int finish) { assert(start < finish); FTTextureFontImpl* impl = (FTTextureFontImpl*) font->GetImpl(); FTGlyphContainer* glyphList = impl->GetGlyphList(); FTCharmap* charMap = glyphList->GetCharmap(); FTVector<FTGlyph*>* glyphVector = glyphList->GetGlyphVector(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); #ifndef ANDROID glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); FTTextureGlyphImpl::ResetActiveTexture(); #endif #ifdef ANDROID impl->PreRender(); #endif int prevC = -1; for(int i = start; i < finish; i++) { int c = text[i]; if(prevC != -1) { x += GetKern(font, prevC, c); } { // Actually do the render. unsigned int charCode = (unsigned int) c; // This isn't just a check! It's lazy loader if(!impl->CheckGlyph(charCode)) { return; } unsigned int index = charMap->GlyphListIndex(charCode); //FTTextureGlyphImpl::ResetActiveTexture(); (*glyphVector)[index]->Render(FTPoint(x, y), FTGL::RENDER_ALL); } prevC = c; } #ifndef ANDROID glPopAttrib(); #endif #ifdef ANDROID impl->PostRender(); #endif return; }
// Returns the cursor position in the text void FormatText::NextLine(FTTextureFont* font, const char* text, unsigned int cursor, float maxwidth, int* outStart, int* outFinish, float* outPixelWidth) { assert(outFinish); assert(outPixelWidth); assert(text); assert(font); // // HACKISH // // Ignore leading space on a line. // This stops formating "Hello World" like: // "Hello" // " World" // When left aligned. if(IsWhiteSpace(text[cursor])) { cursor++; } // // END HACKISH // unsigned int start = cursor; unsigned int finish = cursor; int prevC = -1; int prevNonWhite = -1; float pixelWidth = 0; float pixelWidthStart = 0; for (int i = cursor; text[i] != '\0'; i++) { int c = text[i]; if(IsWhiteSpace(c)) { start = (unsigned int) std::max((int)cursor, i - 1); pixelWidthStart = pixelWidth; prevNonWhite = prevC; } if(prevC != -1) { float kern = GetKern(font, prevC, c); float finishW = CharPixelWidth(font, c); if(start == cursor or pixelWidth + kern + finishW <= maxwidth) { pixelWidth = pixelWidth + kern; } else { finishW = CharPixelWidth(font, prevNonWhite); // From cursor to start of the last word. (*outStart) = cursor; (*outFinish) = start + 1; (*outPixelWidth) = pixelWidthStart + finishW; return; } } prevC = c; finish++; } float finishW = 0; if(prevC != -1) { finishW = CharPixelWidth(font, prevC); } // From cursor to last word (*outStart) = cursor; (*outFinish) = finish; (*outPixelWidth) = pixelWidth + finishW; return; }