Add and optimize text rendering functions

New functions operate on two char*'s in the event strings are not null terminated
* MeasureTextViewEx
* MeasureTextView
* DrawTextViewEx
* DrawTextViewPro

Rewrote some conditional operations as math in DrawTexturePro to try to get compiler
to generate branchless code even in debug mode.
This commit is contained in:
Andersama 2023-04-10 15:49:30 -07:00
parent 796d96408b
commit da9c3b379e
3 changed files with 82 additions and 29 deletions

View File

@ -1362,16 +1362,22 @@ RLAPI void UnloadFont(Font font);
RLAPI bool ExportFontAsCode(Font font, const char *fileName); // Export font as code file, returns true on success
// Text drawing functions
RLAPI void DrawTextViewEx(Font font, const char* text, const char* textEnd, Vector2 position, float fontSize, float spacing, Color tint);
RLAPI void DrawFPS(int posX, int posY); // Draw current FPS
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation)
RLAPI void DrawTextViewPro(Font font, const char* text, const char* textEnd, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint);
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint)
// Text font info functions
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
RLAPI int MeasureTextView(const char* text, const char* textEnd, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextViewEx(Font font, const char* text, const char* textEnd, float fontSize, float spacing); // Measure string size for Font
RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found
RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found

View File

@ -1015,8 +1015,7 @@ void DrawFPS(int posX, int posY)
Color color = LIME; // Good FPS
int fps = GetFPS();
if ((fps < 30) && (fps >= 15)) color = ORANGE; // Warning FPS
else if (fps < 15) color = RED; // Low FPS
color = (fps >= 30) ? color : (fps >= 15) ? ORANGE : RED;
DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, color);
}
@ -1039,20 +1038,18 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
}
}
// Draw text using Font
// NOTE: chars spacing is NOT proportional to fontSize
void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
void DrawTextViewEx(Font font, const char* text, const char* textEnd, Vector2 position, float fontSize, float spacing, Color tint)
{
if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font
int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop
int bytes = textEnd - text; // Total size in bytes of the text, scanned by codepoints in loop
int textOffsetY = 0; // Offset between lines (on linebreak '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
float scaleFactor = fontSize / font.baseSize; // Character quad scaling factor
for (int i = 0; i < size;)
for (int i = 0; i < bytes;)
{
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
@ -1067,24 +1064,46 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
{
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
textOffsetY += (int)((font.baseSize + font.baseSize / 2.0f) * scaleFactor);
textOffsetX = 0.0f;
}
else
{
if ((codepoint != ' ') && (codepoint != '\t'))
{
DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
DrawTextCodepoint(font, codepoint, (Vector2) { position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
}
if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width * scaleFactor + spacing);
else textOffsetX += ((float)font.glyphs[index].advanceX * scaleFactor + spacing);
}
i += codepointByteCount; // Move text bytes counter to next codepoint
}
}
// Draw text using Font and pro parameters (rotation)
void DrawTextViewPro(Font font, const char* text, const char* textEnd, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint)
{
rlPushMatrix();
rlTranslatef(position.x, position.y, 0.0f);
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
rlTranslatef(-origin.x, -origin.y, 0.0f);
DrawTextViewEx(font, text, textEnd, (Vector2) { 0.0f, 0.0f }, fontSize, spacing, tint);
rlPopMatrix();
}
// Draw text using Font
// NOTE: chars spacing is NOT proportional to fontSize
void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
{
int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop
DrawTextViewEx(font, text, text + size, position, fontSize, spacing, tint);
}
// Draw text using Font and pro parameters (rotation)
void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint)
{
@ -1173,14 +1192,32 @@ int MeasureText(const char *text, int fontSize)
return (int)textSize.x;
}
// Measure string width for default font
int MeasureTextView(const char* text, const char* textEnd, int fontSize) {
Vector2 textSize = { 0.0f, 0.0f };
// Check if default font has been loaded
if (GetFontDefault().texture.id != 0)
{
int defaultFontSize = 10; // Default Font chars height in pixel
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize / defaultFontSize;
textSize = MeasureTextViewEx(GetFontDefault(), text, textEnd, (float)fontSize, (float)spacing);
}
return (int)textSize.x;
}
// Measure string size for Font
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
Vector2 MeasureTextViewEx(Font font, const char* text, const char* textEnd, float fontSize, float spacing)
{
Vector2 textSize = { 0 };
if ((font.texture.id == 0) || (text == NULL)) return textSize;
int size = TextLength(text); // Get size in bytes of text
//int size = TextLength(text);
int size = textEnd - text; // Get size in bytes of text
int tempByteCounter = 0; // Used to count longer text line num chars
int byteCounter = 0;
@ -1188,7 +1225,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
float tempTextWidth = 0.0f; // Used to count longer text line width
float textHeight = (float)font.baseSize;
float scaleFactor = fontSize/(float)font.baseSize;
float scaleFactor = fontSize / (float)font.baseSize;
int letter = 0; // Current character
int index = 0; // Index position in sprite font
@ -1216,7 +1253,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
byteCounter = 0;
textWidth = 0;
textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
textHeight += ((float)font.baseSize * 1.5f); // NOTE: Fixed line spacing of 1.5 lines
}
if (tempByteCounter < byteCounter) tempByteCounter = byteCounter;
@ -1224,11 +1261,16 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); // Adds chars spacing to measure
textSize.y = textHeight*scaleFactor;
textSize.x = tempTextWidth * scaleFactor + (float)((tempByteCounter - 1) * spacing); // Adds chars spacing to measure
textSize.y = textHeight * scaleFactor;
return textSize;
}
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
{
int size = TextLength(text); // Get size in bytes of text
return MeasureTextViewEx(font, text, text + size, fontSize, spacing);
}
// Get index position for a unicode character on font
// NOTE: If codepoint is not found in the font it fallbacks to '?'

