Add embedded assets, splash screens, and asset loading support
Features added: - Embedded main.lua and Lua files support (EMBED_MAIN option) - Embedded assets support (EMBED_ASSETS option) - Splash screens with dual logo display (always embedded) - Asset loading progress tracking API (BeginAssetLoading, UpdateAssetLoading, EndAssetLoading) - Custom font embedding for splash/loading screens - --log flag for Windows console control - --no-logo flag to skip splash screens in development - Python scripts for embedding (embed_lua.py, embed_assets.py, embed_logo.py, embed_font.py) - Documentation (EMBEDDING.md, ASSET_LOADING.md, SPLASH_SCREENS.md) This allows building single-executable releases with all Lua code and assets embedded.
This commit is contained in:
61
src/core.c
61
src/core.c
@@ -4,6 +4,14 @@
|
||||
#include "textures.h"
|
||||
#include "lua_core.h"
|
||||
|
||||
/* Forward declarations from lua_core.c for asset loading */
|
||||
extern int g_totalAssets;
|
||||
extern int g_loadedAssets;
|
||||
extern char g_currentAssetName[256];
|
||||
extern bool g_showLoadingScreen;
|
||||
extern float g_loadingProgress;
|
||||
extern void drawLoadingScreen();
|
||||
|
||||
static size_t getBufferElementSize( Buffer* buffer ) {
|
||||
switch ( buffer->type ) {
|
||||
case BUFFER_UNSIGNED_CHAR: return sizeof( unsigned char );
|
||||
@@ -1955,6 +1963,59 @@ int lcoreGetApplicationDirectory( lua_State* L ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
> RL.BeginAssetLoading( int totalAssets )
|
||||
|
||||
Initialize asset loading progress tracking
|
||||
|
||||
- totalAssets: Total number of assets to load
|
||||
*/
|
||||
int lcoreBeginAssetLoading( lua_State* L ) {
|
||||
g_totalAssets = luaL_checkinteger( L, 1 );
|
||||
g_loadedAssets = 0;
|
||||
g_showLoadingScreen = true;
|
||||
g_loadingProgress = 0.0f;
|
||||
g_currentAssetName[0] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
> RL.UpdateAssetLoading( string assetName )
|
||||
|
||||
Update loading progress for current asset
|
||||
|
||||
- assetName: Name of the asset currently being loaded
|
||||
*/
|
||||
int lcoreUpdateAssetLoading( lua_State* L ) {
|
||||
const char* assetName = luaL_checkstring( L, 1 );
|
||||
strncpy( g_currentAssetName, assetName, sizeof(g_currentAssetName) - 1 );
|
||||
g_currentAssetName[sizeof(g_currentAssetName) - 1] = '\0';
|
||||
|
||||
g_loadedAssets++;
|
||||
g_loadingProgress = (float)g_loadedAssets / (float)g_totalAssets;
|
||||
|
||||
if ( g_showLoadingScreen ) {
|
||||
drawLoadingScreen();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
> RL.EndAssetLoading()
|
||||
|
||||
Finish asset loading and hide loading screen
|
||||
*/
|
||||
int lcoreEndAssetLoading( lua_State* L ) {
|
||||
g_showLoadingScreen = false;
|
||||
g_totalAssets = 0;
|
||||
g_loadedAssets = 0;
|
||||
g_currentAssetName[0] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
> success = RL.MakeDirectory( string dirPath )
|
||||
|
||||
|
||||
236
src/lua_core.c
236
src/lua_core.c
@@ -15,6 +15,21 @@
|
||||
#include "reasings.h"
|
||||
#include "bitwiseOp.h"
|
||||
|
||||
#ifdef EMBED_MAIN
|
||||
#include "embedded_main.h"
|
||||
#endif
|
||||
|
||||
#ifdef EMBED_ASSETS
|
||||
#include "embedded_assets.h"
|
||||
#endif
|
||||
|
||||
/* Asset loading progress tracking (non-static so core.c can access) */
|
||||
int g_totalAssets = 0;
|
||||
int g_loadedAssets = 0;
|
||||
char g_currentAssetName[256] = { '\0' };
|
||||
bool g_showLoadingScreen = false;
|
||||
float g_loadingProgress = 0.0f;
|
||||
|
||||
#ifdef PLATFORM_DESKTOP
|
||||
#include "platforms/core_desktop_glfw.c"
|
||||
#elif PLATFORM_DESKTOP_SDL2
|
||||
@@ -25,6 +40,152 @@
|
||||
#include "platforms/core_web.c"
|
||||
#endif
|
||||
|
||||
/* Draw a nice loading screen with progress bar (non-static so core.c can call it) */
|
||||
void drawLoadingScreen() {
|
||||
int screenWidth = GetScreenWidth();
|
||||
int screenHeight = GetScreenHeight();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground( BLACK );
|
||||
|
||||
int centerX = screenWidth / 2;
|
||||
int centerY = screenHeight / 2;
|
||||
|
||||
const char* title = "LOADING";
|
||||
int titleSize = 32;
|
||||
int titleWidth = MeasureText( title, titleSize );
|
||||
|
||||
DrawText( title, centerX - titleWidth / 2, centerY - 80, titleSize, WHITE );
|
||||
|
||||
static float dotTime = 0.0f;
|
||||
dotTime += 0.016f;
|
||||
int dotCount = (int)(dotTime * 2.0f) % 4;
|
||||
|
||||
int dotStartX = centerX + titleWidth / 2 + 10;
|
||||
int dotY = centerY - 80 + titleSize - 12;
|
||||
for ( int i = 0; i < dotCount; i++ ) {
|
||||
DrawRectangle( dotStartX + i * 8, dotY, 4, 4, WHITE );
|
||||
}
|
||||
|
||||
int barWidth = 200;
|
||||
int barHeight = 16;
|
||||
int barX = centerX - barWidth / 2;
|
||||
int barY = centerY;
|
||||
|
||||
DrawRectangle( barX - 2, barY - 2, barWidth + 4, barHeight + 4, WHITE );
|
||||
DrawRectangle( barX, barY, barWidth, barHeight, BLACK );
|
||||
|
||||
int fillWidth = (int)(barWidth * g_loadingProgress);
|
||||
if ( fillWidth > 0 ) {
|
||||
DrawRectangle( barX, barY, fillWidth, barHeight, WHITE );
|
||||
|
||||
for ( int y = 0; y < barHeight; y += 2 ) {
|
||||
for ( int x = 0; x < fillWidth; x += 4 ) {
|
||||
if ( (x + y) % 4 == 0 ) {
|
||||
DrawRectangle( barX + x, barY + y, 1, 1, BLACK );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( g_totalAssets > 0 ) {
|
||||
char progressText[32];
|
||||
sprintf( progressText, "%d/%d", g_loadedAssets, g_totalAssets );
|
||||
int progressWidth = MeasureText( progressText, 16 );
|
||||
DrawText( progressText, centerX - progressWidth / 2, barY + barHeight + 12, 16, WHITE );
|
||||
}
|
||||
|
||||
if ( g_currentAssetName[0] != '\0' ) {
|
||||
int assetNameWidth = MeasureText( g_currentAssetName, 10 );
|
||||
DrawText( g_currentAssetName, centerX - assetNameWidth / 2, barY + barHeight + 36, 10, WHITE );
|
||||
}
|
||||
|
||||
int cornerSize = 8;
|
||||
int margin = 40;
|
||||
|
||||
DrawRectangle( margin, margin, cornerSize, 2, WHITE );
|
||||
DrawRectangle( margin, margin, 2, cornerSize, WHITE );
|
||||
|
||||
DrawRectangle( screenWidth - margin - cornerSize, margin, cornerSize, 2, WHITE );
|
||||
DrawRectangle( screenWidth - margin - 2, margin, 2, cornerSize, WHITE );
|
||||
|
||||
DrawRectangle( margin, screenHeight - margin - cornerSize, 2, cornerSize, WHITE );
|
||||
DrawRectangle( margin, screenHeight - margin - 2, cornerSize, 2, WHITE );
|
||||
|
||||
DrawRectangle( screenWidth - margin - cornerSize, screenHeight - margin - 2, cornerSize, 2, WHITE );
|
||||
DrawRectangle( screenWidth - margin - 2, screenHeight - margin - cornerSize, 2, cornerSize, WHITE );
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
#ifdef EMBED_MAIN
|
||||
/* Custom loader for embedded Lua files */
|
||||
static int embedded_lua_loader( lua_State* L ) {
|
||||
const char* name = lua_tostring( L, 1 );
|
||||
if ( name == NULL ) return 0;
|
||||
|
||||
for ( int i = 0; i < embedded_lua_file_count; i++ ) {
|
||||
const EmbeddedLuaFile* file = &embedded_lua_files[i];
|
||||
|
||||
const char* basename = file->name;
|
||||
size_t name_len = strlen( name );
|
||||
size_t base_len = strlen( basename );
|
||||
|
||||
if ( strcmp( basename, name ) == 0 ||
|
||||
( base_len > 4 && strcmp( basename + base_len - 4, ".lua" ) == 0 &&
|
||||
strncmp( basename, name, base_len - 4 ) == 0 && name_len == base_len - 4 ) ) {
|
||||
|
||||
if ( luaL_loadbuffer( L, (const char*)file->data, file->size, file->name ) == 0 ) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushfstring( L, "\n\tembedded loader error: %s", lua_tostring( L, -1 ) );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushfstring( L, "\n\tno embedded file '%s'", name );
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EMBED_ASSETS
|
||||
/* Helper function to find embedded asset by name */
|
||||
static const EmbeddedAsset* find_embedded_asset( const char* name ) {
|
||||
if ( name == NULL ) return NULL;
|
||||
|
||||
for ( int i = 0; i < embedded_asset_count; i++ ) {
|
||||
if ( strcmp( embedded_assets[i].name, name ) == 0 ) {
|
||||
return &embedded_assets[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Override LoadFileData to check embedded assets first */
|
||||
unsigned char* LoadFileData_Embedded( const char* fileName, int* dataSize ) {
|
||||
const EmbeddedAsset* asset = find_embedded_asset( fileName );
|
||||
if ( asset != NULL ) {
|
||||
*dataSize = asset->size;
|
||||
unsigned char* data = (unsigned char*)malloc( asset->size );
|
||||
if ( data != NULL ) {
|
||||
memcpy( data, asset->data, asset->size );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
return LoadFileData( fileName, dataSize );
|
||||
}
|
||||
|
||||
/* Check if file exists in embedded assets */
|
||||
bool FileExists_Embedded( const char* fileName ) {
|
||||
if ( find_embedded_asset( fileName ) != NULL ) {
|
||||
return true;
|
||||
}
|
||||
return FileExists( fileName );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Custom implementation since LuaJIT doesn't have lua_geti. */
|
||||
static void lua_getiCustom( lua_State* L, int index, int i ) {
|
||||
lua_pushinteger( L, i ); // Push the index onto the stack
|
||||
@@ -1446,11 +1607,51 @@ int luaTraceback( lua_State* L ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void luaCallMain() {
|
||||
bool luaCallMain() {
|
||||
lua_State* L = state->luaState;
|
||||
|
||||
char path[ STRING_LEN ] = { '\0' };
|
||||
|
||||
/* Show loading screen */
|
||||
BeginDrawing();
|
||||
ClearBackground( RAYWHITE );
|
||||
const char* loadingText = "Loading...";
|
||||
int fontSize = 40;
|
||||
int textWidth = MeasureText( loadingText, fontSize );
|
||||
DrawText( loadingText, ( GetScreenWidth() - textWidth ) / 2, GetScreenHeight() / 2 - fontSize / 2, fontSize, DARKGRAY );
|
||||
EndDrawing();
|
||||
|
||||
#ifdef EMBED_MAIN
|
||||
/* Register custom loader for embedded files */
|
||||
lua_getglobal( L, "package" );
|
||||
lua_getfield( L, -1, "loaders" );
|
||||
if ( lua_isnil( L, -1 ) ) {
|
||||
lua_pop( L, 1 );
|
||||
lua_getfield( L, -1, "searchers" ); /* Lua 5.2+ uses 'searchers' */
|
||||
}
|
||||
|
||||
/* Insert our loader at position 2 (before file loaders) */
|
||||
lua_len( L, -1 );
|
||||
int num_loaders = lua_tointeger( L, -1 );
|
||||
lua_pop( L, 1 );
|
||||
for ( int i = num_loaders; i >= 2; i-- ) {
|
||||
lua_rawgeti( L, -1, i );
|
||||
lua_rawseti( L, -2, i + 1 );
|
||||
}
|
||||
lua_pushcfunction( L, embedded_lua_loader );
|
||||
lua_rawseti( L, -2, 2 );
|
||||
lua_pop( L, 2 ); /* Pop loaders/searchers and package */
|
||||
|
||||
/* Load from embedded data */
|
||||
if ( luaL_loadbuffer( L, (const char*)embedded_main_lua, embedded_main_lua_len, "main.lua" ) != 0 ) {
|
||||
TraceLog( LOG_ERROR, "Lua error loading embedded main.lua: %s\n", lua_tostring( L, -1 ) );
|
||||
return false;
|
||||
}
|
||||
if ( lua_pcall( L, 0, 0, 0 ) != 0 ) {
|
||||
TraceLog( LOG_ERROR, "Lua error executing embedded main.lua: %s\n", lua_tostring( L, -1 ) );
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
/* If web, set path to resources folder. */
|
||||
#ifdef PLATFORM_WEB
|
||||
snprintf( path, STRING_LEN, "main.lua" );
|
||||
@@ -1467,17 +1668,16 @@ void luaCallMain() {
|
||||
#endif
|
||||
if ( !FileExists( path ) ) {
|
||||
TraceLog( LOG_ERROR, "Cannot find file: %s\n", path );
|
||||
state->run = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
luaL_dofile( L, path );
|
||||
|
||||
/* Check errors in main.lua */
|
||||
if ( lua_tostring( L, -1 ) ) {
|
||||
TraceLog( LOG_ERROR, "Lua error: %s\n", lua_tostring( L, -1 ) );
|
||||
state->run = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
lua_pushcfunction( L, luaTraceback );
|
||||
int tracebackidx = lua_gettop( L );
|
||||
/* Apply custom callback here. */
|
||||
@@ -1489,8 +1689,7 @@ void luaCallMain() {
|
||||
if ( lua_isfunction( L, -1 ) ) {
|
||||
if ( lua_pcall( L, 0, 0, tracebackidx ) != 0 ) {
|
||||
TraceLog( LOG_ERROR, "Lua error: %s", lua_tostring( L, -1 ) );
|
||||
state->run = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lua_pop( L, -1 );
|
||||
@@ -1502,8 +1701,25 @@ void luaCallMain() {
|
||||
stateContextInit();
|
||||
}
|
||||
else {
|
||||
state->run = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
lua_getglobal( L, "RL" );
|
||||
lua_getfield( L, -1, "init" );
|
||||
|
||||
if ( lua_isfunction( L, -1 ) ) {
|
||||
if ( lua_pcall( L, 0, 0, tracebackidx ) != 0 ) {
|
||||
TraceLog( LOG_ERROR, "Lua error: %s", lua_tostring( L, -1 ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
TraceLog( LOG_ERROR, "%s", "No Lua init found!" );
|
||||
return false;
|
||||
}
|
||||
lua_pop( L, -1 );
|
||||
|
||||
return state->run;
|
||||
}
|
||||
|
||||
void luaCallInit() {
|
||||
@@ -1789,6 +2005,10 @@ void luaRegister() {
|
||||
assingGlobalFunction( "GetPrevDirectoryPath", lcoreGetPrevDirectoryPath );
|
||||
assingGlobalFunction( "GetWorkingDirectory", lcoreGetWorkingDirectory );
|
||||
assingGlobalFunction( "GetApplicationDirectory", lcoreGetApplicationDirectory );
|
||||
/* Asset loading functions. */
|
||||
assingGlobalFunction( "BeginAssetLoading", lcoreBeginAssetLoading );
|
||||
assingGlobalFunction( "UpdateAssetLoading", lcoreUpdateAssetLoading );
|
||||
assingGlobalFunction( "EndAssetLoading", lcoreEndAssetLoading );
|
||||
assingGlobalFunction( "MakeDirectory", lcoreMakeDirectory );
|
||||
assingGlobalFunction( "ChangeDirectory", lcoreChangeDirectory );
|
||||
assingGlobalFunction( "IsPathFile", lcoreIsPathFile );
|
||||
|
||||
114
src/main.c
114
src/main.c
@@ -1,6 +1,15 @@
|
||||
#include "main.h"
|
||||
#include "state.h"
|
||||
#include "lua_core.h"
|
||||
#include "splash.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// Forward declarations for Windows console functions
|
||||
extern __declspec(dllimport) int __stdcall AllocConsole(void);
|
||||
extern __declspec(dllimport) int __stdcall FreeConsole(void);
|
||||
extern __declspec(dllimport) void* __stdcall GetStdHandle(unsigned long nStdHandle);
|
||||
extern __declspec(dllimport) int __stdcall SetStdHandle(unsigned long nStdHandle, void* hHandle);
|
||||
#endif
|
||||
|
||||
static inline void printVersion() {
|
||||
if ( VERSION_DEV ) {
|
||||
@@ -22,30 +31,92 @@ static inline void printVersion() {
|
||||
int main( int argn, const char** argc ) {
|
||||
char basePath[ STRING_LEN ] = { '\0' };
|
||||
bool interpret_mode = false;
|
||||
bool show_console = false;
|
||||
bool skip_splash = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Check for --log and --no-logo arguments */
|
||||
for ( int i = 1; i < argn; i++ ) {
|
||||
if ( strcmp( argc[i], "--log" ) == 0 ) {
|
||||
show_console = true;
|
||||
}
|
||||
if ( strcmp( argc[i], "--no-logo" ) == 0 ) {
|
||||
skip_splash = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Show or hide console based on --log argument */
|
||||
if ( show_console ) {
|
||||
/* Allocate a console if we don't have one */
|
||||
if ( AllocConsole() ) {
|
||||
freopen( "CONOUT$", "w", stdout );
|
||||
freopen( "CONOUT$", "w", stderr );
|
||||
freopen( "CONIN$", "r", stdin );
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Hide console window */
|
||||
FreeConsole();
|
||||
}
|
||||
#else
|
||||
/* Check for --no-logo on non-Windows platforms */
|
||||
for ( int i = 1; i < argn; i++ ) {
|
||||
if ( strcmp( argc[i], "--no-logo" ) == 0 ) {
|
||||
skip_splash = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( 1 < argn ) {
|
||||
if ( strcmp( argc[1], "--version" ) == 0 || strcmp( argc[1], "-v" ) == 0 ) {
|
||||
/* Skip --log and --no-logo flags to find the actual command */
|
||||
int arg_index = 1;
|
||||
while ( arg_index < argn && ( strcmp( argc[arg_index], "--log" ) == 0 || strcmp( argc[arg_index], "--no-logo" ) == 0 ) ) {
|
||||
arg_index++;
|
||||
}
|
||||
|
||||
if ( arg_index < argn && ( strcmp( argc[arg_index], "--version" ) == 0 || strcmp( argc[arg_index], "-v" ) == 0 ) ) {
|
||||
printVersion();
|
||||
return 1;
|
||||
}
|
||||
else if ( strcmp( argc[1], "--help" ) == 0 || strcmp( argc[1], "-h" ) == 0 ) {
|
||||
printf( "Usage: ReiLua [Options] [Directory to main.lua or main]\nOptions:\n-h --help\tThis help\n-v --version\tShow ReiLua version\n-i --interpret\tInterpret mode [File name]\n" );
|
||||
else if ( arg_index < argn && ( strcmp( argc[arg_index], "--help" ) == 0 || strcmp( argc[arg_index], "-h" ) == 0 ) ) {
|
||||
printf( "Usage: ReiLua [Options] [Directory to main.lua or main]\nOptions:\n-h --help\tThis help\n-v --version\tShow ReiLua version\n-i --interpret\tInterpret mode [File name]\n--log\t\tShow console for logging\n--no-logo\tSkip splash screens (development)\n" );
|
||||
return 1;
|
||||
}
|
||||
else if ( strcmp( argc[1], "--interpret" ) == 0 || strcmp( argc[1], "-i" ) == 0 ) {
|
||||
else if ( arg_index < argn && ( strcmp( argc[arg_index], "--interpret" ) == 0 || strcmp( argc[arg_index], "-i" ) == 0 ) ) {
|
||||
interpret_mode = true;
|
||||
|
||||
if ( 2 < argn ) {
|
||||
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[2] );
|
||||
if ( arg_index + 1 < argn ) {
|
||||
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[arg_index + 1] );
|
||||
}
|
||||
}
|
||||
else{
|
||||
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[1] );
|
||||
else if ( arg_index < argn ) {
|
||||
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[arg_index] );
|
||||
}
|
||||
else {
|
||||
/* Only flags were provided, use default path search */
|
||||
char testPath[ STRING_LEN ] = { '\0' };
|
||||
sprintf( testPath, "%s/main.lua", GetWorkingDirectory() );
|
||||
|
||||
if ( FileExists( testPath ) ) {
|
||||
sprintf( basePath, "%s", GetWorkingDirectory() );
|
||||
}
|
||||
else {
|
||||
sprintf( basePath, "%s", GetApplicationDirectory() );
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If no argument given, assume main.lua is in exe directory. */
|
||||
/* If no argument given, check current directory first, then exe directory. */
|
||||
else {
|
||||
sprintf( basePath, "%s", GetApplicationDirectory() );
|
||||
char testPath[ STRING_LEN ] = { '\0' };
|
||||
sprintf( testPath, "%s/main.lua", GetWorkingDirectory() );
|
||||
|
||||
if ( FileExists( testPath ) ) {
|
||||
sprintf( basePath, "%s", GetWorkingDirectory() );
|
||||
}
|
||||
else {
|
||||
sprintf( basePath, "%s", GetApplicationDirectory() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( interpret_mode ) {
|
||||
@@ -65,15 +136,30 @@ int main( int argn, const char** argc ) {
|
||||
else {
|
||||
printVersion();
|
||||
stateInit( argn, argc, basePath );
|
||||
luaCallMain();
|
||||
luaCallInit();
|
||||
|
||||
/* Show splash screens if not skipped */
|
||||
if ( !skip_splash ) {
|
||||
splashInit();
|
||||
bool splashDone = false;
|
||||
|
||||
while ( !splashDone && !WindowShouldClose() ) {
|
||||
float delta = GetFrameTime();
|
||||
splashDone = splashUpdate( delta );
|
||||
splashDraw();
|
||||
}
|
||||
|
||||
splashCleanup();
|
||||
}
|
||||
|
||||
/* Now run the main Lua program */
|
||||
state->run = luaCallMain();
|
||||
|
||||
while ( state->run ) {
|
||||
luaCallUpdate();
|
||||
luaCallDraw();
|
||||
if ( WindowShouldClose() ) {
|
||||
state->run = false;
|
||||
}
|
||||
luaCallUpdate();
|
||||
luaCallDraw();
|
||||
}
|
||||
luaCallExit();
|
||||
}
|
||||
|
||||
198
src/splash.c
Normal file
198
src/splash.c
Normal file
@@ -0,0 +1,198 @@
|
||||
#include "main.h"
|
||||
#include "state.h"
|
||||
#include "splash.h"
|
||||
|
||||
#ifdef EMBED_LOGO
|
||||
#include "embedded_logo.h"
|
||||
#endif
|
||||
|
||||
#define FADE_IN_TIME 0.8f
|
||||
#define DISPLAY_TIME 2.5f
|
||||
#define FADE_OUT_TIME 0.8f
|
||||
#define SPLASH_TOTAL_TIME (FADE_IN_TIME + DISPLAY_TIME + FADE_OUT_TIME)
|
||||
|
||||
typedef enum {
|
||||
SPLASH_INDRAJITH,
|
||||
SPLASH_MADE_WITH,
|
||||
SPLASH_DONE
|
||||
} SplashState;
|
||||
|
||||
static SplashState currentSplash = SPLASH_INDRAJITH;
|
||||
static float splashTimer = 0.0f;
|
||||
static Texture2D raylibLogo = { 0 };
|
||||
static Texture2D reiluaLogo = { 0 };
|
||||
static bool logosLoaded = false;
|
||||
|
||||
static float getSplashAlpha( float timer ) {
|
||||
if ( timer < FADE_IN_TIME ) {
|
||||
return timer / FADE_IN_TIME;
|
||||
}
|
||||
else if ( timer < FADE_IN_TIME + DISPLAY_TIME ) {
|
||||
return 1.0f;
|
||||
}
|
||||
else {
|
||||
float fadeOut = timer - FADE_IN_TIME - DISPLAY_TIME;
|
||||
return 1.0f - ( fadeOut / FADE_OUT_TIME );
|
||||
}
|
||||
}
|
||||
|
||||
static void loadSplashLogos() {
|
||||
if ( logosLoaded ) return;
|
||||
|
||||
#ifdef EMBED_LOGO
|
||||
/* Load from embedded data */
|
||||
Image raylib_img = LoadImageFromMemory( ".png", embedded_raylib_logo, embedded_raylib_logo_size );
|
||||
raylibLogo = LoadTextureFromImage( raylib_img );
|
||||
UnloadImage( raylib_img );
|
||||
|
||||
Image reilua_img = LoadImageFromMemory( ".png", embedded_reilua_logo, embedded_reilua_logo_size );
|
||||
reiluaLogo = LoadTextureFromImage( reilua_img );
|
||||
UnloadImage( reilua_img );
|
||||
#else
|
||||
/* Load from files (development mode) */
|
||||
if ( FileExists( "logo/raylib_logo.png" ) ) {
|
||||
raylibLogo = LoadTexture( "logo/raylib_logo.png" );
|
||||
}
|
||||
if ( FileExists( "logo/reilua_logo.png" ) ) {
|
||||
reiluaLogo = LoadTexture( "logo/reilua_logo.png" );
|
||||
}
|
||||
#endif
|
||||
|
||||
logosLoaded = true;
|
||||
}
|
||||
|
||||
static void unloadSplashLogos() {
|
||||
if ( !logosLoaded ) return;
|
||||
|
||||
UnloadTexture( raylibLogo );
|
||||
UnloadTexture( reiluaLogo );
|
||||
logosLoaded = false;
|
||||
}
|
||||
|
||||
static void drawIndrajithSplash( float alpha ) {
|
||||
int screenWidth = GetScreenWidth();
|
||||
int screenHeight = GetScreenHeight();
|
||||
|
||||
ClearBackground( (Color){ 230, 41, 55, 255 } ); // Raylib red
|
||||
|
||||
const char* text = "INDRAJITH MAKES GAMES";
|
||||
int fontSize = 48;
|
||||
float spacing = 2.0f;
|
||||
|
||||
Color textColor = WHITE;
|
||||
textColor.a = (unsigned char)(255 * alpha);
|
||||
|
||||
/* Draw text with slight expansion effect during fade in */
|
||||
float scale = 0.95f + (alpha * 0.05f); // Subtle scale from 0.95 to 1.0
|
||||
|
||||
/* Measure text with proper spacing for accurate centering */
|
||||
Vector2 textSize = MeasureTextEx( state->defaultFont, text, fontSize * scale, spacing );
|
||||
|
||||
/* Calculate centered position */
|
||||
Vector2 position = {
|
||||
(float)(screenWidth / 2) - (textSize.x / 2),
|
||||
(float)(screenHeight / 2) - (textSize.y / 2)
|
||||
};
|
||||
|
||||
/* Draw with proper kerning */
|
||||
DrawTextEx( state->defaultFont, text, position, fontSize * scale, spacing, textColor );
|
||||
}
|
||||
|
||||
static void drawMadeWithSplash( float alpha ) {
|
||||
int screenWidth = GetScreenWidth();
|
||||
int screenHeight = GetScreenHeight();
|
||||
|
||||
ClearBackground( BLACK );
|
||||
|
||||
/* "Made using" text at top */
|
||||
const char* madeText = "Made using";
|
||||
int madeSize = 32;
|
||||
int madeWidth = MeasureText( madeText, madeSize );
|
||||
|
||||
Color textColor = WHITE;
|
||||
textColor.a = (unsigned char)(255 * alpha);
|
||||
|
||||
int textY = screenHeight / 2 - 100;
|
||||
DrawText( madeText, screenWidth / 2 - madeWidth / 2, textY, madeSize, textColor );
|
||||
|
||||
/* Calculate logo sizes and positions - scale down if too large */
|
||||
int maxLogoSize = 200;
|
||||
float raylibScale = 1.0f;
|
||||
float reiluaScale = 1.0f;
|
||||
|
||||
if ( raylibLogo.id > 0 && raylibLogo.width > maxLogoSize ) {
|
||||
raylibScale = (float)maxLogoSize / (float)raylibLogo.width;
|
||||
}
|
||||
if ( reiluaLogo.id > 0 && reiluaLogo.width > maxLogoSize ) {
|
||||
reiluaScale = (float)maxLogoSize / (float)reiluaLogo.width;
|
||||
}
|
||||
|
||||
int raylibWidth = (int)(raylibLogo.width * raylibScale);
|
||||
int raylibHeight = (int)(raylibLogo.height * raylibScale);
|
||||
int reiluaWidth = (int)(reiluaLogo.width * reiluaScale);
|
||||
int reiluaHeight = (int)(reiluaLogo.height * reiluaScale);
|
||||
|
||||
/* Position logos side by side with spacing */
|
||||
int spacing = 40;
|
||||
int totalWidth = raylibWidth + spacing + reiluaWidth;
|
||||
int startX = screenWidth / 2 - totalWidth / 2;
|
||||
int logoY = screenHeight / 2 - 20;
|
||||
|
||||
Color tint = WHITE;
|
||||
tint.a = (unsigned char)(255 * alpha);
|
||||
|
||||
/* Draw Raylib logo */
|
||||
if ( raylibLogo.id > 0 ) {
|
||||
Rectangle source = { 0, 0, (float)raylibLogo.width, (float)raylibLogo.height };
|
||||
Rectangle dest = { (float)startX, (float)logoY, (float)raylibWidth, (float)raylibHeight };
|
||||
DrawTexturePro( raylibLogo, source, dest, (Vector2){ 0, 0 }, 0.0f, tint );
|
||||
}
|
||||
|
||||
/* Draw ReiLua logo */
|
||||
if ( reiluaLogo.id > 0 ) {
|
||||
int reiluaX = startX + raylibWidth + spacing;
|
||||
Rectangle source = { 0, 0, (float)reiluaLogo.width, (float)reiluaLogo.height };
|
||||
Rectangle dest = { (float)reiluaX, (float)logoY, (float)reiluaWidth, (float)reiluaHeight };
|
||||
DrawTexturePro( reiluaLogo, source, dest, (Vector2){ 0, 0 }, 0.0f, tint );
|
||||
}
|
||||
}
|
||||
|
||||
void splashInit() {
|
||||
loadSplashLogos();
|
||||
currentSplash = SPLASH_INDRAJITH;
|
||||
splashTimer = 0.0f;
|
||||
}
|
||||
|
||||
bool splashUpdate( float delta ) {
|
||||
splashTimer += delta;
|
||||
|
||||
if ( splashTimer >= SPLASH_TOTAL_TIME ) {
|
||||
splashTimer = 0.0f;
|
||||
currentSplash++;
|
||||
}
|
||||
|
||||
return currentSplash >= SPLASH_DONE;
|
||||
}
|
||||
|
||||
void splashDraw() {
|
||||
float alpha = getSplashAlpha( splashTimer );
|
||||
|
||||
BeginDrawing();
|
||||
|
||||
switch ( currentSplash ) {
|
||||
case SPLASH_INDRAJITH:
|
||||
drawIndrajithSplash( alpha );
|
||||
break;
|
||||
case SPLASH_MADE_WITH:
|
||||
drawMadeWithSplash( alpha );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
void splashCleanup() {
|
||||
unloadSplashLogos();
|
||||
}
|
||||
Reference in New Issue
Block a user