mirror of
https://github.com/raysan5/raylib.git
synced 2025-09-13 14:58:15 +00:00
274 lines
11 KiB
C
274 lines
11 KiB
C
/*******************************************************************************************
|
|
*
|
|
* raylib [text] example - inline styling
|
|
*
|
|
* Example complexity rating: [★★★☆] 3/4
|
|
*
|
|
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
|
|
*
|
|
* Example contributed by Wagner Barongello (@SultansOfCode) and reviewed by Ramon Santamaria (@raysan5)
|
|
*
|
|
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
|
* BSD-like license that allows static linking with closed source software
|
|
*
|
|
* Copyright (c) 2025 Wagner Barongello (@SultansOfCode) and Ramon Santamaria (@raysan5)
|
|
*
|
|
********************************************************************************************/
|
|
|
|
#include "raylib.h"
|
|
|
|
#include <stdlib.h> // Required for: strtoul(), NULL
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Module Functions Declaration
|
|
//----------------------------------------------------------------------------------
|
|
static void DrawTextStyled(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color color);
|
|
static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, float spacing);
|
|
|
|
//------------------------------------------------------------------------------------
|
|
// Program main entry point
|
|
//------------------------------------------------------------------------------------
|
|
int main(void)
|
|
{
|
|
// Initialization
|
|
//--------------------------------------------------------------------------------------
|
|
const int screenWidth = 800;
|
|
const int screenHeight = 450;
|
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [text] example - inline styling");
|
|
|
|
Vector2 textSize = { 0 }; // Measure text box for provided font and text
|
|
Color colRandom = RED; // Random color used on text
|
|
int frameCounter = 0; // Used to generate a new random color every certain frames
|
|
|
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// Main game loop
|
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
|
{
|
|
// Update
|
|
//----------------------------------------------------------------------------------
|
|
frameCounter++;
|
|
|
|
if ((frameCounter%20) == 0)
|
|
{
|
|
colRandom.r = (unsigned char)GetRandomValue(0, 255);
|
|
colRandom.g = (unsigned char)GetRandomValue(0, 255);
|
|
colRandom.b = (unsigned char)GetRandomValue(0, 255);
|
|
colRandom.a = 255;
|
|
}
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Draw
|
|
//----------------------------------------------------------------------------------
|
|
BeginDrawing();
|
|
|
|
ClearBackground(RAYWHITE);
|
|
|
|
// Text inline styling strategy used: [ ] delimiters for format
|
|
// - Define foreground color: [cRRGGBBAA]
|
|
// - Define background color: [bRRGGBBAA]
|
|
// - Reset formating: [r]
|
|
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
|
|
|
|
DrawTextStyled(GetFontDefault(), "This changes the [cFF0000FF]foreground color[r] of provided text!!!",
|
|
(Vector2){ 100, 80 }, 20.0f, 2.0f, BLACK);
|
|
|
|
DrawTextStyled(GetFontDefault(), "This changes the [bFF00FFFF]background color[r] of provided text!!!",
|
|
(Vector2){ 100, 120 }, 20.0f, 2.0f, BLACK);
|
|
|
|
DrawTextStyled(GetFontDefault(), "This changes the [c00ff00ff][bff0000ff]foreground and background colors[r]!!!",
|
|
(Vector2){ 100, 160 }, 20.0f, 2.0f, BLACK);
|
|
|
|
// Get pointer to formated text
|
|
const char *text = TextFormat("Let's be [c%02x%02x%02xFF]CREATIVE[r] !!!", colRandom.r, colRandom.g, colRandom.b);
|
|
DrawTextStyled(GetFontDefault(), text, (Vector2){ 100, 220 }, 40.0f, 2.0f, BLACK);
|
|
|
|
textSize = MeasureTextStyled(GetFontDefault(), text, 40.0f, 2.0f);
|
|
DrawRectangleLines(100, 220, textSize.x, textSize.y, GREEN);
|
|
|
|
EndDrawing();
|
|
//----------------------------------------------------------------------------------
|
|
}
|
|
|
|
// De-Initialization
|
|
//--------------------------------------------------------------------------------------
|
|
CloseWindow(); // Close window and OpenGL context
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Module Functions Definition
|
|
//----------------------------------------------------------------------------------
|
|
// Draw text using inline styling
|
|
// PARAM: color is the default text color, background color is BLANK by default
|
|
static void DrawTextStyled(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color color)
|
|
{
|
|
// Text inline styling strategy used: [ ] delimiters for format
|
|
// - Define foreground color: [cRRGGBBAA]
|
|
// - Define background color: [bRRGGBBAA]
|
|
// - Reset formating: [r]
|
|
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
|
|
|
|
if (font.texture.id == 0) font = GetFontDefault();
|
|
|
|
int textLen = TextLength(text);
|
|
|
|
Color colFront = color;
|
|
Color colBack = BLANK;
|
|
int backRecPadding = 4; // Background rectangle padding
|
|
|
|
float textOffsetY = 0.0f;
|
|
float textOffsetX = 0.0f;
|
|
float textLineSpacing = 0.0f;
|
|
float scaleFactor = fontSize/font.baseSize;
|
|
|
|
for (int i = 0; i < textLen;)
|
|
{
|
|
int codepointByteCount = 0;
|
|
int codepoint = GetCodepointNext(&text[i], &codepointByteCount);
|
|
|
|
if (codepoint == '\n')
|
|
{
|
|
textOffsetY += (fontSize + textLineSpacing);
|
|
textOffsetX = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if (codepoint == '[') // Process pipe styling
|
|
{
|
|
if (((i + 2) < textLen) && (text[i + 1] == 'r') && (text[i + 2] == ']')) // Reset styling
|
|
{
|
|
colFront = color;
|
|
colBack = BLANK;
|
|
|
|
i += 3; // Skip "[r]"
|
|
continue; // Do not draw characters
|
|
}
|
|
else if (((i + 1) < textLen) && ((text[i + 1] == 'c') || (text[i + 1] == 'b')))
|
|
{
|
|
i += 2; // Skip "[c" or "[b" to start parsing color
|
|
|
|
// Parse following color
|
|
char colHexText[9] = { 0 };
|
|
char *textPtr = &text[i]; // Color should start here, let's see...
|
|
|
|
int colHexCount = 0;
|
|
while ((textPtr != NULL) && (textPtr[colHexCount] != '\0') && (textPtr[colHexCount] != ']'))
|
|
{
|
|
if (((textPtr[colHexCount] >= '0') && (textPtr[colHexCount] <= '9')) ||
|
|
((textPtr[colHexCount] >= 'A') && (textPtr[colHexCount] <= 'F')) ||
|
|
((textPtr[colHexCount] >= 'a') && (textPtr[colHexCount] <= 'f')))
|
|
{
|
|
colHexText[colHexCount] = textPtr[colHexCount];
|
|
colHexCount++;
|
|
}
|
|
else break; // Only affects while loop
|
|
}
|
|
|
|
// Convert hex color text into actual Color
|
|
unsigned int colHexValue = strtoul(colHexText, NULL, 16);
|
|
if (text[i - 1] == 'c') colFront = GetColor(colHexValue);
|
|
else if (text[i - 1] == 'b') colBack = GetColor(colHexValue);
|
|
|
|
i += (colHexCount + 1); // Skip color value retrieved and ']'
|
|
continue; // Do not draw characters
|
|
}
|
|
}
|
|
|
|
int index = GetGlyphIndex(font, codepoint);
|
|
float increaseX = 0.0f;
|
|
|
|
if (font.glyphs[index].advanceX == 0) increaseX = ((float)font.recs[index].width*scaleFactor + spacing);
|
|
else increaseX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
|
|
|
|
// Draw background rectangle color (if required)
|
|
if (colBack.a > 0) DrawRectangle(position.x + textOffsetX, position.y + textOffsetY - backRecPadding, increaseX, fontSize + 2*backRecPadding, colBack);
|
|
|
|
if ((codepoint != ' ') && (codepoint != '\t'))
|
|
{
|
|
DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, colFront);
|
|
}
|
|
|
|
textOffsetX += increaseX;
|
|
}
|
|
|
|
i += codepointByteCount;
|
|
}
|
|
}
|
|
|
|
// Measure inline styled text
|
|
// NOTE: Measuring styled text requires skipping styling data
|
|
// WARNING: Not considering line breaks
|
|
static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, float spacing)
|
|
{
|
|
Vector2 textSize = { 0 };
|
|
|
|
if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
|
|
|
|
int textLen = TextLength(text); // Get size in bytes of text
|
|
float textLineSpacing = fontSize*1.5f;
|
|
|
|
float textWidth = 0.0f;
|
|
float textHeight = fontSize;
|
|
float scaleFactor = fontSize/(float)font.baseSize;
|
|
|
|
int codepoint = 0; // Current character
|
|
int index = 0; // Index position in sprite font
|
|
int validCodepointCounter = 0;
|
|
|
|
for (int i = 0; i < textLen;)
|
|
{
|
|
int codepointByteCount = 0;
|
|
codepoint = GetCodepointNext(&text[i], &codepointByteCount);
|
|
|
|
if (codepoint == '[') // Ignore pipe inline styling
|
|
{
|
|
if (((i + 2) < textLen) && (text[i + 1] == 'r') && (text[i + 2] == ']')) // Reset styling
|
|
{
|
|
i += 3; // Skip "[r]"
|
|
continue; // Do not measure characters
|
|
}
|
|
else if (((i + 1) < textLen) && ((text[i + 1] == 'c') || (text[i + 1] == 'b')))
|
|
{
|
|
i += 2; // Skip "[c" or "[b" to start parsing color
|
|
|
|
char *textPtr = &text[i]; // Color should start here, let's see...
|
|
|
|
int colHexCount = 0;
|
|
while ((textPtr != NULL) && (textPtr[colHexCount] != '\0') && (textPtr[colHexCount] != ']'))
|
|
{
|
|
if (((textPtr[colHexCount] >= '0') && (textPtr[colHexCount] <= '9')) ||
|
|
((textPtr[colHexCount] >= 'A') && (textPtr[colHexCount] <= 'F')) ||
|
|
((textPtr[colHexCount] >= 'a') && (textPtr[colHexCount] <= 'f')))
|
|
{
|
|
colHexCount++;
|
|
}
|
|
else break; // Only affects while loop
|
|
}
|
|
|
|
i += (colHexCount + 1); // Skip color value retrieved and ']'
|
|
continue; // Do not measure characters
|
|
}
|
|
}
|
|
else if (codepoint != '\n')
|
|
{
|
|
index = GetGlyphIndex(font, codepoint);
|
|
|
|
if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
|
|
else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
|
|
|
|
validCodepointCounter++;
|
|
i += codepointByteCount;
|
|
}
|
|
}
|
|
|
|
textSize.x = textWidth*scaleFactor + (validCodepointCounter - 1)*spacing;
|
|
textSize.y = textHeight;
|
|
|
|
return textSize;
|
|
}
|