Files
reilua-enhanced/src/text.c
2024-05-10 11:13:32 +03:00

1294 lines
31 KiB
C

#include "main.h"
#include "state.h"
#include "text.h"
#include "textures.h"
#include "lua_core.h"
void unloadGlyphInfo( GlyphInfo* glyph ) {
UnloadImage( glyph->image );
}
// DrawTextBoxed is modified DrawTextBoxedSelectable from raylib [text] example - Rectangle bounds
// Draw text using font inside rectangle limits
static int DrawTextBoxed( Font font, const char* text, Rectangle rec, float fontSize, float spacing,
bool wordWrap, Color* tints, int tintCount, Color* backTints, int backTintCount )
{
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
float textOffsetY = 0; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw
float scaleFactor = fontSize/(float)font.baseSize; // Character rectangle scaling factor
// Word/character wrapping mechanism variables
enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
int state = wordWrap ? MEASURE_STATE : DRAW_STATE;
int startLine = -1; // Index where to begin drawing (where a line begins)
int endLine = -1; // Index where to stop drawing (where a line ends)
int lastk = -1; // Holds last value of the character position
Color tint = BLACK;
Color backTint = BLANK;
Vector2 mousePos = GetMousePosition();
int mouseChar = -1;
for ( int i = 0, k = 0; i < length; i++, k++)
{
if ( i < tintCount ) {
tint = tints[i];
}
if ( i < backTintCount ) {
backTint = backTints[i];
}
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
int codepoint = GetCodepoint(&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;
i += (codepointByteCount - 1);
float glyphWidth = 0;
if (codepoint != '\n')
{
glyphWidth = (font.glyphs[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.glyphs[index].advanceX*scaleFactor;
if (i + 1 < length) glyphWidth = glyphWidth + spacing;
}
// NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
// We store this info in startLine and endLine, then we change states, draw the text between those two variables
// and change states again and again recursively until the end of the text (or until we get outside of the container).
// When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
// and begin drawing on the next line before we can get outside the container.
if (state == MEASURE_STATE)
{
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
// Ref: http://jkorpela.fi/chars/spaces.html
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
if ((textOffsetX + glyphWidth) > rec.width)
{
endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= codepointByteCount;
if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
state = !state;
}
else if ((i + 1) == length)
{
endLine = i;
state = !state;
}
else if (codepoint == '\n') state = !state;
if (state == DRAW_STATE)
{
textOffsetX = 0;
i = startLine;
glyphWidth = 0;
// Save character position when we switch states
int tmp = lastk;
lastk = k - 1;
k = tmp;
}
}
else
{
if (codepoint == '\n')
{
if (!wordWrap)
{
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0;
}
}
else
{
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
{
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0;
}
// When text overflows rectangle height limit, just stop drawing
if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break;
// Draw selection background
// bool isGlyphSelected = false;
// if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
// {
// DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
// isGlyphSelected = true;
// }
if ( CheckCollisionPointRec( mousePos, (Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor } ) ) {
mouseChar = i;
}
if ( 0 < backTint.a ) {
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, backTint);
}
// Draw current character glyph
if ((codepoint != ' ') && (codepoint != '\t'))
{
// DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint);
DrawTextCodepoint( font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, tint );
}
}
if (wordWrap && (i == endLine))
{
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0;
startLine = endLine;
endLine = -1;
glyphWidth = 0;
// selectStart += lastk - k;
k = lastk;
state = !state;
}
}
if ((textOffsetX != 0) || (codepoint != ' ')) textOffsetX += glyphWidth; // avoid leading spaces
}
return mouseChar;
}
static inline void getCodepoints( lua_State* L, int codepoints[], int index ) {
int t = index;
int i = 0;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
codepoints[i] = lua_tointeger( L, -1 );
i++;
lua_pop( L, 1 );
}
}
/*
## Text - Font loading/unloading functions
*/
/*
> font = RL.GetFontDefault()
Get the default Font. Return as lightuserdata
- Success return Font
*/
int ltextGetFontDefault( lua_State* L ) {
lua_pushlightuserdata( L, &state->defaultFont );
return 1;
}
/*
> font = RL.LoadFont( string fileName )
Load font from file into GPU memory (VRAM)
- Failure return nil
- Success return Font
*/
int ltextLoadFont( lua_State* L ) {
if ( FileExists( luaL_checkstring( L, 1 ) ) ) {
uluaPushFont( L, LoadFont( lua_tostring( L, 1 ) ) );
return 1;
}
TraceLog( state->logLevelInvalid, "Invalid file '%s'", lua_tostring( L, 1 ) );
lua_pushnil( L );
return 1;
}
/*
> font = RL.LoadFontEx( string fileName, int fontSize, int{}|nil codepoints )
Load font from file with extended parameters, use NULL for codepoints to load the default character set
- Failure return nil
- Success return Font
*/
int ltextLoadFontEx( lua_State* L ) {
int fontSize = luaL_checkinteger( L, 2 );
if ( FileExists( luaL_checkstring( L, 1 ) ) ) {
if ( lua_istable( L, 3 ) ) {
int codepointCount = uluaGetTableLen( L, 3 );
int codepoints[ codepointCount ];
getCodepoints( L, codepoints, 3 );
uluaPushFont( L, LoadFontEx( lua_tostring( L, 1 ), fontSize, codepoints, codepointCount ) );
return 1;
}
uluaPushFont( L, LoadFontEx( lua_tostring( L, 1 ), fontSize, NULL, 0 ) );
return 1;
}
TraceLog( state->logLevelInvalid, "Invalid file '%s'", lua_tostring( L, 1 ) );
lua_pushnil( L );
return 1;
}
/*
> font = RL.LoadFontFromImage( Image image, Color key, int firstChar )
Load font from Image (XNA style)
- Success return Font
*/
int ltextLoadFontFromImage( lua_State* L ) {
Image* image = uluaGetImage( L, 1 );
Color key = uluaGetColor( L, 2 );
int firstChar = luaL_checkinteger( L, 3 );
uluaPushFont( L, LoadFontFromImage( *image, key, firstChar ) );
return 1;
}
/*
> font = RL.LoadFontFromMemory( string fileType, Buffer fileData, int fontSize, int{} codepoints )
Load font from memory buffer, fileType refers to extension: i.e. '.ttf'. NOTE: fileData type should be unsigned char
- Success return Font
*/
int ltextLoadFontFromMemory( lua_State* L ) {
const char* fileType = luaL_checkstring( L, 1 );
Buffer* fileData = uluaGetBuffer( L, 2 );
int fontSize = luaL_checkinteger( L, 3 );
if ( lua_istable( L, 4 ) ) {
int codepointCount = uluaGetTableLen( L, 4 );
int codepoints[ codepointCount ];
getCodepoints( L, codepoints, 4 );
uluaPushFont( L, LoadFontFromMemory( fileType, fileData->data, fileData->size, fontSize, codepoints, codepointCount ) );
return 1;
}
/* If no codepoints provided. */
uluaPushFont( L, LoadFontFromMemory( fileType, fileData->data, fileData->size, fontSize, NULL, 0 ) );
return 1;
}
/*
> font = RL.LoadFontFromData( Font{} fontData )
Load Font from data
- Success return Font
*/
int ltextLoadFontFromData( lua_State* L ) {
luaL_checktype( L, 1, LUA_TTABLE );
Font font = { 0 };
int t = 1;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
if ( strcmp( "baseSize", (char*)lua_tostring( L, -2 ) ) == 0 ) {
font.baseSize = luaL_checkinteger( L, -1 );
}
else if ( strcmp( "glyphCount", (char*)lua_tostring( L, -2 ) ) == 0 ) {
font.glyphCount = luaL_checkinteger( L, -1 );
}
else if ( strcmp( "glyphPadding", (char*)lua_tostring( L, -2 ) ) == 0 ) {
font.glyphPadding = luaL_checkinteger( L, -1 );
}
else if ( strcmp( "texture", (char*)lua_tostring( L, -2 ) ) == 0 ) {
font.texture = *uluaGetTexture( L, lua_gettop( L ) );
}
else if ( strcmp( "recs", (char*)lua_tostring( L, -2 ) ) == 0 ) {
int recCount = uluaGetTableLen( L, lua_gettop( L ) );
font.recs = malloc( recCount * sizeof( Rectangle ) );
int t2 = lua_gettop( L );
int i = 0;
lua_pushnil( L );
while ( lua_next( L, t2 ) != 0 ) {
font.recs[i] = uluaGetRectangle( L, lua_gettop( L ) );
i++;
lua_pop( L, 1 );
}
}
else if ( strcmp( "glyphs", (char*)lua_tostring( L, -2 ) ) == 0 ) {
int glyphCount = uluaGetTableLen( L, lua_gettop( L ) );
font.glyphs = malloc( glyphCount * sizeof( GlyphInfo ) );
int t2 = lua_gettop( L );
int i = 0;
lua_pushnil( L );
while ( lua_next( L, t2 ) != 0 ) {
font.glyphs[i] = *uluaGetGlyphInfo( L, lua_gettop( L ) );
i++;
lua_pop( L, 1 );
}
}
lua_pop( L, 1 );
}
uluaPushFont( L, font );
return 1;
}
/*
> isReady = RL.IsFontReady( Font font )
Check if a font is ready
- Success return bool
*/
int ltextIsFontReady( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
lua_pushboolean( L, IsFontReady( *font ) );
return 1;
}
/*
> glyphs = RL.LoadFontData( Buffer fileData, int fontSize, int{} codepoints, int type )
Load font data for further use. NOTE: fileData type should be unsigned char
- Success return GlyphInfo{}
*/
int ltextLoadFontData( lua_State* L ) {
Buffer* fileData = uluaGetBuffer( L, 1 );
int fontSize = luaL_checkinteger( L, 2 );
int type = luaL_checkinteger( L, 4 );
int codepointCount = 95; // In case no chars count provided, default to 95.
if ( lua_istable( L, 3 ) ) {
codepointCount = uluaGetTableLen( L, 3 );
int codepoints[ codepointCount ];
getCodepoints( L, codepoints, 3 );
GlyphInfo* glyphs = LoadFontData( fileData->data, fileData->size, fontSize, codepoints, codepointCount, type );
lua_createtable( L, codepointCount, 0 );
for ( int i = 0; i < codepointCount; i++ ) {
uluaPushGlyphInfo( L, glyphs[i] );
lua_rawseti( L, -2, i + 1 );
}
UnloadFontData( glyphs, codepointCount );
return 1;
}
/* If no codepoints provided. */
GlyphInfo* glyphs = LoadFontData( fileData->data, fileData->size, fontSize, NULL, 0, type );
lua_createtable( L, codepointCount, 0 );
for ( int i = 0; i < codepointCount; i++ ) {
uluaPushGlyphInfo( L, glyphs[i] );
lua_rawseti( L, -2, i + 1 );
}
UnloadFontData( glyphs, codepointCount );
return 1;
}
/*
> image, rectangles = RL.GenImageFontAtlas( GlyphInfo{} glyphs, int fontSize, int padding, int packMethod )
Generate image font atlas using chars info. NOTE: Packing method: 0-Default, 1-Skyline
- Success Image, Rectangle{}
*/
int ltextGenImageFontAtlas( lua_State* L ) {
int fontSize = luaL_checkinteger( L, 2 );
int padding = luaL_checkinteger( L, 3 );
int packMethod = luaL_checkinteger( L, 4 );
int glyphCount = uluaGetTableLen( L, 1 );
GlyphInfo glyphs[ glyphCount ];
Rectangle *glyphRecs;
int t = 1;
int i = 0;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
glyphs[i] = *uluaGetGlyphInfo( L, lua_gettop( L ) );
i++;
lua_pop( L, 1 );
}
uluaPushImage( L, GenImageFontAtlas( glyphs, &glyphRecs, glyphCount, fontSize, padding, packMethod ) );
lua_createtable( L, glyphCount, 0 );
for ( i = 0; i < glyphCount; i++ ) {
uluaPushRectangle( L, glyphRecs[i] );
lua_rawseti( L, -2, i + 1 );
}
return 2;
}
/*
> RL.UnloadFont( Font font )
Unload font from GPU memory (VRAM)
*/
int ltextUnloadFont( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
UnloadFont( *font );
return 0;
}
/*
> RL.ExportFontAsCode( Font font, string fileName )
Export font as code file, returns true on success
- Success return bool
*/
int ltextExportFontAsCode( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
const char* fileName = luaL_checkstring( L, 2 );
lua_pushboolean( L, ExportFontAsCode( *font, fileName ) );
return 1;
}
/*
## Text - Text drawing functions
*/
/*
> RL.DrawFPS( Vector2 pos )
Draw current FPS
*/
int ltextDrawFPS( lua_State* L ) {
Vector2 pos = uluaGetVector2( L, 1 );
DrawFPS( pos.x, pos.y );
return 0;
}
/*
> RL.DrawText( string text, Vector2 position, float fontSize, Color tint )
Draw text (using default font)
*/
int ltextDrawText( lua_State* L ) {
Vector2 position = uluaGetVector2( L, 2 );
float fontSize = luaL_checknumber( L, 3 );
Color tint = uluaGetColor( L, 4 );
DrawText( luaL_checkstring( L, 1 ), position.x, position.y, fontSize, tint );
return 0;
}
/*
> RL.DrawTextEx( Font font, string text, Vector2 position, float fontSize, float spacing, Color tint )
Draw text using font and additional parameters
*/
int ltextDrawTextEx( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
Vector2 position = uluaGetVector2( L, 3 );
float fontSize = luaL_checknumber( L, 4 );
float spacing = luaL_checknumber( L, 5 );
Color tint = uluaGetColor( L, 6 );
DrawTextEx( *font, luaL_checkstring( L, 2 ), position, fontSize, spacing, tint );
return 0;
}
/*
> RL.DrawTextPro( Font font, string text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint )
Draw text using Font and pro parameters (rotation)
*/
int ltextDrawTextPro( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
Vector2 position = uluaGetVector2( L, 3 );
Vector2 origin = uluaGetVector2( L, 4 );
float rotation = luaL_checknumber( L, 5 );
float fontSize = luaL_checknumber( L, 6 );
float spacing = luaL_checknumber( L, 7 );
Color tint = uluaGetColor( L, 8 );
DrawTextPro( *font, luaL_checkstring( L, 2 ), position, origin, rotation, fontSize, spacing, tint );
return 0;
}
/*
> RL.DrawTextCodepoint( Font font, int codepoint, Vector2 position, float fontSize, Color tint )
Draw one character (codepoint)
*/
int ltextDrawTextCodepoint( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
int codepoint = luaL_checkinteger( L, 2 );
Vector2 position = uluaGetVector2( L, 3 );
float fontSize = luaL_checknumber( L, 4 );
Color tint = uluaGetColor( L, 5 );
DrawTextCodepoint( *font, codepoint, position, fontSize, tint );
return 0;
}
/*
> RL.DrawTextCodepoints( Font font, int{} codepoints, Vector2 position, float fontSize, float spacing, Color tint )
Draw multiple character (codepoint)
*/
int ltextDrawTextCodepoints( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
Vector2 position = uluaGetVector2( L, 3 );
float fontSize = luaL_checknumber( L, 4 );
float spacing = luaL_checknumber( L, 5 );
Color tint = uluaGetColor( L, 6 );
int codepointCount = uluaGetTableLen( L, 2 );
int codepoints[ codepointCount ];
int t = 2;
int i = 0;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
codepoints[i] = lua_tointeger( L, -1 );
i++;
lua_pop( L, 1 );
}
DrawTextCodepoints( *font, codepoints, codepointCount, position, fontSize, spacing, tint );
return 0;
}
/*
> mouseCharId = RL.DrawTextBoxed(Font font, string text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint )
Draw text using font inside rectangle limits. Return character id from mouse position (default -1). Function from raylib [text] example - Rectangle bounds.
- Success return int
*/
int ltextDrawTextBoxed( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
const char* text = luaL_checkstring( L, 2 );
Rectangle rec = uluaGetRectangle( L, 3 );
float fontSize = luaL_checknumber( L, 4 );
float spacing = luaL_checknumber( L, 5 );
bool wordWrap = uluaGetBoolean( L, 6 );
Color tint = uluaGetColor( L, 7 );
lua_pushinteger( L, DrawTextBoxed( *font, text, rec, fontSize, spacing, wordWrap, &tint, 1, NULL, 0 ) );
return 1;
}
/*
> mouseCharId = RL.DrawTextBoxedTinted( Font font, string text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tints, Color backTints )
Draw text using font inside rectangle limits with support for tint and background tint for each character. Return character id from mouse position (default -1)
- Success return int
*/
int ltextDrawTextBoxedTinted( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
const char* text = luaL_checkstring( L, 2 );
Rectangle rec = uluaGetRectangle( L, 3 );
float fontSize = luaL_checknumber( L, 4 );
float spacing = luaL_checknumber( L, 5 );
bool wordWrap = uluaGetBoolean( L, 6 );
int tintCount = uluaGetTableLen( L, 7 );
int backTintCount = uluaGetTableLen( L, 8 );
Color tints[ tintCount ];
Color backTints[ backTintCount ];
/* Tints. */
int t = 7, i = 0;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
tints[i] = uluaGetColor( L, lua_gettop( L ) );
i++;
lua_pop( L, 1 );
}
/* Back tints. */
t = 8; i = 0;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
backTints[i] = uluaGetColor( L, lua_gettop( L ) );
i++;
lua_pop( L, 1 );
}
lua_pushinteger( L, DrawTextBoxed( *font, text, rec, fontSize, spacing, wordWrap, tints, tintCount, backTints, backTintCount ) );
return 1;
}
/*
## Text - Text font info functions
*/
/*
> size = RL.SetTextLineSpacing( int spacing )
Set vertical line spacing when drawing with line-breaks
*/
int ltextSetTextLineSpacing( lua_State* L ) {
int spacing = luaL_checkinteger( L, 1 );
SetTextLineSpacing( spacing );
}
/*
> width = RL.MeasureText( string text, int fontSize )
Measure string width for default font
- Success return int
*/
int ltextMeasureText( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
int fontSize = luaL_checkinteger( L, 2 );
lua_pushinteger( L, MeasureText( text, fontSize ) );
return 1;
}
/*
> size = RL.MeasureTextEx( Font font, string text, float fontSize, float spacing )
Measure string size for Font
- Success return Vector2
*/
int ltextMeasureTextEx( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
const char* text = luaL_checkstring( L, 2 );
float fontSize = luaL_checknumber( L, 3 );
float spacing = luaL_checknumber( L, 4 );
uluaPushVector2( L, MeasureTextEx( *font, text, fontSize, spacing ) );
return 1;
}
/*
> index = RL.GetGlyphIndex( Font font, int codepoint )
Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
- Success return int
*/
int ltextGetGlyphIndex( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
int codepoint = luaL_checkinteger( L, 2 );
lua_pushinteger( L, GetGlyphIndex( *font, codepoint ) );
return 1;
}
/*
> glyphInfo = RL.GetGlyphInfo( Font font, int codepoint )
Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found. Return as lightuserdata
- Success return GlyphInfo
*/
int ltextGetGlyphInfo( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
int codepoint = luaL_checkinteger( L, 2 );
int id = GetGlyphIndex( *font, codepoint );
lua_pushlightuserdata( L, &font->glyphs[id] );
return 1;
}
/*
> glyphInfo = RL.GetGlyphInfoByIndex( Font font, int index )
Get glyph font info data by index. Return as lightuserdata
- Failure return nil
- Success return GlyphInfo
*/
int ltextGetGlyphInfoByIndex( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
int index = luaL_checkinteger( L, 2 );
if ( 0 <= index && index < font->glyphCount ) {
lua_pushlightuserdata( L, &font->glyphs[ index ] );
}
else {
TraceLog( state->logLevelInvalid, "Glyph index %d out of bounds", index );
lua_pushnil( L );
}
return 1;
}
/*
> rect = RL.GetGlyphAtlasRec( Font font, int codepoint )
Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found
- Success return Rectangle
*/
int ltextGetGlyphAtlasRec( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
int codepoint = luaL_checkinteger( L, 2 );
uluaPushRectangle( L, GetGlyphAtlasRec( *font, codepoint ) );
return 1;
}
/*
> rect = RL.GetGlyphAtlasRecByIndex( Font font, int index )
Get glyph rectangle in font atlas by index
- Failure return nil
- Success return Rectangle
*/
int ltextGetGlyphAtlasRecByIndex( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
int index = luaL_checkinteger( L, 2 );
if ( 0 <= index && index < font->glyphCount ) {
uluaPushRectangle( L, font->recs[ index ] );
}
else {
TraceLog( state->logLevelInvalid, "Glyph index %d out of bounds", index );
lua_pushnil( L );
}
return 1;
}
/*
> baseSize = RL.GetFontBaseSize( Font font )
Get font base size (default chars height)
- Success return int
*/
int ltextGetFontBaseSize( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
lua_pushinteger( L, font->baseSize );
return 1;
}
/*
> glyphCount = RL.GetFontGlyphCount( Font font )
Get font number of glyph characters
- Success return int
*/
int ltextGetFontGlyphCount( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
lua_pushinteger( L, font->glyphCount );
return 1;
}
/*
> glyphPadding = RL.GetFontGlyphPadding( Font font )
Get font padding around the glyph characters
- Success return int
*/
int ltextGetFontGlyphPadding( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
lua_pushinteger( L, font->glyphPadding );
return 1;
}
/*
> texture = RL.GetFontTexture( Font font )
Get font texture atlas containing the glyphs. Return as lightuserdata
- Success return Texture
*/
int ltextGetFontTexture( lua_State* L ) {
Font* font = uluaGetFont( L, 1 );
lua_pushlightuserdata( L, &font->texture );
return 1;
}
/*
## Text - GlyphInfo management functions
*/
/*
> glyphInfo = RL.LoadGlyphInfo( GlyphInfo{} glyphInfoData )
Load GlyphInfo from data
- Success return GlyphInfo
*/
int ltextLoadGlyphInfo( lua_State* L ) {
luaL_checktype( L, 1, LUA_TTABLE );
GlyphInfo glyph = { 0 };
int t = 1;
lua_pushnil( L );
while ( lua_next( L, t ) != 0 ) {
if ( strcmp( "value", (char*)lua_tostring( L, -2 ) ) == 0 ) {
glyph.value = (unsigned int)luaL_checkinteger( L, -1 );
}
else if ( strcmp( "offsetX", (char*)lua_tostring( L, -2 ) ) == 0 ) {
glyph.offsetX = luaL_checkinteger( L, -1 );
}
else if ( strcmp( "offsetY", (char*)lua_tostring( L, -2 ) ) == 0 ) {
glyph.offsetY = luaL_checkinteger( L, -1 );
}
else if ( strcmp( "advanceX", (char*)lua_tostring( L, -2 ) ) == 0 ) {
glyph.advanceX = luaL_checkinteger( L, -1 );
}
else if ( strcmp( "image", (char*)lua_tostring( L, -2 ) ) == 0 ) {
glyph.image = *uluaGetImage( L, lua_gettop( L ) );
}
lua_pop( L, 1 );
}
uluaPushGlyphInfo( L, glyph );
return 1;
}
/*
> RL.UnloadGlyphInfo( GlyphInfo glyphInfo )
Unload glyphInfo image from CPU memory (RAM)
*/
int ltextUnloadGlyphInfo( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
unloadGlyphInfo( glyph );
return 0;
}
/*
> RL.SetGlyphInfoValue( GlyphInfo glyphInfo, int value )
Set glyphInfo character value (Unicode)
*/
int ltextSetGlyphInfoValue( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
int value = luaL_checkinteger( L, 2 );
glyph->value = value;
return 0;
}
/*
> RL.SetGlyphInfoOffset( GlyphInfo glyphInfo, Vector2 offset )
Set glyphInfo character offset when drawing
*/
int ltextSetGlyphInfoOffset( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
Vector2 offset = uluaGetVector2( L, 2 );
glyph->offsetX = (int)offset.x;
glyph->offsetY = (int)offset.y;
return 0;
}
/*
> RL.SetGlyphInfoAdvanceX( GlyphInfo glyphInfo, int advanceX )
Set glyphInfo character advance position X
*/
int ltextSetGlyphInfoAdvanceX( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
int advanceX = luaL_checkinteger( L, 2 );
glyph->advanceX = advanceX;
return 0;
}
/*
> RL.SetGlyphInfoImage( GlyphInfo glyphInfo, Image image )
Set glyphInfo character image data
*/
int ltextSetGlyphInfoImage( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
Image image = *uluaGetImage( L, 2 );
glyph->image = image;
return 0;
}
/*
> value = RL.GetGlyphInfoValue( GlyphInfo glyphInfo )
Get glyphInfo character value (Unicode)
- Success return int
*/
int ltextGetGlyphInfoValue( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
lua_pushinteger( L, glyph->value );
return 1;
}
/*
> offset = RL.GetGlyphInfoOffset( GlyphInfo glyphInfo )
Get glyphInfo character offset when drawing
- Success return Vector2
*/
int ltextGetGlyphInfoOffset( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
uluaPushVector2( L, (Vector2){ glyph->offsetX, glyph->offsetY } );
return 1;
}
/*
> advanceX = RL.GetGlyphInfoAdvanceX( GlyphInfo glyphInfo )
Get glyphInfo character advance position X
- Success return int
*/
int ltextGetGlyphInfoAdvanceX( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
lua_pushinteger( L, glyph->advanceX );
return 1;
}
/*
> image = RL.GetGlyphInfoImage( GlyphInfo glyphInfo )
Get glyphInfo character image data. Return as lightuserdata
- Success return Image
*/
int ltextGetGlyphInfoImage( lua_State* L ) {
GlyphInfo* glyph = uluaGetGlyphInfo( L, 1 );
lua_pushlightuserdata( L, &glyph->image );
return 1;
}
/*
## Text - Text codepoints management functions (unicode characters)
*/
/*
> string = RL.LoadUTF8( int{} codepoints )
Load UTF-8 text encoded from codepoints array
- Success return string
*/
int ltextLoadUTF8( lua_State* L ) {
int codepointCount = uluaGetTableLen( L, 1 );
int codepoints[ codepointCount ];
getCodepoints( L, codepoints, 1 );
char* string = LoadUTF8( codepoints, codepointCount );
lua_pushstring( L, string );
UnloadUTF8( string );
return 1;
}
/*
> codepoints = RL.LoadCodepoints( string text )
Load all codepoints from a UTF-8 text string
- Success return int{}
*/
int ltextLoadCodepoints( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
int count = 0;
int* codepoints = LoadCodepoints( text, &count );
lua_createtable( L, count, 0 );
for ( int i = 0; i < count; i++ ) {
lua_pushinteger( L, codepoints[i] );
lua_rawseti( L, -2, i + 1 );
}
UnloadCodepoints( codepoints );
return 1;
}
/*
> count = RL.GetCodepointCount( string text )
Get total number of codepoints in a UTF-8 encoded string
- Success return int
*/
int ltextGetCodepointCount( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
lua_pushinteger( L, GetCodepointCount( text ) );
return 1;
}
/*
> codepoint, codepointSize = RL.GetCodepoint( string text, int position )
Get codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
- Success return int, int
*/
int ltextGetCodepoint( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
int position = luaL_checkinteger( L, 2 );
text += position;
int codepointSize = 0;
lua_pushinteger( L, GetCodepoint( text, &codepointSize ) );
lua_pushinteger( L, codepointSize );
return 2;
}
/*
> codepoint, codepointSize = RL.GetCodepointNext( string text, int position )
Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
- Success return int, int
*/
int ltextGetCodepointNext( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
int position = luaL_checkinteger( L, 2 );
text += position;
int codepointSize = 0;
lua_pushinteger( L, GetCodepointNext( text, &codepointSize ) );
lua_pushinteger( L, codepointSize );
return 2;
}
/*
> codepoint, codepointSize = RL.GetCodepointPrevious( string text, int position )
Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
- Success return int, int
*/
int ltextGetCodepointPrevious( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
int position = luaL_checkinteger( L, 2 );
text += position;
int codepointSize = 0;
lua_pushinteger( L, GetCodepointPrevious( text, &codepointSize ) );
lua_pushinteger( L, codepointSize );
return 2;
}
/*
> string = RL.CodepointToUTF8( int codepoint )
Encode one codepoint into UTF-8 byte array
- Success return string
*/
int ltextCodepointToUTF8( lua_State* L ) {
int codepoint = luaL_checkinteger( L, 1 );
int utf8Size = 0;
char text[5] = { '\0' };
const char* utf8 = CodepointToUTF8( codepoint, &utf8Size );
memcpy( text, utf8, utf8Size );
lua_pushstring( L, text );
return 1;
}
/*
## Text - Text strings management functions (no UTF-8 strings, only byte chars)
*/
/*
> text = RL.TextSubtext( string text, int position, int length )
Get a piece of a text string
- Success return string
*/
int ltextTextSubtext( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
int position = luaL_checkinteger( L, 2 );
int length = luaL_checkinteger( L, 3 );
lua_pushstring( L, TextSubtext( text, position, length ) );
return 1;
}
/*
> text = RL.TextReplace( string text, string replace, string by )
Replace text string
- Success return string
*/
int ltextTextReplace( lua_State* L ) {
char* text = (char*)luaL_checkstring( L, 1 );
const char* replace = luaL_checkstring( L, 2 );
const char* by = luaL_checkstring( L, 3 );
char* result = TextReplace( text, replace, by );
lua_pushstring( L, result );
free( result );
return 1;
}
/*
> text = RL.TextInsert( string text, string insert, int position )
Insert text in a specific position, moves all text forward
- Success return string
*/
int ltextTextInsert( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
const char* insert = luaL_checkstring( L, 2 );
int position = luaL_checkinteger( L, 3 );
// char* result = TextInsert( text, insert, position ); // Bug in the raylib implementation.
int textLen = TextLength( text );
int insertLen = TextLength( insert );
char* result = RL_MALLOC( textLen + insertLen + 1 );
memcpy( result, text, position );
memcpy( result + position, insert, insertLen );
memcpy( result + position + insertLen, text + position, textLen - position );
result[ textLen + insertLen ] = '\0'; // Make sure text string is valid!
lua_pushstring( L, result );
free( result );
return 1;
}
/*
> splits = RL.TextSplit( string text, char delimiter )
Split text into multiple strings
- Success return string{}
*/
int ltextTextSplit( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
const char* delimiter = luaL_checkstring( L, 2 );
int count = 0;
const char** splits = TextSplit( text, delimiter[0], &count );
lua_createtable( L, count, 0 );
for ( int i = 0; i < count; i++ ) {
lua_pushstring( L, splits[i] );
lua_rawseti( L, -2, i + 1 );
}
/* Note! No need to free. Uses static memory. */
return 1;
}
/*
> index = RL.TextFindIndex( string text, string find )
Find first text occurrence within a string
- Success return int
*/
int ltextTextFindIndex( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
const char* find = luaL_checkstring( L, 2 );
lua_pushinteger( L, TextFindIndex( text, find ) );
return 1;
}
/*
> text = RL.TextToPascal( string text )
Get Pascal case notation version of provided string
- Success return string
*/
int ltextTextToPascal( lua_State* L ) {
const char* text = luaL_checkstring( L, 1 );
lua_pushstring( L, TextToPascal( text ) );
return 1;
}