std::string Encode(const std::string& rawString) { char encodingBuffer[4] = { '%', '\0', '\0', '\0' }; std::size_t rawLen = rawString.size(); std::string encodedString; encodedString.reserve(rawLen); for (std::size_t i = 0; i < rawLen; ++i) { char curChar = rawString[i]; if (curChar == ' ') encodedString += '+'; else if (isalpha(curChar) || isdigit(curChar) || IsSpecialCharacter(curChar)) encodedString += curChar; else { unsigned int temp = static_cast<unsigned int>(curChar); encodingBuffer[1] = ConvertToHexDigit(temp / 0x10); encodingBuffer[2] = ConvertToHexDigit(temp % 0x10); encodedString += encodingBuffer; } } return encodedString; }
void FontRenderable::GetStringRect(const char* str, const Font* fnt, float scale, FontAlignment alignment, Math::FRECT& inout) { unsigned int lineHeight = fnt->GetLineHeight(); NormalizeScaling(fnt, scale); inout.bottomRight = inout.topLeft; inout.bottomRight.y -= scale * lineHeight; glm::vec3 pos(inout.topLeft.x, inout.bottomRight.y, 0.0f); while (*str) { if (fnt->IsValidCharacter(*str)) { if (!IsSpecialCharacter(*str)) { pos.x += scale * fnt->GetCharDescriptor(*str).XAdvance; } else { ProccessSpecialCharacter(*str, scale, lineHeight, glm::vec3(inout.topLeft, 0.0f), pos); inout.bottomRight.y = glm::min(inout.bottomRight.y, pos.y); } inout.bottomRight.x = glm::max(inout.bottomRight.x, pos.x); } str++; } if (alignment != FontAlignment::Left) { glm::vec2 offset; AlignTextPos(inout.bottomRight.x - inout.topLeft.x, alignment, offset); inout.topLeft += offset; inout.bottomRight += offset; } }
void FontRenderable::Render(const Mesh& mesh, ApplyShader& shader, const IResource* resource) { assert(resource != nullptr); const Font* fnt = static_cast<const Font*>(resource->QueryInterface(ResourceType::Font)); assert("Invalid resource selected" && (fnt != nullptr)); // Text to be rendered const char* str = text.c_str(); glm::vec3 oldPos = pos; // If the text needs to be aligned to center or right if (alignment != FontAlignment::Left) { Math::FRECT drawRect(glm::vec2(oldPos.x, oldPos.y)); GetStringRect(str, fnt, scale, alignment, drawRect); oldPos.x = drawRect.topLeft.x; } // World pos of aligned text to be rendered glm::vec3 posW = oldPos; char prevChar = 0; NormalizeScaling(fnt, scale); shader->SetColor(color); // Loop over the entire string while (*str) { if (fnt->IsValidCharacter(*str)) { if (!IsSpecialCharacter(*str)) { // Font info about the character to draw const CharDescriptor& charInfo = fnt->GetCharDescriptor(*str); int kerningOffset = fnt->GetKerningPairOffset(prevChar, *str); // Calculate position of text glm::vec3 posTopLeft(posW.x + (charInfo.XOffset + kerningOffset) * scale, posW.y - charInfo.YOffset * scale, posW.z); glm::vec3 posBottomRight(posTopLeft.x + charInfo.Width * scale, posTopLeft.y - charInfo.Height * scale, posW.z); // Advance position after the current character posW.x += charInfo.XAdvance * scale; // Build transformation matrix to give to the shader glm::mat4 T = glm::translate(glm::vec3((posTopLeft + posBottomRight) / 2.0f)); T = glm::scale(T, glm::vec3(glm::abs(posBottomRight - posTopLeft))); // Give data to shader shader->SetValue("transformation", T); shader->SetValue("charInfo.pos", glm::vec2(charInfo.x, charInfo.y)); shader->SetValue("charInfo.size", glm::vec2(charInfo.Width, charInfo.Height)); // Render a single character of the string mesh.Draw(); } else { ProccessSpecialCharacter(*str, scale, fnt->GetLineHeight(), oldPos, posW); } prevChar = *str; } str++; } }