View File

@ -3546,10 +3546,10 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
float width = (float)texture.width;
float height = (float)texture.height;
bool flipX = false;
bool flipX = source.width < 0;
if (source.width < 0) { flipX = true; source.width *= -1; }
if (source.height < 0) source.y -= source.height;
source.width = flipX ? source.width * -1 : source.width;
source.y -= (source.height < 0) ? source.height : 0.0f;
Vector2 topLeft = { 0 };
Vector2 topRight = { 0 };
@ -3594,24 +3594,29 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
float right_edge_x = (source.x + source.width) / width;
float left_edge_x = source.x / width;
float bottom_edge_y = (source.y + source.height) / height;
float top_edge_y = source.y / height;
// Should communicate the non-branchy version of this expression to the compiler
float l_edge = (flipX * right_edge_x) + (!flipX * left_edge_x);//flipX ? right_edge_x : left_edge_x;
float r_edge = (flipX * left_edge_x) + (!flipX * right_edge_x);//flipX ? left_edge_x : right_edge_x;
// Top-left corner for texture and quad
if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
else rlTexCoord2f(source.x/width, source.y/height);
rlTexCoord2f(l_edge, top_edge_y);
rlVertex2f(topLeft.x, topLeft.y);
// Bottom-left corner for texture and quad
if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
rlTexCoord2f(l_edge, bottom_edge_y);
rlVertex2f(bottomLeft.x, bottomLeft.y);
// Bottom-right corner for texture and quad
if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
rlTexCoord2f(r_edge, bottom_edge_y);
rlVertex2f(bottomRight.x, bottomRight.y);
// Top-right corner for texture and quad
if (flipX) rlTexCoord2f(source.x/width, source.y/height);
else rlTexCoord2f((source.x + source.width)/width, source.y/height);
rlTexCoord2f(r_edge, top_edge_y);
rlVertex2f(topRight.x, topRight.y);
rlEnd();