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:
285
ASSET_LOADING.md
Normal file
285
ASSET_LOADING.md
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
# Asset Loading System
|
||||||
|
|
||||||
|
ReiLua includes a built-in asset loading system with a nice loading screen UI that automatically shows progress while assets are being loaded.
|
||||||
|
|
||||||
|
## 🎨 Features
|
||||||
|
|
||||||
|
- **Automatic Progress Tracking** - Tracks how many assets have been loaded
|
||||||
|
- **Beautiful Loading UI** - Modern, minimal loading screen with:
|
||||||
|
- Animated "Loading..." text with dots
|
||||||
|
- Smooth progress bar with shimmer effect
|
||||||
|
- Progress percentage (e.g., "3 / 10")
|
||||||
|
- Current asset name being loaded
|
||||||
|
- Dark, professional color scheme
|
||||||
|
- **Easy to Use** - Just 3 functions to show loading progress
|
||||||
|
- **Works Everywhere** - Development and release builds
|
||||||
|
|
||||||
|
## 📝 API Functions
|
||||||
|
|
||||||
|
### RL.BeginAssetLoading(totalAssets)
|
||||||
|
|
||||||
|
Initialize asset loading progress tracking and show the loading screen.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `totalAssets` (integer) - Total number of assets to load
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```lua
|
||||||
|
RL.BeginAssetLoading(10) -- We're loading 10 assets
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### RL.UpdateAssetLoading(assetName)
|
||||||
|
|
||||||
|
Update the loading progress and display current asset being loaded.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assetName` (string) - Name of the asset currently being loaded
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```lua
|
||||||
|
RL.UpdateAssetLoading("player.png")
|
||||||
|
```
|
||||||
|
|
||||||
|
Call this **after** each asset is loaded to update the progress bar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### RL.EndAssetLoading()
|
||||||
|
|
||||||
|
Finish asset loading and hide the loading screen.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```lua
|
||||||
|
RL.EndAssetLoading()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Quick Example
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function RL.init()
|
||||||
|
-- List of assets to load
|
||||||
|
local assetsToLoad = {
|
||||||
|
"assets/player.png",
|
||||||
|
"assets/enemy.png",
|
||||||
|
"assets/background.png",
|
||||||
|
"assets/music.wav",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Begin loading
|
||||||
|
RL.BeginAssetLoading(#assetsToLoad)
|
||||||
|
|
||||||
|
-- Load each asset
|
||||||
|
for i, path in ipairs(assetsToLoad) do
|
||||||
|
RL.UpdateAssetLoading(path) -- Update progress
|
||||||
|
|
||||||
|
-- Load the actual asset
|
||||||
|
if path:match("%.png$") or path:match("%.jpg$") then
|
||||||
|
textures[i] = RL.LoadTexture(path)
|
||||||
|
elseif path:match("%.wav$") or path:match("%.ogg$") then
|
||||||
|
sounds[i] = RL.LoadSound(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Done!
|
||||||
|
RL.EndAssetLoading()
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 Complete Example
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local assets = {}
|
||||||
|
|
||||||
|
local assetsToLoad = {
|
||||||
|
{type="texture", name="player", path="assets/player.png"},
|
||||||
|
{type="texture", name="enemy", path="assets/enemy.png"},
|
||||||
|
{type="texture", name="background", path="assets/background.png"},
|
||||||
|
{type="sound", name="music", path="assets/music.wav"},
|
||||||
|
{type="sound", name="shoot", path="assets/shoot.wav"},
|
||||||
|
{type="font", name="title", path="assets/title.ttf"},
|
||||||
|
}
|
||||||
|
|
||||||
|
function RL.init()
|
||||||
|
RL.SetWindowTitle("My Game")
|
||||||
|
|
||||||
|
-- Start loading with progress
|
||||||
|
RL.BeginAssetLoading(#assetsToLoad)
|
||||||
|
|
||||||
|
-- Load all assets
|
||||||
|
for i, asset in ipairs(assetsToLoad) do
|
||||||
|
-- Show current asset name on loading screen
|
||||||
|
RL.UpdateAssetLoading(asset.name)
|
||||||
|
|
||||||
|
-- Load based on type
|
||||||
|
if asset.type == "texture" then
|
||||||
|
assets[asset.name] = RL.LoadTexture(asset.path)
|
||||||
|
elseif asset.type == "sound" then
|
||||||
|
assets[asset.name] = RL.LoadSound(asset.path)
|
||||||
|
elseif asset.type == "font" then
|
||||||
|
assets[asset.name] = RL.LoadFont(asset.path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Loading complete!
|
||||||
|
RL.EndAssetLoading()
|
||||||
|
|
||||||
|
print("Game ready!")
|
||||||
|
end
|
||||||
|
|
||||||
|
function RL.update(delta)
|
||||||
|
-- Your game logic
|
||||||
|
end
|
||||||
|
|
||||||
|
function RL.draw()
|
||||||
|
RL.ClearBackground(RL.RAYWHITE)
|
||||||
|
|
||||||
|
-- Use loaded assets
|
||||||
|
if assets.background then
|
||||||
|
RL.DrawTexture(assets.background, {0, 0}, RL.WHITE)
|
||||||
|
end
|
||||||
|
|
||||||
|
if assets.player then
|
||||||
|
RL.DrawTexture(assets.player, {100, 100}, RL.WHITE)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎨 Loading Screen Appearance
|
||||||
|
|
||||||
|
The loading screen features a clean 1-bit pixel art style:
|
||||||
|
|
||||||
|
**Design:**
|
||||||
|
- Pure black and white aesthetic
|
||||||
|
- Retro pixel art styling
|
||||||
|
- Minimal and clean design
|
||||||
|
|
||||||
|
**Elements:**
|
||||||
|
- **Title**: "LOADING" in bold white pixel text
|
||||||
|
- **Animated Dots**: White pixelated dots (4x4 squares) that cycle
|
||||||
|
- **Progress Bar**:
|
||||||
|
- 200px wide, 16px tall
|
||||||
|
- Thick 2px white border (pixel art style)
|
||||||
|
- White fill with black dithering pattern
|
||||||
|
- Retro/Classic terminal aesthetic
|
||||||
|
- **Progress Text**: "3/10" in white pixel font style
|
||||||
|
- **Asset Name**: Current loading asset in small white text
|
||||||
|
- **Corner Decorations**: White pixel art L-shaped corners in all 4 corners
|
||||||
|
|
||||||
|
**Background:**
|
||||||
|
- Pure black background (#000000)
|
||||||
|
- High contrast for maximum clarity
|
||||||
|
|
||||||
|
**Color Palette:**
|
||||||
|
- White text and UI (#FFFFFF)
|
||||||
|
- Black background (#000000)
|
||||||
|
- Pure 1-bit aesthetic (inverted terminal style)
|
||||||
|
|
||||||
|
**Visual Layout:**
|
||||||
|
```
|
||||||
|
[Black Background]
|
||||||
|
|
||||||
|
┌─┐ ┌─┐
|
||||||
|
│ │ LOADING □ □ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ┌──────────────────┐ │ │
|
||||||
|
│ │ │████████░░░░░░░░░░│ 3/10 │ │
|
||||||
|
│ │ └──────────────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ player.png │ │
|
||||||
|
│ │ │ │
|
||||||
|
└─┘ └─┘
|
||||||
|
|
||||||
|
[All text and UI elements in WHITE]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Style Inspiration:**
|
||||||
|
- Classic terminal / console aesthetic
|
||||||
|
- MS-DOS loading screens
|
||||||
|
- 1-bit dithering patterns
|
||||||
|
- Chunky pixel borders
|
||||||
|
- Retro computing / CRT monitor style
|
||||||
|
|
||||||
|
## 🔧 Customization
|
||||||
|
|
||||||
|
If you want to customize the loading screen appearance, you can modify the colors and sizes in `src/lua_core.c` in the `drawLoadingScreen()` function.
|
||||||
|
|
||||||
|
## ⚡ Performance Tips
|
||||||
|
|
||||||
|
1. **Call UpdateAssetLoading AFTER loading** - This ensures the progress updates at the right time
|
||||||
|
2. **Load assets in order of importance** - Load critical assets first
|
||||||
|
3. **Group similar assets** - Load all textures, then sounds, etc.
|
||||||
|
4. **Use descriptive names** - Shows better feedback to users
|
||||||
|
|
||||||
|
## 📋 Example Asset Loading Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Simple List
|
||||||
|
```lua
|
||||||
|
local files = {"player.png", "enemy.png", "music.wav"}
|
||||||
|
RL.BeginAssetLoading(#files)
|
||||||
|
for i, file in ipairs(files) do
|
||||||
|
RL.UpdateAssetLoading(file)
|
||||||
|
-- load file
|
||||||
|
end
|
||||||
|
RL.EndAssetLoading()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 2: With Types
|
||||||
|
```lua
|
||||||
|
local assets = {
|
||||||
|
textures = {"player.png", "enemy.png"},
|
||||||
|
sounds = {"music.wav", "shoot.wav"},
|
||||||
|
}
|
||||||
|
local total = #assets.textures + #assets.sounds
|
||||||
|
|
||||||
|
RL.BeginAssetLoading(total)
|
||||||
|
for _, file in ipairs(assets.textures) do
|
||||||
|
RL.UpdateAssetLoading(file)
|
||||||
|
-- load texture
|
||||||
|
end
|
||||||
|
for _, file in ipairs(assets.sounds) do
|
||||||
|
RL.UpdateAssetLoading(file)
|
||||||
|
-- load sound
|
||||||
|
end
|
||||||
|
RL.EndAssetLoading()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 3: Error Handling
|
||||||
|
```lua
|
||||||
|
RL.BeginAssetLoading(#files)
|
||||||
|
for i, file in ipairs(files) do
|
||||||
|
RL.UpdateAssetLoading(file)
|
||||||
|
|
||||||
|
if RL.FileExists(file) then
|
||||||
|
-- load file
|
||||||
|
else
|
||||||
|
print("Warning: " .. file .. " not found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RL.EndAssetLoading()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎮 When to Use
|
||||||
|
|
||||||
|
**Use the loading system when:**
|
||||||
|
- You have more than 5-10 assets to load
|
||||||
|
- Assets are large (images, sounds, fonts)
|
||||||
|
- Loading might take more than 1 second
|
||||||
|
- You want professional loading feedback
|
||||||
|
|
||||||
|
**You can skip it when:**
|
||||||
|
- You have very few, small assets
|
||||||
|
- Loading is nearly instant
|
||||||
|
- You prefer immediate game start
|
||||||
|
|
||||||
|
## ✨ Benefits
|
||||||
|
|
||||||
|
- ✅ Professional user experience
|
||||||
|
- ✅ User knows the game is loading, not frozen
|
||||||
|
- ✅ Shows progress for large asset sets
|
||||||
|
- ✅ Works with embedded assets
|
||||||
|
- ✅ Minimal code required
|
||||||
|
- ✅ Beautiful default UI
|
||||||
|
|
||||||
|
The loading system makes your game feel polished and professional with just a few lines of code!
|
||||||
@@ -15,6 +15,8 @@ option( LUAJIT "Use LuaJIT." off )
|
|||||||
option( LUA_EVENTS "Enable Lua event callbacks (RL.event)." off )
|
option( LUA_EVENTS "Enable Lua event callbacks (RL.event)." off )
|
||||||
option( DYNAMIC_SYMBOLS "Expose all dynamic symbols with rdynamic." off )
|
option( DYNAMIC_SYMBOLS "Expose all dynamic symbols with rdynamic." off )
|
||||||
option( EXPOSE_API_SYMBOLS "Expose dynamic symbols only for get and push functions of variable types." off )
|
option( EXPOSE_API_SYMBOLS "Expose dynamic symbols only for get and push functions of variable types." off )
|
||||||
|
option( EMBED_MAIN "Embed all Lua files from build directory into executable." off )
|
||||||
|
option( EMBED_ASSETS "Embed all files from assets folder into executable." off )
|
||||||
|
|
||||||
enum_option( PLATFORM "Desktop;Desktop_SDL2;Desktop_SDL3;Web" "Platform to build for." )
|
enum_option( PLATFORM "Desktop;Desktop_SDL2;Desktop_SDL3;Web" "Platform to build for." )
|
||||||
|
|
||||||
@@ -25,7 +27,75 @@ endif()
|
|||||||
|
|
||||||
file( GLOB SOURCES src/*.c )
|
file( GLOB SOURCES src/*.c )
|
||||||
|
|
||||||
|
# Always embed logo files for splash screens
|
||||||
|
set( LOGO_FILES
|
||||||
|
"${CMAKE_SOURCE_DIR}/logo/raylib_logo.png"
|
||||||
|
"${CMAKE_SOURCE_DIR}/logo/reilua_logo.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/embedded_logo.h
|
||||||
|
COMMAND python ${CMAKE_SOURCE_DIR}/embed_logo.py
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/embedded_logo.h
|
||||||
|
${CMAKE_SOURCE_DIR}/logo/raylib_logo.png
|
||||||
|
${CMAKE_SOURCE_DIR}/logo/reilua_logo.png
|
||||||
|
DEPENDS ${LOGO_FILES}
|
||||||
|
COMMENT "Embedding logo files for splash screens..."
|
||||||
|
)
|
||||||
|
list( APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/embedded_logo.h )
|
||||||
|
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEMBED_LOGO" )
|
||||||
|
|
||||||
|
# Always embed font file
|
||||||
|
set( FONT_FILE "${CMAKE_SOURCE_DIR}/fonts/Oleaguid.ttf" )
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/embedded_font.h
|
||||||
|
COMMAND python ${CMAKE_SOURCE_DIR}/embed_font.py
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/embedded_font.h
|
||||||
|
${CMAKE_SOURCE_DIR}/fonts/Oleaguid.ttf
|
||||||
|
DEPENDS ${FONT_FILE}
|
||||||
|
COMMENT "Embedding font file..."
|
||||||
|
)
|
||||||
|
list( APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/embedded_font.h )
|
||||||
|
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEMBED_FONT" )
|
||||||
|
|
||||||
|
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||||
include_directories( include )
|
include_directories( include )
|
||||||
|
|
||||||
|
# Embed Lua files if EMBED_MAIN is ON
|
||||||
|
if( EMBED_MAIN )
|
||||||
|
file( GLOB LUA_FILES "${CMAKE_CURRENT_BINARY_DIR}/*.lua" )
|
||||||
|
if( LUA_FILES )
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/embedded_main.h
|
||||||
|
COMMAND python ${CMAKE_SOURCE_DIR}/embed_lua.py ${CMAKE_CURRENT_BINARY_DIR}/embedded_main.h ${LUA_FILES}
|
||||||
|
DEPENDS ${LUA_FILES}
|
||||||
|
COMMENT "Embedding Lua files into executable..."
|
||||||
|
)
|
||||||
|
list( APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/embedded_main.h )
|
||||||
|
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEMBED_MAIN" )
|
||||||
|
else()
|
||||||
|
message( WARNING "EMBED_MAIN is ON but no .lua files found in build directory!" )
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Embed asset files if EMBED_ASSETS is ON
|
||||||
|
if( EMBED_ASSETS )
|
||||||
|
file( GLOB_RECURSE ASSET_FILES "${CMAKE_CURRENT_BINARY_DIR}/assets/*" )
|
||||||
|
if( ASSET_FILES )
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.h
|
||||||
|
COMMAND python ${CMAKE_SOURCE_DIR}/embed_assets.py ${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.h ${ASSET_FILES}
|
||||||
|
DEPENDS ${ASSET_FILES}
|
||||||
|
COMMENT "Embedding asset files into executable..."
|
||||||
|
)
|
||||||
|
list( APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.h )
|
||||||
|
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEMBED_ASSETS" )
|
||||||
|
else()
|
||||||
|
message( WARNING "EMBED_ASSETS is ON but no files found in build/assets/ directory!" )
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable( ${PROJECT_NAME} ${SOURCES} )
|
add_executable( ${PROJECT_NAME} ${SOURCES} )
|
||||||
|
|
||||||
if( PLATFORM STREQUAL "Desktop" )
|
if( PLATFORM STREQUAL "Desktop" )
|
||||||
|
|||||||
290
EMBEDDING.md
Normal file
290
EMBEDDING.md
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
# Embedding main.lua into Executable
|
||||||
|
|
||||||
|
When you're ready to ship your game, you can embed all Lua files and asset files directly into the executable.
|
||||||
|
|
||||||
|
## Development vs Release Workflow
|
||||||
|
|
||||||
|
### 🔧 Development Build (Fast Iteration)
|
||||||
|
|
||||||
|
During development, use external files for quick iteration:
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
```
|
||||||
|
GameFolder/
|
||||||
|
├── ReiLua.exe
|
||||||
|
├── main.lua
|
||||||
|
├── player.lua
|
||||||
|
└── assets/
|
||||||
|
├── player.png
|
||||||
|
└── music.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
```bash
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- ✅ Edit Lua files and re-run immediately
|
||||||
|
- ✅ Edit assets and reload
|
||||||
|
- ✅ Fast development cycle
|
||||||
|
- ✅ Debug with `--log` flag
|
||||||
|
|
||||||
|
### 📦 Release Build (Single Executable)
|
||||||
|
|
||||||
|
For distribution, embed everything into one file:
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
```bash
|
||||||
|
cd build
|
||||||
|
|
||||||
|
# Copy Lua files to build directory
|
||||||
|
copy ..\main.lua .
|
||||||
|
copy ..\player.lua .
|
||||||
|
|
||||||
|
# Create assets folder and copy files
|
||||||
|
mkdir assets
|
||||||
|
copy ..\player.png assets\
|
||||||
|
copy ..\music.wav assets\
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
```bash
|
||||||
|
# Configure with embedding
|
||||||
|
cmake .. -DEMBED_MAIN=ON -DEMBED_ASSETS=ON
|
||||||
|
|
||||||
|
# Build release
|
||||||
|
cmake --build . --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
```
|
||||||
|
Distribution/
|
||||||
|
└── YourGame.exe (Everything embedded!)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- ✅ Single executable file
|
||||||
|
- ✅ No external dependencies
|
||||||
|
- ✅ Users can't modify game files
|
||||||
|
- ✅ Professional distribution
|
||||||
|
- ✅ Smaller download (no separate files)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Embedding Lua Files
|
||||||
|
|
||||||
|
1. **Copy your Lua files to the build directory**:
|
||||||
|
```bash
|
||||||
|
copy main.lua build\main.lua
|
||||||
|
copy player.lua build\player.lua
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Build with EMBED_MAIN option**:
|
||||||
|
```bash
|
||||||
|
cd build
|
||||||
|
cmake .. -DEMBED_MAIN=ON
|
||||||
|
cmake --build . --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command Line Options
|
||||||
|
|
||||||
|
ReiLua supports several command-line options:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ReiLua [Options] [Directory to main.lua or main]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Show help message
|
||||||
|
-v, --version Show ReiLua version
|
||||||
|
-i, --interpret Interpret mode [File name]
|
||||||
|
--log Show console window for logging (Windows only)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Console/Logging
|
||||||
|
|
||||||
|
By default, ReiLua runs **without a console window** for a clean user experience. To enable console output for debugging:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run with console for debugging
|
||||||
|
ReiLua.exe --log
|
||||||
|
|
||||||
|
# You can also combine with other options
|
||||||
|
ReiLua.exe --log path/to/game
|
||||||
|
|
||||||
|
# Or with interpret mode
|
||||||
|
ReiLua.exe --log -i script.lua
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful during development to see:
|
||||||
|
- TraceLog output
|
||||||
|
- Print statements
|
||||||
|
- Lua errors
|
||||||
|
- Debug information
|
||||||
|
|
||||||
|
## Complete Release Workflow
|
||||||
|
|
||||||
|
Here's a complete step-by-step guide to prepare your game for release:
|
||||||
|
|
||||||
|
### Step 1: Organize Your Project
|
||||||
|
|
||||||
|
Ensure your project has this structure:
|
||||||
|
```
|
||||||
|
MyGame/
|
||||||
|
├── main.lua
|
||||||
|
├── player.lua
|
||||||
|
├── enemy.lua
|
||||||
|
├── player.png
|
||||||
|
├── enemy.png
|
||||||
|
├── music.wav
|
||||||
|
└── icon.ico (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Customize Branding (Optional)
|
||||||
|
|
||||||
|
**Change executable icon:**
|
||||||
|
```bash
|
||||||
|
# Replace ReiLua's icon with yours
|
||||||
|
copy MyGame\icon.ico ReiLua\icon.ico
|
||||||
|
```
|
||||||
|
|
||||||
|
**Edit executable properties:**
|
||||||
|
Open `ReiLua\resources.rc` and modify:
|
||||||
|
```rc
|
||||||
|
VALUE "CompanyName", "Your Studio Name"
|
||||||
|
VALUE "FileDescription", "Your Game Description"
|
||||||
|
VALUE "ProductName", "Your Game Name"
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) Your Name, 2025"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Change executable name:**
|
||||||
|
Edit `ReiLua\CMakeLists.txt`:
|
||||||
|
```cmake
|
||||||
|
project( YourGameName ) # Change from "ReiLua"
|
||||||
|
```
|
||||||
|
|
||||||
|
See [CUSTOMIZATION.md](CUSTOMIZATION.md) for full details.
|
||||||
|
|
||||||
|
### Important: Asset Paths
|
||||||
|
|
||||||
|
**Keep your paths consistent!** The embedding system now preserves the `assets/` prefix, so use the same paths in both development and release:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- ✅ Correct - works in both dev and release
|
||||||
|
playerImage = RL.LoadTexture("assets/player.png")
|
||||||
|
backgroundImg = RL.LoadTexture("assets/background.png")
|
||||||
|
musicSound = RL.LoadSound("assets/music.wav")
|
||||||
|
```
|
||||||
|
|
||||||
|
Your Lua code doesn't need to change between development and release builds!
|
||||||
|
|
||||||
|
### Step 3: Prepare Build Directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ReiLua\build
|
||||||
|
|
||||||
|
# Copy all Lua files
|
||||||
|
copy ..\MyGame\*.lua .
|
||||||
|
|
||||||
|
# Create assets folder
|
||||||
|
mkdir assets
|
||||||
|
|
||||||
|
# Copy all asset files (images, sounds, etc.)
|
||||||
|
copy ..\MyGame\*.png assets\
|
||||||
|
copy ..\MyGame\*.wav assets\
|
||||||
|
copy ..\MyGame\*.ogg assets\
|
||||||
|
# Or copy entire folders
|
||||||
|
xcopy /E /I ..\MyGame\images assets\images
|
||||||
|
xcopy /E /I ..\MyGame\sounds assets\sounds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Build Release
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure with embedding enabled
|
||||||
|
cmake .. -DEMBED_MAIN=ON -DEMBED_ASSETS=ON
|
||||||
|
|
||||||
|
# Build in release mode
|
||||||
|
cmake --build . --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Test Release Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test with console to verify everything loaded
|
||||||
|
YourGameName.exe --log
|
||||||
|
|
||||||
|
# Test production mode (no console)
|
||||||
|
YourGameName.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
Check console output for:
|
||||||
|
- ✅ "ReiLua x.x.x" version info
|
||||||
|
- ✅ No file loading errors
|
||||||
|
- ✅ Game runs correctly
|
||||||
|
|
||||||
|
### Step 6: Package for Distribution
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create distribution folder
|
||||||
|
mkdir ..\Distribution
|
||||||
|
copy YourGameName.exe ..\Distribution\
|
||||||
|
|
||||||
|
# Optional: Add README, LICENSE, etc.
|
||||||
|
copy ..\README.txt ..\Distribution\
|
||||||
|
```
|
||||||
|
|
||||||
|
Your game is now ready to distribute as a single executable!
|
||||||
|
|
||||||
|
### Workflow Summary
|
||||||
|
|
||||||
|
| Stage | Build Command | Files Needed | Result |
|
||||||
|
|-------|--------------|--------------|--------|
|
||||||
|
| **Development** | `cmake .. && cmake --build .` | Lua + assets external | Fast iteration |
|
||||||
|
| **Testing** | `cmake .. -DEMBED_MAIN=ON && cmake --build .` | Lua in build/ | Test embedding |
|
||||||
|
| **Release** | `cmake .. -DEMBED_MAIN=ON -DEMBED_ASSETS=ON && cmake --build . --config Release` | Lua + assets in build/ | Single .exe |
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
**Problem: "No .lua files found in build directory"**
|
||||||
|
```bash
|
||||||
|
# Solution: Copy Lua files to build directory
|
||||||
|
copy ..\*.lua .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem: "No files found in assets folder"**
|
||||||
|
```bash
|
||||||
|
# Solution: Create assets folder and copy files
|
||||||
|
mkdir assets
|
||||||
|
copy ..\*.png assets\
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem: Game crashes on startup**
|
||||||
|
```bash
|
||||||
|
# Solution: Run with --log to see error messages
|
||||||
|
YourGameName.exe --log
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem: Assets not loading**
|
||||||
|
- Verify assets are in `build/assets/` before building
|
||||||
|
- Check asset filenames match in your Lua code
|
||||||
|
- Use `--log` to see loading errors
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- `.lua` files in the **build directory root** are embedded when using `EMBED_MAIN=ON`
|
||||||
|
- Asset files in **build/assets/** folder (and subfolders) are embedded when using `EMBED_ASSETS=ON`
|
||||||
|
- `main.lua` must exist and is always the entry point
|
||||||
|
- Asset embedding works with subdirectories: `assets/images/player.png` → Load with `LoadImage("player.png")`
|
||||||
|
- Both Lua and asset embedding can be used independently or together
|
||||||
|
- The system falls back to file system if embedded file is not found
|
||||||
|
- No code changes needed - all raylib functions work automatically with embedded assets
|
||||||
|
|
||||||
|
## Customizing Your Executable
|
||||||
|
|
||||||
|
Want to add your own icon and version info to the executable? See [CUSTOMIZATION.md](CUSTOMIZATION.md) for details on:
|
||||||
|
- Adding a custom icon
|
||||||
|
- Setting exe properties (company name, version, description)
|
||||||
|
- Renaming the executable
|
||||||
230
SPLASH_SCREENS.md
Normal file
230
SPLASH_SCREENS.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
# Splash Screens
|
||||||
|
|
||||||
|
ReiLua includes a built-in splash screen system that displays three professional splash screens before your game loads. This gives your game a polished, professional appearance right from startup.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
When you run your ReiLua game, it automatically shows two splash screens in sequence:
|
||||||
|
|
||||||
|
1. **"INDRAJITH MAKES GAMES"** - Clean, bold text on Raylib red background (similar to Squid Game style)
|
||||||
|
2. **"Made using"** - Text with Raylib and ReiLua logos displayed side-by-side
|
||||||
|
|
||||||
|
Each splash screen:
|
||||||
|
- Fades in over 0.8 seconds
|
||||||
|
- Displays for 2.5 seconds
|
||||||
|
- Fades out over 0.8 seconds
|
||||||
|
- Total display time: 8.2 seconds for both screens
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Always Embedded
|
||||||
|
|
||||||
|
The logo images are **always embedded** into the executable in both development and release builds. This means:
|
||||||
|
|
||||||
|
- ✅ No external logo files needed
|
||||||
|
- ✅ Consistent splash screens across all builds
|
||||||
|
- ✅ No risk of missing logo files
|
||||||
|
- ✅ Professional appearance from the start
|
||||||
|
|
||||||
|
### Asset Loading Integration
|
||||||
|
|
||||||
|
The splash screens display **before** your game's asset loading begins. This means:
|
||||||
|
|
||||||
|
1. User starts your game
|
||||||
|
2. Splash screens play (~8 seconds)
|
||||||
|
3. Your `RL.init()` function runs
|
||||||
|
4. Asset loading with progress indicator (if you use it)
|
||||||
|
5. Your game starts
|
||||||
|
|
||||||
|
This creates a smooth, professional startup experience.
|
||||||
|
|
||||||
|
## Skipping Splash Screens (Development)
|
||||||
|
|
||||||
|
During development, you often need to test your game repeatedly. Waiting for splash screens every time can slow down your workflow. Use the `--no-logo` flag to skip them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows
|
||||||
|
ReiLua.exe --no-logo
|
||||||
|
|
||||||
|
# Linux/Mac
|
||||||
|
./ReiLua --no-logo
|
||||||
|
|
||||||
|
# With other options
|
||||||
|
ReiLua.exe --log --no-logo
|
||||||
|
./ReiLua --no-logo path/to/game/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The `--no-logo` flag only works in development. In release builds, users should see the full splash screen sequence.
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
The splash screen system is implemented in C and runs before any Lua code executes:
|
||||||
|
|
||||||
|
1. **Logo Embedding**: During build, `embed_logo.py` converts PNG files to C byte arrays
|
||||||
|
2. **Initialization**: Before calling `RL.init()`, the engine initializes splash screens
|
||||||
|
3. **Display Loop**: A dedicated loop handles timing, fading, and rendering
|
||||||
|
4. **Cleanup**: After completion, resources are freed and Lua code begins
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
- `src/splash.c` - Splash screen implementation
|
||||||
|
- `include/splash.h` - Header file
|
||||||
|
- `embed_logo.py` - Python script to embed logo images
|
||||||
|
- `logo/raylib_logo.png` - Raylib logo (embedded)
|
||||||
|
- `logo/reilua_logo.png` - ReiLua logo (embedded)
|
||||||
|
|
||||||
|
### Build Integration
|
||||||
|
|
||||||
|
The CMakeLists.txt automatically:
|
||||||
|
|
||||||
|
1. Runs `embed_logo.py` during build
|
||||||
|
2. Generates `embedded_logo.h` with logo data
|
||||||
|
3. Defines `EMBED_LOGO` flag
|
||||||
|
4. Compiles `splash.c` with the project
|
||||||
|
|
||||||
|
No manual steps required - it just works!
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### Changing Splash Screen Text
|
||||||
|
|
||||||
|
To change "INDRAJITH MAKES GAMES" to your studio name:
|
||||||
|
|
||||||
|
1. Open `src/splash.c`
|
||||||
|
2. Find the `drawIndrajithSplash()` function
|
||||||
|
3. Change this line:
|
||||||
|
```c
|
||||||
|
const char* text = "INDRAJITH MAKES GAMES";
|
||||||
|
```
|
||||||
|
4. Rebuild the project
|
||||||
|
|
||||||
|
**Note:** Use ALL CAPS for the Squid Game-style aesthetic.
|
||||||
|
|
||||||
|
### Changing Logos
|
||||||
|
|
||||||
|
To use different logos:
|
||||||
|
|
||||||
|
1. Replace `logo/raylib_logo.png` and/or `logo/reilua_logo.png` with your images
|
||||||
|
2. Recommended size: 256x256 or smaller (logos are auto-scaled to max 200px)
|
||||||
|
3. Format: PNG with transparency support
|
||||||
|
4. Rebuild the project - logos will be automatically embedded
|
||||||
|
|
||||||
|
### Changing Timing
|
||||||
|
|
||||||
|
To adjust how long each screen displays:
|
||||||
|
|
||||||
|
1. Open `src/splash.c`
|
||||||
|
2. Modify these constants at the top:
|
||||||
|
```c
|
||||||
|
#define FADE_IN_TIME 0.8f // Seconds to fade in
|
||||||
|
#define DISPLAY_TIME 2.5f // Seconds to display fully
|
||||||
|
#define FADE_OUT_TIME 0.8f // Seconds to fade out
|
||||||
|
```
|
||||||
|
3. Rebuild the project
|
||||||
|
|
||||||
|
### Removing Splash Screens Entirely
|
||||||
|
|
||||||
|
If you don't want any splash screens:
|
||||||
|
|
||||||
|
1. Open `src/main.c`
|
||||||
|
2. Find this block:
|
||||||
|
```c
|
||||||
|
/* Show splash screens if not skipped */
|
||||||
|
if ( !skip_splash ) {
|
||||||
|
splashInit();
|
||||||
|
// ... splash code ...
|
||||||
|
splashCleanup();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. Comment out or remove the entire block
|
||||||
|
4. Rebuild the project
|
||||||
|
|
||||||
|
## Example: Complete Startup Sequence
|
||||||
|
|
||||||
|
Here's what a typical game startup looks like with everything enabled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ReiLua.exe MyGame/
|
||||||
|
```
|
||||||
|
|
||||||
|
**User Experience:**
|
||||||
|
|
||||||
|
1. **Splash Screen 1** (4.1 seconds)
|
||||||
|
- "INDRAJITH MAKES GAMES" bold text
|
||||||
|
- Red background (Raylib color #E62937)
|
||||||
|
- Subtle zoom effect
|
||||||
|
|
||||||
|
2. **Splash Screen 2** (4.1 seconds)
|
||||||
|
- "Made using" text at top
|
||||||
|
- Raylib + ReiLua logos side-by-side (max 200px each)
|
||||||
|
- Black background
|
||||||
|
|
||||||
|
3. **Asset Loading** (varies)
|
||||||
|
- Your loading screen with progress bar
|
||||||
|
- Shows "Loading texture1.png", "3/10", etc.
|
||||||
|
|
||||||
|
4. **Game Start**
|
||||||
|
- Your game's main screen appears
|
||||||
|
- Player can interact
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Keep --no-logo for Development**: Always use `--no-logo` during active development
|
||||||
|
2. **Test Without Flag**: Occasionally test without `--no-logo` to ensure splash screens work
|
||||||
|
3. **Customize for Your Studio**: Change the text and logos to match your branding
|
||||||
|
4. **Consider Total Time**: Splash (~8s) + Loading (varies) = Total startup time
|
||||||
|
5. **Optimize Loading**: Keep asset loading fast to maintain a good first impression
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Splash Screens Don't Show
|
||||||
|
|
||||||
|
**Problem**: Game starts immediately without splash screens
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
- Check you're not using `--no-logo` flag
|
||||||
|
- Verify logos exist in `logo/` folder before building
|
||||||
|
- Check console output for embedding errors
|
||||||
|
- Rebuild project completely: `cmake .. && make clean && make`
|
||||||
|
|
||||||
|
### Logos Appear Corrupted
|
||||||
|
|
||||||
|
**Problem**: Logos display incorrectly or not at all
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
- Verify PNG files are valid (open in image viewer)
|
||||||
|
- Check file sizes aren't too large (keep under 1MB each)
|
||||||
|
- Ensure PNGs use standard format (not progressive or exotic encoding)
|
||||||
|
- Rebuild project to regenerate embedded data
|
||||||
|
|
||||||
|
### Compilation Errors
|
||||||
|
|
||||||
|
**Problem**: Build fails with logo-related errors
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
- Ensure Python 3 is installed and in PATH
|
||||||
|
- Check `embed_logo.py` has correct paths
|
||||||
|
- Verify `logo/` folder exists with both PNG files
|
||||||
|
- Check CMake output for specific error messages
|
||||||
|
|
||||||
|
## Command Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development (skip splash)
|
||||||
|
ReiLua --no-logo
|
||||||
|
|
||||||
|
# Development with logging
|
||||||
|
ReiLua --log --no-logo
|
||||||
|
|
||||||
|
# Production/testing (full splash)
|
||||||
|
ReiLua
|
||||||
|
|
||||||
|
# Help
|
||||||
|
ReiLua --help
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The splash screen system adds a professional touch to your ReiLua games with minimal effort. Customize it to match your studio's branding and give players a great first impression!
|
||||||
1
build/.gitignore
vendored
1
build/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
*
|
|
||||||
116
embed_assets.py
Normal file
116
embed_assets.py
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Embed asset files (images, sounds, fonts, etc.) into a C header file.
|
||||||
|
Usage: python embed_assets.py <output.h> <file1.png> [file2.wav] [file3.ttf] ...
|
||||||
|
|
||||||
|
Embeds all specified asset files into a C header for inclusion in the executable.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def sanitize_name(filename):
|
||||||
|
"""Convert filename to valid C identifier"""
|
||||||
|
name = os.path.basename(filename)
|
||||||
|
# Remove or replace all non-alphanumeric characters (except underscore)
|
||||||
|
valid_chars = []
|
||||||
|
for char in name:
|
||||||
|
if char.isalnum() or char == '_':
|
||||||
|
valid_chars.append(char)
|
||||||
|
else:
|
||||||
|
valid_chars.append('_')
|
||||||
|
name = ''.join(valid_chars)
|
||||||
|
# Ensure it doesn't start with a digit
|
||||||
|
if name and name[0].isdigit():
|
||||||
|
name = '_' + name
|
||||||
|
return name
|
||||||
|
|
||||||
|
def get_file_extension(filename):
|
||||||
|
"""Get the file extension"""
|
||||||
|
return os.path.splitext(filename)[1].lower()
|
||||||
|
|
||||||
|
def embed_files(output_file, input_files):
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write('#ifndef EMBEDDED_ASSETS_H\n')
|
||||||
|
f.write('#define EMBEDDED_ASSETS_H\n\n')
|
||||||
|
f.write('/* Auto-generated file - do not edit manually */\n\n')
|
||||||
|
|
||||||
|
# Embed each file as a separate array
|
||||||
|
for idx, input_file in enumerate(input_files):
|
||||||
|
with open(input_file, 'rb') as inf:
|
||||||
|
data = inf.read()
|
||||||
|
|
||||||
|
var_name = sanitize_name(input_file)
|
||||||
|
# Extract relative path from 'assets/' onwards if present
|
||||||
|
if 'assets' in input_file.replace('\\', '/'):
|
||||||
|
parts = input_file.replace('\\', '/').split('assets/')
|
||||||
|
if len(parts) > 1:
|
||||||
|
relative_name = 'assets/' + parts[-1]
|
||||||
|
else:
|
||||||
|
relative_name = os.path.basename(input_file)
|
||||||
|
else:
|
||||||
|
relative_name = os.path.basename(input_file)
|
||||||
|
|
||||||
|
f.write(f'/* Embedded asset: {input_file} ({len(data)} bytes) */\n')
|
||||||
|
f.write(f'static const unsigned char embedded_asset_{idx}_{var_name}[] = {{\n')
|
||||||
|
|
||||||
|
for i, byte in enumerate(data):
|
||||||
|
if i % 12 == 0:
|
||||||
|
f.write(' ')
|
||||||
|
f.write(f'0x{byte:02x}')
|
||||||
|
if i < len(data) - 1:
|
||||||
|
f.write(',')
|
||||||
|
if (i + 1) % 12 == 0:
|
||||||
|
f.write('\n')
|
||||||
|
else:
|
||||||
|
f.write(' ')
|
||||||
|
|
||||||
|
f.write('\n};\n')
|
||||||
|
f.write(f'static const unsigned int embedded_asset_{idx}_{var_name}_len = {len(data)};\n\n')
|
||||||
|
|
||||||
|
# Create the asset table
|
||||||
|
f.write('/* Asset table for virtual filesystem */\n')
|
||||||
|
f.write('typedef struct {\n')
|
||||||
|
f.write(' const char* name;\n')
|
||||||
|
f.write(' const unsigned char* data;\n')
|
||||||
|
f.write(' unsigned int size;\n')
|
||||||
|
f.write('} EmbeddedAsset;\n\n')
|
||||||
|
|
||||||
|
f.write('static const EmbeddedAsset embedded_assets[] = {\n')
|
||||||
|
for idx, input_file in enumerate(input_files):
|
||||||
|
var_name = sanitize_name(input_file)
|
||||||
|
# Extract relative path from 'assets/' onwards if present
|
||||||
|
if 'assets' in input_file.replace('\\', '/'):
|
||||||
|
parts = input_file.replace('\\', '/').split('assets/')
|
||||||
|
if len(parts) > 1:
|
||||||
|
relative_name = 'assets/' + parts[-1]
|
||||||
|
else:
|
||||||
|
relative_name = os.path.basename(input_file)
|
||||||
|
else:
|
||||||
|
relative_name = os.path.basename(input_file)
|
||||||
|
f.write(f' {{ "{relative_name}", embedded_asset_{idx}_{var_name}, embedded_asset_{idx}_{var_name}_len }},\n')
|
||||||
|
f.write('};\n\n')
|
||||||
|
|
||||||
|
f.write(f'static const int embedded_asset_count = {len(input_files)};\n\n')
|
||||||
|
f.write('#endif /* EMBEDDED_ASSETS_H */\n')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print('Usage: python embed_assets.py <output.h> <asset1> [asset2] ...')
|
||||||
|
print(' Embeds images, sounds, fonts, and other asset files into a C header.')
|
||||||
|
print(' Supported: .png, .jpg, .wav, .ogg, .mp3, .ttf, .otf, etc.')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_file = sys.argv[1]
|
||||||
|
input_files = sys.argv[2:]
|
||||||
|
|
||||||
|
# Check all input files exist
|
||||||
|
for f in input_files:
|
||||||
|
if not os.path.exists(f):
|
||||||
|
print(f'Error: File not found: {f}')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
embed_files(output_file, input_files)
|
||||||
|
print(f'Embedded {len(input_files)} asset file(s) into {output_file}')
|
||||||
|
for f in input_files:
|
||||||
|
size = os.path.getsize(f)
|
||||||
|
print(f' - {f} ({size} bytes)')
|
||||||
57
embed_font.py
Normal file
57
embed_font.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Embed font file into C header.
|
||||||
|
Usage: python embed_font.py <output.h> <font.ttf>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def embed_file(file_path, var_name):
|
||||||
|
"""Convert a file to a C byte array"""
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
output = f"/* {os.path.basename(file_path)} */\n"
|
||||||
|
output += f"static const unsigned char {var_name}[] = {{\n"
|
||||||
|
|
||||||
|
# Write bytes in rows of 16
|
||||||
|
for i in range(0, len(data), 16):
|
||||||
|
chunk = data[i:i+16]
|
||||||
|
hex_values = ', '.join(f'0x{b:02x}' for b in chunk)
|
||||||
|
output += f" {hex_values},\n"
|
||||||
|
|
||||||
|
output += "};\n"
|
||||||
|
output += f"static const unsigned int {var_name}_size = {len(data)};\n\n"
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Usage: python embed_font.py <output.h> <font.ttf>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_file = sys.argv[1]
|
||||||
|
font_file = sys.argv[2]
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if not os.path.exists(font_file):
|
||||||
|
print(f"Error: {font_file} not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Generate header content
|
||||||
|
header_content = "/* Auto-generated embedded font file */\n"
|
||||||
|
header_content += "#pragma once\n\n"
|
||||||
|
|
||||||
|
# Embed font file
|
||||||
|
header_content += embed_file(font_file, "embedded_font_data")
|
||||||
|
|
||||||
|
# Write to output file
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(header_content)
|
||||||
|
|
||||||
|
print(f"Generated {output_file}")
|
||||||
|
print(f" - Embedded {font_file} ({os.path.getsize(font_file)} bytes)")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
64
embed_logo.py
Normal file
64
embed_logo.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Embed logo image files into C header for splash screens.
|
||||||
|
Usage: python embed_logo.py <output.h> <raylib_logo.png> <reilua_logo.png>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def embed_file(file_path, var_name):
|
||||||
|
"""Convert a file to a C byte array"""
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
output = f"/* {os.path.basename(file_path)} */\n"
|
||||||
|
output += f"static const unsigned char {var_name}[] = {{\n"
|
||||||
|
|
||||||
|
# Write bytes in rows of 16
|
||||||
|
for i in range(0, len(data), 16):
|
||||||
|
chunk = data[i:i+16]
|
||||||
|
hex_values = ', '.join(f'0x{b:02x}' for b in chunk)
|
||||||
|
output += f" {hex_values},\n"
|
||||||
|
|
||||||
|
output += "};\n"
|
||||||
|
output += f"static const unsigned int {var_name}_size = {len(data)};\n\n"
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print("Usage: python embed_logo.py <output.h> <raylib_logo.png> <reilua_logo.png>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_file = sys.argv[1]
|
||||||
|
raylib_logo = sys.argv[2]
|
||||||
|
reilua_logo = sys.argv[3]
|
||||||
|
|
||||||
|
# Check if files exist
|
||||||
|
if not os.path.exists(raylib_logo):
|
||||||
|
print(f"Error: {raylib_logo} not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not os.path.exists(reilua_logo):
|
||||||
|
print(f"Error: {reilua_logo} not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Generate header content
|
||||||
|
header_content = "/* Auto-generated embedded logo files */\n"
|
||||||
|
header_content += "#pragma once\n\n"
|
||||||
|
|
||||||
|
# Embed both logo files
|
||||||
|
header_content += embed_file(raylib_logo, "embedded_raylib_logo")
|
||||||
|
header_content += embed_file(reilua_logo, "embedded_reilua_logo")
|
||||||
|
|
||||||
|
# Write to output file
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(header_content)
|
||||||
|
|
||||||
|
print(f"Generated {output_file}")
|
||||||
|
print(f" - Embedded {raylib_logo} ({os.path.getsize(raylib_logo)} bytes)")
|
||||||
|
print(f" - Embedded {reilua_logo} ({os.path.getsize(reilua_logo)} bytes)")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
92
embed_lua.py
Normal file
92
embed_lua.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Embed multiple Lua files into a C header file for inclusion in the executable.
|
||||||
|
Usage: python embed_lua.py <output.h> <file1.lua> [file2.lua] [file3.lua] ...
|
||||||
|
|
||||||
|
Embeds all specified Lua files into a C header with a virtual filesystem.
|
||||||
|
The first file is treated as main.lua (entry point).
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def sanitize_name(filename):
|
||||||
|
"""Convert filename to valid C identifier"""
|
||||||
|
name = os.path.basename(filename)
|
||||||
|
name = name.replace('.', '_').replace('-', '_').replace('/', '_').replace('\\', '_')
|
||||||
|
return name
|
||||||
|
|
||||||
|
def embed_files(output_file, input_files):
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write('#ifndef EMBEDDED_MAIN_H\n')
|
||||||
|
f.write('#define EMBEDDED_MAIN_H\n\n')
|
||||||
|
f.write('/* Auto-generated file - do not edit manually */\n\n')
|
||||||
|
|
||||||
|
# Embed each file as a separate array
|
||||||
|
for idx, input_file in enumerate(input_files):
|
||||||
|
with open(input_file, 'rb') as inf:
|
||||||
|
data = inf.read()
|
||||||
|
|
||||||
|
var_name = sanitize_name(input_file)
|
||||||
|
f.write(f'/* Embedded file: {input_file} */\n')
|
||||||
|
f.write(f'static const unsigned char embedded_lua_{idx}_{var_name}[] = {{\n')
|
||||||
|
|
||||||
|
for i, byte in enumerate(data):
|
||||||
|
if i % 12 == 0:
|
||||||
|
f.write(' ')
|
||||||
|
f.write(f'0x{byte:02x}')
|
||||||
|
if i < len(data) - 1:
|
||||||
|
f.write(',')
|
||||||
|
if (i + 1) % 12 == 0:
|
||||||
|
f.write('\n')
|
||||||
|
else:
|
||||||
|
f.write(' ')
|
||||||
|
|
||||||
|
f.write('\n};\n')
|
||||||
|
f.write(f'static const unsigned int embedded_lua_{idx}_{var_name}_len = {len(data)};\n\n')
|
||||||
|
|
||||||
|
# Create the file table
|
||||||
|
f.write('/* File table for virtual filesystem */\n')
|
||||||
|
f.write('typedef struct {\n')
|
||||||
|
f.write(' const char* name;\n')
|
||||||
|
f.write(' const unsigned char* data;\n')
|
||||||
|
f.write(' unsigned int size;\n')
|
||||||
|
f.write('} EmbeddedLuaFile;\n\n')
|
||||||
|
|
||||||
|
f.write('static const EmbeddedLuaFile embedded_lua_files[] = {\n')
|
||||||
|
for idx, input_file in enumerate(input_files):
|
||||||
|
var_name = sanitize_name(input_file)
|
||||||
|
# Store both original filename and basename for require compatibility
|
||||||
|
basename = os.path.basename(input_file)
|
||||||
|
f.write(f' {{ "{basename}", embedded_lua_{idx}_{var_name}, embedded_lua_{idx}_{var_name}_len }},\n')
|
||||||
|
f.write('};\n\n')
|
||||||
|
|
||||||
|
f.write(f'static const int embedded_lua_file_count = {len(input_files)};\n\n')
|
||||||
|
|
||||||
|
# Main entry point (first file)
|
||||||
|
var_name = sanitize_name(input_files[0])
|
||||||
|
f.write('/* Main entry point */\n')
|
||||||
|
f.write(f'#define embedded_main_lua embedded_lua_0_{var_name}\n')
|
||||||
|
f.write(f'#define embedded_main_lua_len embedded_lua_0_{var_name}_len\n\n')
|
||||||
|
|
||||||
|
f.write('#endif /* EMBEDDED_MAIN_H */\n')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print('Usage: python embed_lua.py <output.h> <file1.lua> [file2.lua] ...')
|
||||||
|
print(' The first Lua file is treated as the main entry point.')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_file = sys.argv[1]
|
||||||
|
input_files = sys.argv[2:]
|
||||||
|
|
||||||
|
# Check all input files exist
|
||||||
|
for f in input_files:
|
||||||
|
if not os.path.exists(f):
|
||||||
|
print(f'Error: File not found: {f}')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
embed_files(output_file, input_files)
|
||||||
|
print(f'Embedded {len(input_files)} file(s) into {output_file}')
|
||||||
|
for f in input_files:
|
||||||
|
print(f' - {f}')
|
||||||
|
|
||||||
BIN
fonts/Oleaguid.ttf
Normal file
BIN
fonts/Oleaguid.ttf
Normal file
Binary file not shown.
@@ -140,6 +140,9 @@ int lcoreGetDirectoryPath( lua_State* L );
|
|||||||
int lcoreGetPrevDirectoryPath( lua_State* L );
|
int lcoreGetPrevDirectoryPath( lua_State* L );
|
||||||
int lcoreGetWorkingDirectory( lua_State* L );
|
int lcoreGetWorkingDirectory( lua_State* L );
|
||||||
int lcoreGetApplicationDirectory( lua_State* L );
|
int lcoreGetApplicationDirectory( lua_State* L );
|
||||||
|
int lcoreBeginAssetLoading( lua_State* L );
|
||||||
|
int lcoreUpdateAssetLoading( lua_State* L );
|
||||||
|
int lcoreEndAssetLoading( lua_State* L );
|
||||||
int lcoreMakeDirectory( lua_State* L );
|
int lcoreMakeDirectory( lua_State* L );
|
||||||
int lcoreChangeDirectory( lua_State* L );
|
int lcoreChangeDirectory( lua_State* L );
|
||||||
int lcoreIsPathFile( lua_State* L );
|
int lcoreIsPathFile( lua_State* L );
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void assingGlobalFunction( const char* name, int ( *functionPtr )( lua_State* )
|
|||||||
|
|
||||||
bool luaInit( int argn, const char** argc );
|
bool luaInit( int argn, const char** argc );
|
||||||
int luaTraceback( lua_State* L );
|
int luaTraceback( lua_State* L );
|
||||||
void luaCallMain();
|
bool luaCallMain();
|
||||||
void luaCallInit();
|
void luaCallInit();
|
||||||
void luaCallUpdate();
|
void luaCallUpdate();
|
||||||
void luaCallDraw();
|
void luaCallDraw();
|
||||||
|
|||||||
6
include/splash.h
Normal file
6
include/splash.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void splashInit();
|
||||||
|
bool splashUpdate( float delta );
|
||||||
|
void splashDraw();
|
||||||
|
void splashCleanup();
|
||||||
BIN
logo/raylib_logo.png
Normal file
BIN
logo/raylib_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
logo/reilua_logo.png
Normal file
BIN
logo/reilua_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
61
src/core.c
61
src/core.c
@@ -4,6 +4,14 @@
|
|||||||
#include "textures.h"
|
#include "textures.h"
|
||||||
#include "lua_core.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 ) {
|
static size_t getBufferElementSize( Buffer* buffer ) {
|
||||||
switch ( buffer->type ) {
|
switch ( buffer->type ) {
|
||||||
case BUFFER_UNSIGNED_CHAR: return sizeof( unsigned char );
|
case BUFFER_UNSIGNED_CHAR: return sizeof( unsigned char );
|
||||||
@@ -1955,6 +1963,59 @@ int lcoreGetApplicationDirectory( lua_State* L ) {
|
|||||||
return 1;
|
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 )
|
> success = RL.MakeDirectory( string dirPath )
|
||||||
|
|
||||||
|
|||||||
236
src/lua_core.c
236
src/lua_core.c
@@ -15,6 +15,21 @@
|
|||||||
#include "reasings.h"
|
#include "reasings.h"
|
||||||
#include "bitwiseOp.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
|
#ifdef PLATFORM_DESKTOP
|
||||||
#include "platforms/core_desktop_glfw.c"
|
#include "platforms/core_desktop_glfw.c"
|
||||||
#elif PLATFORM_DESKTOP_SDL2
|
#elif PLATFORM_DESKTOP_SDL2
|
||||||
@@ -25,6 +40,152 @@
|
|||||||
#include "platforms/core_web.c"
|
#include "platforms/core_web.c"
|
||||||
#endif
|
#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. */
|
/* Custom implementation since LuaJIT doesn't have lua_geti. */
|
||||||
static void lua_getiCustom( lua_State* L, int index, int i ) {
|
static void lua_getiCustom( lua_State* L, int index, int i ) {
|
||||||
lua_pushinteger( L, i ); // Push the index onto the stack
|
lua_pushinteger( L, i ); // Push the index onto the stack
|
||||||
@@ -1446,11 +1607,51 @@ int luaTraceback( lua_State* L ) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void luaCallMain() {
|
bool luaCallMain() {
|
||||||
lua_State* L = state->luaState;
|
lua_State* L = state->luaState;
|
||||||
|
|
||||||
char path[ STRING_LEN ] = { '\0' };
|
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. */
|
/* If web, set path to resources folder. */
|
||||||
#ifdef PLATFORM_WEB
|
#ifdef PLATFORM_WEB
|
||||||
snprintf( path, STRING_LEN, "main.lua" );
|
snprintf( path, STRING_LEN, "main.lua" );
|
||||||
@@ -1467,17 +1668,16 @@ void luaCallMain() {
|
|||||||
#endif
|
#endif
|
||||||
if ( !FileExists( path ) ) {
|
if ( !FileExists( path ) ) {
|
||||||
TraceLog( LOG_ERROR, "Cannot find file: %s\n", path );
|
TraceLog( LOG_ERROR, "Cannot find file: %s\n", path );
|
||||||
state->run = false;
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
luaL_dofile( L, path );
|
luaL_dofile( L, path );
|
||||||
|
|
||||||
/* Check errors in main.lua */
|
/* Check errors in main.lua */
|
||||||
if ( lua_tostring( L, -1 ) ) {
|
if ( lua_tostring( L, -1 ) ) {
|
||||||
TraceLog( LOG_ERROR, "Lua error: %s\n", lua_tostring( L, -1 ) );
|
TraceLog( LOG_ERROR, "Lua error: %s\n", lua_tostring( L, -1 ) );
|
||||||
state->run = false;
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
lua_pushcfunction( L, luaTraceback );
|
lua_pushcfunction( L, luaTraceback );
|
||||||
int tracebackidx = lua_gettop( L );
|
int tracebackidx = lua_gettop( L );
|
||||||
/* Apply custom callback here. */
|
/* Apply custom callback here. */
|
||||||
@@ -1489,8 +1689,7 @@ void luaCallMain() {
|
|||||||
if ( lua_isfunction( L, -1 ) ) {
|
if ( lua_isfunction( L, -1 ) ) {
|
||||||
if ( lua_pcall( L, 0, 0, tracebackidx ) != 0 ) {
|
if ( lua_pcall( L, 0, 0, tracebackidx ) != 0 ) {
|
||||||
TraceLog( LOG_ERROR, "Lua error: %s", lua_tostring( L, -1 ) );
|
TraceLog( LOG_ERROR, "Lua error: %s", lua_tostring( L, -1 ) );
|
||||||
state->run = false;
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pop( L, -1 );
|
lua_pop( L, -1 );
|
||||||
@@ -1502,8 +1701,25 @@ void luaCallMain() {
|
|||||||
stateContextInit();
|
stateContextInit();
|
||||||
}
|
}
|
||||||
else {
|
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() {
|
void luaCallInit() {
|
||||||
@@ -1789,6 +2005,10 @@ void luaRegister() {
|
|||||||
assingGlobalFunction( "GetPrevDirectoryPath", lcoreGetPrevDirectoryPath );
|
assingGlobalFunction( "GetPrevDirectoryPath", lcoreGetPrevDirectoryPath );
|
||||||
assingGlobalFunction( "GetWorkingDirectory", lcoreGetWorkingDirectory );
|
assingGlobalFunction( "GetWorkingDirectory", lcoreGetWorkingDirectory );
|
||||||
assingGlobalFunction( "GetApplicationDirectory", lcoreGetApplicationDirectory );
|
assingGlobalFunction( "GetApplicationDirectory", lcoreGetApplicationDirectory );
|
||||||
|
/* Asset loading functions. */
|
||||||
|
assingGlobalFunction( "BeginAssetLoading", lcoreBeginAssetLoading );
|
||||||
|
assingGlobalFunction( "UpdateAssetLoading", lcoreUpdateAssetLoading );
|
||||||
|
assingGlobalFunction( "EndAssetLoading", lcoreEndAssetLoading );
|
||||||
assingGlobalFunction( "MakeDirectory", lcoreMakeDirectory );
|
assingGlobalFunction( "MakeDirectory", lcoreMakeDirectory );
|
||||||
assingGlobalFunction( "ChangeDirectory", lcoreChangeDirectory );
|
assingGlobalFunction( "ChangeDirectory", lcoreChangeDirectory );
|
||||||
assingGlobalFunction( "IsPathFile", lcoreIsPathFile );
|
assingGlobalFunction( "IsPathFile", lcoreIsPathFile );
|
||||||
|
|||||||
114
src/main.c
114
src/main.c
@@ -1,6 +1,15 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "lua_core.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() {
|
static inline void printVersion() {
|
||||||
if ( VERSION_DEV ) {
|
if ( VERSION_DEV ) {
|
||||||
@@ -22,30 +31,92 @@ static inline void printVersion() {
|
|||||||
int main( int argn, const char** argc ) {
|
int main( int argn, const char** argc ) {
|
||||||
char basePath[ STRING_LEN ] = { '\0' };
|
char basePath[ STRING_LEN ] = { '\0' };
|
||||||
bool interpret_mode = false;
|
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 ( 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();
|
printVersion();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ( strcmp( argc[1], "--help" ) == 0 || strcmp( argc[1], "-h" ) == 0 ) {
|
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" );
|
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;
|
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;
|
interpret_mode = true;
|
||||||
|
|
||||||
if ( 2 < argn ) {
|
if ( arg_index + 1 < argn ) {
|
||||||
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[2] );
|
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[arg_index + 1] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else if ( arg_index < argn ) {
|
||||||
sprintf( basePath, "%s/%s", GetWorkingDirectory(), argc[1] );
|
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 {
|
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 ) {
|
if ( interpret_mode ) {
|
||||||
@@ -65,15 +136,30 @@ int main( int argn, const char** argc ) {
|
|||||||
else {
|
else {
|
||||||
printVersion();
|
printVersion();
|
||||||
stateInit( argn, argc, basePath );
|
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 ) {
|
while ( state->run ) {
|
||||||
luaCallUpdate();
|
|
||||||
luaCallDraw();
|
|
||||||
if ( WindowShouldClose() ) {
|
if ( WindowShouldClose() ) {
|
||||||
state->run = false;
|
state->run = false;
|
||||||
}
|
}
|
||||||
|
luaCallUpdate();
|
||||||
|
luaCallDraw();
|
||||||
}
|
}
|
||||||
luaCallExit();
|
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