From 668ba870e4e84991770a14305317ae0bfafbd777 Mon Sep 17 00:00:00 2001 From: Vlad Adrian Date: Sun, 28 Mar 2021 17:08:14 +0300 Subject: [PATCH] Added draw 3d text example (#1689) --- examples/Makefile | 3 +- .../resources/shaders/glsl330/alphaDiscard.fs | 19 + examples/text/text_draw_3d.c | 751 ++++++++++++++++++ examples/text/text_draw_3d.png | Bin 0 -> 58003 bytes 4 files changed, 772 insertions(+), 1 deletion(-) create mode 100644 examples/text/resources/shaders/glsl330/alphaDiscard.fs create mode 100644 examples/text/text_draw_3d.c create mode 100644 examples/text/text_draw_3d.png diff --git a/examples/Makefile b/examples/Makefile index c8fc3fb2..270f736c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -450,7 +450,8 @@ TEXT = \ text/text_input_box \ text/text_writing_anim \ text/text_rectangle_bounds \ - text/text_unicode + text/text_unicode \ + text/text_draw_3d MODELS = \ models/models_animation \ diff --git a/examples/text/resources/shaders/glsl330/alphaDiscard.fs b/examples/text/resources/shaders/glsl330/alphaDiscard.fs new file mode 100644 index 00000000..d2134a68 --- /dev/null +++ b/examples/text/resources/shaders/glsl330/alphaDiscard.fs @@ -0,0 +1,19 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + vec4 texelColor = texture(texture0, fragTexCoord); + if (texelColor.a == 0.0) discard; + finalColor = texelColor * fragColor * colDiffuse; +} diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c new file mode 100644 index 00000000..3cf5bb6d --- /dev/null +++ b/examples/text/text_draw_3d.c @@ -0,0 +1,751 @@ +/******************************************************************************************* +* +* raylib [text] example - Draw 2D text in 3D +* +* Draw a 2D text in 3D space, each letter is drawn in a quad (or 2 quads if backface is set) +* where the texture coodinates of each quad map to the texture coordinates of the glyphs +* inside the font texture. +* A more efficient approach, i believe, would be to render the text in a render texture and +* map that texture to a plane and render that, or maybe a shader but my method allows more +* flexibility...for example to change position of each letter individually to make somethink +* like a wavy text effect. +* +* Special thanks to: +* @Nighten for the DrawTextStyle() code https://github.com/NightenDushi/Raylib_DrawTextStyle +* Chris Camacho (codifies - http://bedroomcoders.co.uk/) for the alpha discard shader +* +* This example has been created using raylib 3.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (C) 2021 Vlad Adrian (@Demizdor - https://github.com/Demizdor) +* Copyright (C) 2021 Ramon Santamaria (@raysan5) +********************************************************************************************/ + +#include // for NULL +#include // for sinf() +#include "raylib.h" +#include "rlgl.h" + +// To make it work with the older RLGL module just comment the line below +#define RAYLIB_NEW_RLGL + +//-------------------------------------------------------------------------------------- +// Globals +//-------------------------------------------------------------------------------------- +#define LETTER_BOUNDRY_SIZE 0.25f +#define TEXT_MAX_LAYERS 32 + +bool SHOW_LETTER_BOUNDRY = false; +#define LETTER_BOUDRY_COLOR VIOLET +bool SHOW_TEXT_BOUNDRY = false; +//-------------------------------------------------------------------------------------- + + + +//-------------------------------------------------------------------------------------- +// Module Functions Declaration +//-------------------------------------------------------------------------------------- +// Draw a codepoint in 3D space +void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint); +// Draw a 2D text in 3D space +void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint); +// Measure a text in 3D. For some reason `MeasureTextEx()` just doesn't seem to work so i had to use this instead. +Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing); +// Configuration structure for waving the text +typedef struct { + Vector3 waveRange; + Vector3 waveSpeed; + Vector3 waveOffset; +} WaveTextConfig; +// Draw a 2D text in 3D space and wave the parts that start with `~~` and end with `~~`. +// This is a modified version of the original code by @Nighten found here https://github.com/NightenDushi/Raylib_DrawTextStyle +void DrawTextWave3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, WaveTextConfig* config, float time, Color tint); +// Measure a text in 3D ignoring the `~~` chars. +Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing); +// Generates a nice color with a random hue +Color GenerateRandomColor(float s, float v); +//-------------------------------------------------------------------------------------- + + + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT|FLAG_VSYNC_HINT); + InitWindow(screenWidth, screenHeight, "raylib [text] example - draw 2D text in 3D"); + + bool spin = true; // Spin the camera? + bool multicolor = false; // Multicolor mode + + // Define the camera to look into our 3d world + Camera3D camera = { 0 }; + camera.position = (Vector3){ -10.0f, 15.0f, -10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + + SetCameraMode(camera, CAMERA_ORBITAL); + + Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; + Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + + // Use the default font + Font font = GetFontDefault(); + float fontSize = 8.0f; + float fontSpacing = 0.5f; + float lineSpacing = -1.0f; + + // Set the text + char text[64] = "Hello ~~World~~ in 3D!"; + Vector3 tbox = {0}; + int layers = 1; + int quads = 0; + float layerDistance = 0.01f; + + WaveTextConfig wcfg; + wcfg.waveSpeed.x = wcfg.waveSpeed.y = 3.0f; wcfg.waveSpeed.z = 0.5f; + wcfg.waveOffset.x = wcfg.waveOffset.y = wcfg.waveOffset.z = 0.35f; + wcfg.waveRange.x = wcfg.waveRange.y = wcfg.waveRange.z = 0.45f; + + float time = 0.0f; + + // Setup a light and dark color + Color light = MAROON; + Color dark = RED; + + // Load the alpha discard shader + Shader alphaDiscard = LoadShader(NULL, "resources/shaders/glsl330/alphaDiscard.fs"); + + // Array filled with multiple random colors (when multicolor mode is set) + Color multi[TEXT_MAX_LAYERS] = {0}; + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // Handle font files dropped + if (IsFileDropped()) + { + int count = 0; + char **droppedFiles = GetDroppedFiles(&count); + + // NOTE: We only support first ttf file dropped + if (IsFileExtension(droppedFiles[0], ".ttf")) + { + UnloadFont(font); + font = LoadFontEx(droppedFiles[0], fontSize, 0, 0); + } + else if(IsFileExtension(droppedFiles[0], ".fnt")) + { + UnloadFont(font); + font = LoadFont(droppedFiles[0]); + fontSize = font.baseSize; + } + ClearDroppedFiles(); + } + + // Handle Events + if(IsKeyPressed(KEY_F1)) SHOW_LETTER_BOUNDRY = !SHOW_LETTER_BOUNDRY; + if(IsKeyPressed(KEY_F2)) SHOW_TEXT_BOUNDRY = !SHOW_TEXT_BOUNDRY; + if(IsKeyPressed(KEY_F3)) + { + // Handle camera change + spin = !spin; + // we need to reset the camera when changing modes + camera = (Camera3D){ 0 }; + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + + if(spin) + { + camera.position = (Vector3){ -10.0f, 15.0f, -10.0f }; // Camera position + SetCameraMode(camera, CAMERA_ORBITAL); + } + else + { + camera.position = (Vector3){ 10.0f, 10.0f, -10.0f }; // Camera position + SetCameraMode(camera, CAMERA_FREE); + } + } + + // Handle clicking the cube + if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + Ray ray = GetMouseRay(GetMousePosition(), camera); + + // Check collision between ray and box + bool collision = CheckCollisionRayBox(ray, + (BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 }, + (Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }}); + if(collision) + { + // generate new random colors + light = GenerateRandomColor(0.5f, 0.78f); + dark = GenerateRandomColor(0.4f, 0.58f); + } + } + + // Handle text layers changes + if(IsKeyPressed(KEY_HOME)){ if(layers > 1) --layers; } + else if(IsKeyPressed(KEY_END)) { if(layers < TEXT_MAX_LAYERS) ++layers; } + + // Handle text changes + if(IsKeyPressed(KEY_LEFT)) fontSize -= 0.5f; + else if(IsKeyPressed(KEY_RIGHT)) fontSize += 0.5f; + else if(IsKeyPressed(KEY_UP)) fontSpacing -= 0.1f; + else if(IsKeyPressed(KEY_DOWN)) fontSpacing += 0.1f; + else if(IsKeyPressed(KEY_PAGE_UP)) lineSpacing -= 0.1f; + else if(IsKeyPressed(KEY_PAGE_DOWN)) lineSpacing += 0.1f; + else if(IsKeyDown(KEY_INSERT)) layerDistance -= 0.001f; + else if(IsKeyDown(KEY_DELETE)) layerDistance += 0.001f; + else if(IsKeyPressed(KEY_TAB)) + { + // enable /disable multicolor mode + multicolor = !multicolor; + + if(multicolor) + { + // Fill color array with random colors + for(int i=0; i 0) text[len-1] = '\0'; + } + else if(IsKeyPressed(KEY_ENTER)) + { + // handle newline + int len = TextLength(text); + if(len < sizeof(text)-1) { + text[len] = '\n'; + text[len+1] ='\0'; + } + } + else + { + // append only printable chars + int len = TextLength(text); + if(len < sizeof(text)-1) { + text[len] = ch; + text[len+1] ='\0'; + } + } + + // Measure 3D text so we can center it + tbox = MeasureTextWave3D(font, text, fontSize, fontSpacing, lineSpacing); + + UpdateCamera(&camera); // Update camera + quads = 0; // Reset quad counter + time += GetFrameTime(); // Update timer needed by `DrawTextWave3D()` + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + DrawCubeV(cubePosition, cubeSize, dark); + DrawCubeWires(cubePosition, 2.1f, 2.1f, 2.1f, light); + + DrawGrid(10, 2.0f); + + // Use a shader to handle the depth buffer issue with transparent textures + // NOTE: more info at https://bedroomcoders.co.uk/raylib-billboards-advanced-use/ + BeginShaderMode(alphaDiscard); + + // Draw the 3D text above the red cube + rlPushMatrix(); + rlRotatef(90.0f, 1.0f, 0.0f, 0.0f); + rlRotatef(90.0f, 0.0f, 0.0f, -1.0f); + for(int i=0; i", fontSize); + quads += TextLength(opt); + Vector3 m = MeasureText3D(GetFontDefault(), opt, 8.0f, 1.0f, 0.0f); + Vector3 pos = { -m.x/2.0f, 0.01f, 2.0f}; + DrawText3D(GetFontDefault(), opt, pos, 8.0f, 1.0f, 0.0f, false, BLUE); + pos.z += 0.5f + m.z; + + opt = (char*)TextFormat("< SPACING: %2.1f >", fontSpacing); + quads += TextLength(opt); + m = MeasureText3D(GetFontDefault(), opt, 8.0f, 1.0f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 8.0f, 1.0f, 0.0f, false, BLUE); + pos.z += 0.5f + m.z; + + opt = (char*)TextFormat("< LINE: %2.1f >", lineSpacing); + quads += TextLength(opt); + m = MeasureText3D(GetFontDefault(), opt, 8.0f, 1.0f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 8.0f, 1.0f, 0.0f, false, BLUE); + pos.z += 1.0f + m.z; + + opt = (char*)TextFormat("< LBOX: %3s >", slb ?"ON":"OFF"); + quads += TextLength(opt); + m = MeasureText3D(GetFontDefault(), opt, 8.0f, 1.0f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 8.0f, 1.0f, 0.0f, false, RED); + pos.z += 0.5f + m.z; + + opt = (char*)TextFormat("< TBOX: %3s >", SHOW_TEXT_BOUNDRY ?"ON":"OFF"); + quads += TextLength(opt); + m = MeasureText3D(GetFontDefault(), opt, 8.0f, 1.0f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 8.0f, 1.0f, 0.0f, false, RED); + pos.z += 0.5f + m.z; + + opt = (char*)TextFormat("< LAYER DISTANCE: %.3f >", layerDistance); + quads += TextLength(opt); + m = MeasureText3D(GetFontDefault(), opt, 8.0f, 1.0f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 8.0f, 1.0f, 0.0f, false, DARKPURPLE); + rlPopMatrix(); + //------------------------------------------------------------------------- + + // Draw 3D info text (use default font) + //------------------------------------------------------------------------- + opt = "All the text displayed here is in 3D"; + quads += 36; + m = MeasureText3D(GetFontDefault(), opt, 10.0f, 0.5f, 0.0f); + pos = (Vector3){-m.x/2.0f, 0.01f, 2.0f}; + DrawText3D(GetFontDefault(), opt, pos, 10.0f, 0.5f, 0.0f, false, DARKBLUE); + pos.z += 1.5f + m.z; + + opt = "press [Left]/[Right] to change the font size"; + quads += 44; + m = MeasureText3D(GetFontDefault(), opt, 6.0f, 0.5f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 6.0f, 0.5f, 0.0f, false, DARKBLUE); + pos.z += 0.5f + m.z; + + opt = "press [Up]/[Down] to change the font spacing"; + quads += 44; + m = MeasureText3D(GetFontDefault(), opt, 6.0f, 0.5f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 6.0f, 0.5f, 0.0f, false, DARKBLUE); + pos.z += 0.5f + m.z; + + opt = "press [PgUp]/[PgDown] to change the line spacing"; + quads += 48; + m = MeasureText3D(GetFontDefault(), opt, 6.0f, 0.5f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 6.0f, 0.5f, 0.0f, false, DARKBLUE); + pos.z += 0.5f + m.z; + + opt = "press [F1] to toggle the letter boundry"; + quads += 39; + m = MeasureText3D(GetFontDefault(), opt, 6.0f, 0.5f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 6.0f, 0.5f, 0.0f, false, DARKBLUE); + pos.z += 0.5f + m.z; + + opt = "press [F2] to toggle the text boundry"; + quads += 37; + m = MeasureText3D(GetFontDefault(), opt, 6.0f, 0.5f, 0.0f); + pos.x = -m.x/2.0f; + DrawText3D(GetFontDefault(), opt, pos, 6.0f, 0.5f, 0.0f, false, DARKBLUE); + //------------------------------------------------------------------------- + + SHOW_LETTER_BOUNDRY = slb; + EndShaderMode(); + + EndMode3D(); + + // Draw 2D info text & stats + //------------------------------------------------------------------------- + DrawText("Drag & drop a font file to change the font!\nType something, see what happens!\n\n" + "Press [F3] to toggle the camera", 10, 35, 10, BLACK); + + quads += TextLength(text)*2*layers; + char* tmp = (char*)TextFormat("%2i layer(s) | %s camera | %4i quads (%4i verts)", layers, spin ? "ORBITAL" : "FREE", quads, quads*4); + int width = MeasureText(tmp, 10); + DrawText(tmp, screenWidth - 20 - width, 10, 10, DARKGREEN); + + tmp = "[Home]/[End] to add/remove 3D text layers"; + width = MeasureText(tmp, 10); + DrawText(tmp, screenWidth - 20 - width, 25, 10, DARKGRAY); + + tmp = "[Insert]/[Delete] to increase/decrease distance between layers"; + width = MeasureText(tmp, 10); + DrawText(tmp, screenWidth - 20 - width, 40, 10, DARKGRAY); + + tmp = "click the [CUBE] for a random color"; + width = MeasureText(tmp, 10); + DrawText(tmp, screenWidth - 20 - width, 55, 10, DARKGRAY); + + tmp = "[Tab] to toggle multicolor mode"; + width = MeasureText(tmp, 10); + DrawText(tmp, screenWidth - 20 - width, 70, 10, DARKGRAY); + //------------------------------------------------------------------------- + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadFont(font); + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + + + +//-------------------------------------------------------------------------------------- +// Module Functions Definitions +//-------------------------------------------------------------------------------------- + +// Draw codepoint at specified position in 3D space +void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint) +{ + // Character index position in sprite font + // NOTE: In case a codepoint is not available in the font, index returned points to '?' + int index = GetGlyphIndex(font, codepoint); + float scale = fontSize/(float)font.baseSize; + + // Character destination rectangle on screen + // NOTE: We consider charsPadding on drawing + position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale; + position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale; + + // Character source rectangle from font texture atlas + // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects + Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, + font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; + + float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale; + float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale; + + if(font.texture.id > 0) + { + const float x = 0.0f; + const float y = 0.0f; + const float z = 0.0f; + + // normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f) + const float tx = srcRec.x/font.texture.width; + const float ty = srcRec.y/font.texture.height; + const float tw = (srcRec.x+srcRec.width)/font.texture.width; + const float th = (srcRec.y+srcRec.height)/font.texture.height; + + if(SHOW_LETTER_BOUNDRY) + DrawCubeWiresV((Vector3){ position.x+width/2, position.y, position.z+height/2}, (Vector3){width, LETTER_BOUNDRY_SIZE, height}, LETTER_BOUDRY_COLOR); + +#if defined(RAYLIB_NEW_RLGL) + rlCheckRenderBatchLimit(4+4*backface); + rlSetTexture(font.texture.id); +#else + if (rlCheckBufferLimit(4+4*backface)) rlglDraw(); + rlEnableTexture(font.texture.id); +#endif + rlPushMatrix(); + rlTranslatef(position.x, position.y, position.z); + + rlBegin(RL_QUADS); + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + + // Front Face + rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up + rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Left Of The Texture and Quad + rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad + rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad + rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad + + if(backface) + { + // Back Face + rlNormal3f(0.0f, -1.0f, 0.0f); // Normal Pointing Down + rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Right Of The Texture and Quad + rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Left Of The Texture and Quad + rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Left Of The Texture and Quad + rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Right Of The Texture and Quad + } + rlEnd(); + rlPopMatrix(); + +#if defined(RAYLIB_NEW_RLGL) + rlSetTexture(0); +#else + rlDisableTexture(); +#endif + + } +} + + +void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint) +{ + int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop + + float textOffsetY = 0.0f; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scale = fontSize/(float)font.baseSize; + + + for (int i = 0; i < length;) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + + if (codepoint == '\n') + { + // NOTE: Fixed line spacing of 1.5 line-height + // TODO: Support custom line spacing defined by user + textOffsetY += scale + lineSpacing/(float)font.baseSize*scale; + textOffsetX = 0.0f; + } + else + { + if ((codepoint != ' ') && (codepoint != '\t')) + { + DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint); + } + + if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; + else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; + } + + i += codepointByteCount; // Move text bytes counter to next codepoint + } +} + +Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) +{ + int len = TextLength(text); + int tempLen = 0; // Used to count longer text line num chars + int lenCounter = 0; + + + float tempTextWidth = 0.0f; // Used to count longer text line width + + float scale = fontSize/(float)font.baseSize; + float textHeight = scale; + float textWidth = 0.0f; + + int letter = 0; // Current character + int index = 0; // Index position in sprite font + + for (int i = 0; i < len; i++) + { + lenCounter++; + + int next = 0; + letter = GetNextCodepoint(&text[i], &next); + index = GetGlyphIndex(font, letter); + + // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 + if (letter == 0x3f) next = 1; + i += next - 1; + + if (letter != '\n') + { + if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; + else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale; + } + else + { + if (tempTextWidth < textWidth) tempTextWidth = textWidth; + lenCounter = 0; + textWidth = 0.0f; + textHeight += scale + lineSpacing/(float)font.baseSize*scale; + } + + if (tempLen < lenCounter) tempLen = lenCounter; + } + + if (tempTextWidth < textWidth) tempTextWidth = textWidth; + + Vector3 vec = { 0 }; + vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure + vec.y = 0.25f; + vec.z = textHeight; + + return vec; +} + + +void DrawTextWave3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, WaveTextConfig* config, float time, Color tint) +{ + int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop + + float textOffsetY = 0.0f; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scale = fontSize/(float)font.baseSize; + + bool wave = false; + + for (int i = 0, k = 0; i < length; ++k) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + + if (codepoint == '\n') + { + // NOTE: Fixed line spacing of 1.5 line-height + // TODO: Support custom line spacing defined by user + textOffsetY += scale + lineSpacing/(float)font.baseSize*scale; + textOffsetX = 0.0f; + k = 0; + } + else if (codepoint == '~') + { + if (GetNextCodepoint(&text[i+1], &codepointByteCount) == '~') + { + codepointByteCount += 1; + wave = !wave; + } + } + else + { + if ((codepoint != ' ') && (codepoint != '\t')) + { + Vector3 pos = position; + if (wave) // Apply the wave effect + { + pos.x += sinf(time*config->waveSpeed.x-k*config->waveOffset.x)*config->waveRange.x; + pos.y += sinf(time*config->waveSpeed.y-k*config->waveOffset.y)*config->waveRange.y; + pos.z += sinf(time*config->waveSpeed.z-k*config->waveOffset.z)*config->waveRange.z; + } + + DrawTextCodepoint3D(font, codepoint, (Vector3){ pos.x + textOffsetX, pos.y, pos.z + textOffsetY }, fontSize, backface, tint); + } + + if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; + else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; + } + + i += codepointByteCount; // Move text bytes counter to next codepoint + } +} + +Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) +{ + int len = TextLength(text); + int tempLen = 0; // Used to count longer text line num chars + int lenCounter = 0; + + + float tempTextWidth = 0.0f; // Used to count longer text line width + + float scale = fontSize/(float)font.baseSize; + float textHeight = scale; + float textWidth = 0.0f; + + int letter = 0; // Current character + int index = 0; // Index position in sprite font + + for (int i = 0; i < len; i++) + { + lenCounter++; + + int next = 0; + letter = GetNextCodepoint(&text[i], &next); + index = GetGlyphIndex(font, letter); + + // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 + if (letter == 0x3f) next = 1; + i += next - 1; + + if (letter != '\n') + { + if(letter == '~' && GetNextCodepoint(&text[i+1], &next) == '~') + { + i++; + } + else + { + if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; + else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale; + } + } + else + { + if (tempTextWidth < textWidth) tempTextWidth = textWidth; + lenCounter = 0; + textWidth = 0.0f; + textHeight += scale + lineSpacing/(float)font.baseSize*scale; + } + + if (tempLen < lenCounter) tempLen = lenCounter; + } + + if (tempTextWidth < textWidth) tempTextWidth = textWidth; + + Vector3 vec = { 0 }; + vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure + vec.y = 0.25f; + vec.z = textHeight; + + return vec; +} + +Color GenerateRandomColor(float s, float v) +{ + const float Phi = 0.618033988749895; // golden ratio conjugate + float h = GetRandomValue(0, 360); + h = fmodf((h + h*Phi), 360.0f); + return ColorFromHSV(h, s, v); +} diff --git a/examples/text/text_draw_3d.png b/examples/text/text_draw_3d.png new file mode 100644 index 0000000000000000000000000000000000000000..ce92959808c3277d3dace4e329283c14de9eba25 GIT binary patch literal 58003 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

>35q$q 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