gw-libretro/gwlua/functions.c
Vladimir Serbinenko 0505a20683 Remove snprintf
2022-04-08 11:40:09 +02:00

634 lines
13 KiB
C

#include <gwlua.h>
#include <rl_rand.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <math.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <bsreader.h>
#include "lua/class.h"
#include "lua/classes.h"
#include "lua/controls.h"
#include "lua/dialogs.h"
#include "lua/extctrls.h"
#include "lua/fmod.h"
#include "lua/fmodtypes.h"
#include "lua/forms.h"
#include "lua/graphics.h"
#include "lua/jpeg.h"
#include "lua/math.h"
#include "lua/messages.h"
#include "lua/registry.h"
#include "lua/stdctrls.h"
#include "lua/sysutils.h"
#include "lua/windows.h"
#include "lua/compatinit.h"
#include "lua/system.h"
#include "png/boxybold_20.h"
#include "png/boxybold_21.h"
#include "png/boxybold_22.h"
#include "png/boxybold_23.h"
#include "png/boxybold_24.h"
#include "png/boxybold_25.h"
#include "png/boxybold_26.h"
#include "png/boxybold_27.h"
#include "png/boxybold_28.h"
#include "png/boxybold_29.h"
#include "png/boxybold_2a.h"
#include "png/boxybold_2b.h"
#include "png/boxybold_2c.h"
#include "png/boxybold_2d.h"
#include "png/boxybold_2e.h"
#include "png/boxybold_2f.h"
#include "png/boxybold_30.h"
#include "png/boxybold_31.h"
#include "png/boxybold_32.h"
#include "png/boxybold_33.h"
#include "png/boxybold_34.h"
#include "png/boxybold_35.h"
#include "png/boxybold_36.h"
#include "png/boxybold_37.h"
#include "png/boxybold_38.h"
#include "png/boxybold_39.h"
#include "png/boxybold_3a.h"
#include "png/boxybold_3b.h"
#include "png/boxybold_3c.h"
#include "png/boxybold_3d.h"
#include "png/boxybold_3e.h"
#include "png/boxybold_3f.h"
#include "png/boxybold_40.h"
#include "png/boxybold_41.h"
#include "png/boxybold_42.h"
#include "png/boxybold_43.h"
#include "png/boxybold_44.h"
#include "png/boxybold_45.h"
#include "png/boxybold_46.h"
#include "png/boxybold_47.h"
#include "png/boxybold_48.h"
#include "png/boxybold_49.h"
#include "png/boxybold_4a.h"
#include "png/boxybold_4b.h"
#include "png/boxybold_4c.h"
#include "png/boxybold_4d.h"
#include "png/boxybold_4e.h"
#include "png/boxybold_4f.h"
#include "png/boxybold_50.h"
#include "png/boxybold_51.h"
#include "png/boxybold_52.h"
#include "png/boxybold_53.h"
#include "png/boxybold_54.h"
#include "png/boxybold_55.h"
#include "png/boxybold_56.h"
#include "png/boxybold_57.h"
#include "png/boxybold_58.h"
#include "png/boxybold_59.h"
#include "png/boxybold_5a.h"
#include "png/boxybold_5b.h"
#include "png/boxybold_5c.h"
#include "png/boxybold_5d.h"
#include "png/boxybold_5e.h"
#include "png/boxybold_5f.h"
#include "png/boxybold_60.h"
#include "png/boxybold_7b.h"
#include "png/boxybold_7c.h"
#include "png/boxybold_7d.h"
#include "png/boxybold_7e.h"
#include "png/hand.h"
#include "png/snes.h"
#define __inline
#include "entries.c"
#undef __inline
#define get_state( L ) ( ( gwlua_t* )lua_touserdata( L, lua_upvalueindex( 1 ) ) )
static int channels[ RL_MAX_VOICES ];
static int logmsg( const char* format, ... )
{
va_list args;
va_start(args, format);
gwlua_vlog( format, args );
va_end(args);
return 0;
}
static void soundstopped( const rl_sound_t* data )
{
channels[ data->ud[ 0 ].i ] = -1;
}
static int l_playsound( lua_State* L )
{
gwlua_sound_t* sound = (gwlua_sound_t*)luaL_checkudata( L, 1, "sound" );
int channel = luaL_checkinteger( L, 2 );
int i;
if ( sound->data == NULL )
{
return luaL_error( L, "sound data not set" );
}
if ( channel == -1 )
{
for ( i = 0; i < sizeof( channels ) / sizeof( channels[ 0 ] ); i++ )
{
if ( channels[ i ] == -1 )
{
channel = i;
break;
}
}
if ( channel == -1 )
{
return 0;
}
}
else if ( channels[ channel ] != -1 )
{
rl_sound_stop( channels[ channel ] );
}
channels[ channel ] = rl_sound_play( sound->data, sound->loop, soundstopped );
sound->data->ud[ 0 ].i = channel;
return 0;
}
static int l_stopsounds( lua_State* L )
{
int channel = luaL_checkinteger( L, 1 );
if ( channel == -1 )
{
rl_sound_stop_all();
}
else if ( channels[ channel ] != -1 )
{
rl_sound_stop( channels[ channel ] );
}
return 0;
}
static int l_pausesounds( lua_State* L )
{
rl_sound_pause();
return 0;
}
static int l_resumesounds( lua_State* L )
{
rl_sound_resume();
return 0;
}
static int l_issoundactive( lua_State* L )
{
lua_pushboolean( L, rl_sound_is_active() );
return 1;
}
static int l_randomize( lua_State* L )
{
rl_srand( time( NULL ) );
return 0;
}
static int l_random( lua_State* L )
{
if ( lua_isnumber( L, 1 ) )
{
lua_pushinteger( L, rl_random( 0, lua_tointeger( L, 1 ) - 1 ) );
}
else
{
lua_pushnumber( L, rl_rand() / 4294967296.0 );
}
return 1;
}
static int l_round( lua_State* L )
{
double x = luaL_checknumber( L, 1 );
double f = floor( x );
double c = ceil( x );
double d1 = x - f;
double d2 = c - x;
/* TODO: is this behavior present in a built-in function? */
if ( d1 < d2 )
{
lua_pushnumber( L, f );
}
else if ( d1 > d2 )
{
lua_pushnumber( L, c );
}
else
{
if ( 1 & (int64_t)f )
{
lua_pushnumber( L, c );
}
else
{
lua_pushnumber( L, f );
}
}
return 1;
}
static int l_now( lua_State* L )
{
lua_pushinteger( L, time( NULL ) );
return 1;
}
static int l_splittime( lua_State* L )
{
time_t tt = (time_t)luaL_checkinteger( L, 1 );
struct tm* tm = localtime( &tt );
lua_pushinteger( L, tm->tm_hour );
lua_pushinteger( L, tm->tm_min );
lua_pushinteger( L, tm->tm_sec );
lua_pushinteger( L, 0 );
lua_pushinteger( L, tm->tm_mday );
lua_pushinteger( L, tm->tm_mon + 1 );
lua_pushinteger( L, tm->tm_year + 1900 );
return 7;
}
static int l_inttostr( lua_State* L )
{
lua_tostring( L, 1 );
lua_pushvalue( L, 1 );
return 1;
}
static int l_loadvalue( lua_State* L )
{
gwlua_t* state = get_state( L );
const char* key = luaL_checkstring( L, 1 );
int type;
const char* value = gwlua_load_value( state, key, &type );
if ( value )
{
switch ( type )
{
case GWLUA_NULL:
default:
lua_pushnil( L );
break;
case GWLUA_BOOLEAN:
lua_pushboolean( L, !strcmp( value, "true" ) );
break;
case GWLUA_NUMBER:
if ( !lua_stringtonumber( L, value ) )
{
lua_pushinteger( L, 0 );
}
break;
case GWLUA_STRING:
lua_pushstring( L, value );
break;
}
}
else
{
lua_pushnil( L );
}
return 1;
}
static int l_savevalue( lua_State* L )
{
gwlua_t* state = get_state( L );
const char* key = luaL_checkstring( L, 1 );
switch ( lua_type( L, 2 ) )
{
case LUA_TBOOLEAN:
gwlua_save_value( state, key, lua_toboolean( L, 2 ) ? "true" : "false", GWLUA_BOOLEAN );
break;
case LUA_TNUMBER:
gwlua_save_value( state, key, lua_tostring( L, 2 ), GWLUA_NUMBER );
break;
case LUA_TSTRING:
gwlua_save_value( state, key, lua_tostring( L, 2 ), GWLUA_STRING );
break;
default:
gwlua_save_value( state, key, NULL, GWLUA_NULL );
break;
}
return 1;
}
#define MAX( a, b ) ( a > b ? a : b )
static int l_setbackground( lua_State* L )
{
gwlua_t* state = get_state( L );
rl_image_t*** picture = (rl_image_t***)luaL_checkudata( L, 1, "picture" );
rl_image_t* bg = **picture;
int width = MAX( bg->width, 480 );
int x0;
if ( rl_backgrnd_create( width, bg->height ) )
{
return luaL_error( L, "out of memory allocating the background framebuffer" );
}
x0 = ( width - bg->width ) / 2;
state->screen = rl_backgrnd_fb( &state->width, &state->height );
rl_backgrnd_clear( 0 );
rl_image_blit_nobg( bg, x0, 0 );
rl_sprites_translate( x0, 0 );
gwlua_set_fb( state->width, state->height );
return 0;
}
static int l_setzoom( lua_State* L )
{
gwlua_t* state = get_state( L );
if ( lua_type( L, 1 ) == LUA_TTABLE )
{
lua_geti( L, 1, 1 );
state->zoom.x0 = luaL_checkinteger( L, -1 );
lua_geti( L, 1, 2 );
state->zoom.y0 = luaL_checkinteger( L, -1 );
lua_geti( L, 1, 3 );
state->zoom.w = luaL_checkinteger( L, -1 );
lua_geti( L, 1, 4 );
state->zoom.h = luaL_checkinteger( L, -1 );
}
else
{
state->zoom.x0 = state->zoom.y0 = state->zoom.w = state->zoom.h = -1;
}
gwlua_zoom( state, state->zoom.x0, state->zoom.y0, state->zoom.w, state->zoom.h );
return 0;
}
static int l_iszoomed( lua_State* L )
{
gwlua_t* state = get_state( L );
lua_pushboolean( L, state->zoom.x0 != -1 );
return 1;
}
static const char* button_name( int button )
{
switch ( button )
{
case GWLUA_UP: return "up";
case GWLUA_DOWN: return "down";
case GWLUA_LEFT: return "left";
case GWLUA_RIGHT: return "right";
case GWLUA_A: return "a";
case GWLUA_B: return "b";
case GWLUA_X: return "x";
case GWLUA_Y: return "y";
case GWLUA_L1: return "l1";
case GWLUA_R1: return "r1";
case GWLUA_L2: return "l2";
case GWLUA_R2: return "r2";
case GWLUA_L3: return "l3";
case GWLUA_R3: return "r3";
case GWLUA_SELECT: return "select";
case GWLUA_START: return "start";
default: return "?";
}
}
static int l_inputstate( lua_State* L )
{
gwlua_t* state = get_state( L );
char name[ 32 ];
int i, p;
if ( lua_type( L, 1 ) == LUA_TTABLE )
{
lua_pushvalue( L, 1 );
}
else
{
lua_createtable( L, 0, 37 );
}
for ( p = 0; p < 2; p++ )
{
for ( i = 1; i < sizeof( state->input[ 0 ] ) / sizeof( state->input[ 0 ][ 0 ] ); i++ )
{
name[sizeof( name ) - 1] = '\0';
strncpy(name, button_name( i ), sizeof( name ) - 1);
if (p != 0)
strncat (name, "/2", sizeof( name ) - (strlen(name) + 1));
lua_pushboolean( L, state->input[ p ][ i ] );
lua_setfield( L, -2, name );
}
}
if ( state->zoom.x0 == -1 )
{
lua_pushinteger( L, ( state->pointer.x + 32767 ) * state->width / 65534 );
lua_setfield( L, -2, "pointer_x" );
lua_pushinteger( L, ( state->pointer.y + 32767 ) * state->height / 65534 );
lua_setfield( L, -2, "pointer_y" );
}
else
{
lua_pushinteger( L, state->zoom.x0 + ( state->pointer.x + 32767 ) * state->zoom.w / 65534 );
lua_setfield( L, -2, "pointer_x" );
lua_pushinteger( L, state->zoom.y0 + ( state->pointer.y + 32767 ) * state->zoom.h / 65534 );
lua_setfield( L, -2, "pointer_y" );
}
lua_pushboolean( L, state->pointer.pressed );
lua_setfield( L, -2, "pointer_pressed" );
return 1;
}
static int l_loadbin( lua_State* L )
{
gwlua_t* state = get_state( L );
size_t len;
const char* name = luaL_checklstring( L, 1, &len );
const struct binary_t* found = in_word_set( name, len );
gwrom_entry_t entry;
if ( found )
{
entry.data = (void*)found->data;
entry.size = found->size;
}
else
{
if ( gwrom_find( &entry, state->rom, name ) != GWROM_OK )
{
return 0;
}
}
lua_pushlstring( L, (char*)entry.data, entry.size );
return 1;
}
static int l_bsread( lua_State* L )
{
void* bs = lua_touserdata( L, lua_upvalueindex( 1 ) );
const char* string;
size_t size;
string = bsread( L, bs, &size );
if ( string )
{
lua_pushlstring( L, string, size );
return 1;
}
free( bs );
return 0;
}
static int l_loadbs( lua_State* L )
{
gwlua_t* state = get_state( L );
const char* name = luaL_checkstring( L, 1 );
gwrom_entry_t entry;
if ( gwrom_find( &entry, state->rom, name ) == GWROM_OK )
{
void* bs = bsnew( entry.data );
if ( bs )
{
lua_pushlightuserdata( L, bs );
lua_pushcclosure( L, l_bsread, 1 );
return 1;
}
}
return 0;
}
static int l_log( lua_State* L )
{
return logmsg( "%s\n", luaL_optstring( L, 1, "" ) );
}
void register_image( lua_State* L, gwlua_t* state );
void register_sound( lua_State* L, gwlua_t* state );
void register_timer( lua_State* L, gwlua_t* state );
extern const char* gw_version;
extern const char* gw_githash;
void register_functions( lua_State* L, gwlua_t* state )
{
static const luaL_Reg statics[] =
{
{ "playsound", l_playsound },
{ "stopsounds", l_stopsounds },
{ "pausesounds", l_pausesounds },
{ "resumesounds", l_resumesounds },
{ "issoundactive", l_issoundactive },
{ "randomize", l_randomize },
{ "random", l_random },
{ "round", l_round },
{ "now", l_now },
{ "splittime", l_splittime },
{ "inttostr", l_inttostr },
{ "loadvalue", l_loadvalue },
{ "savevalue", l_savevalue },
{ "setbackground", l_setbackground },
{ "setzoom", l_setzoom },
{ "iszoomed", l_iszoomed },
{ "inputstate", l_inputstate },
{ "loadbin", l_loadbin },
{ "loadbs", l_loadbs },
{ "log", l_log },
{ NULL, NULL }
};
int i;
lua_newtable( L );
register_image( L, state );
register_sound( L, state );
register_timer( L, state );
lua_pushlightuserdata( L, (void*)state );
luaL_setfuncs( L, statics, 1 );
lua_pushstring( L, gw_version );
lua_setfield( L, -2, "GW_VERSIONSTR" );
lua_pushstring( L, gw_githash );
lua_setfield( L, -2, "GW_GITHASH" );
// module
if ( luaL_loadbufferx( L, (const char*)gwlua_lua_system_lua, gwlua_lua_system_lua_len, "system.lua", "t" ) != LUA_OK )
{
lua_error( L );
return;
}
// module chunk
lua_call( L, 0, 1 );
// module function
lua_pushvalue( L, -2 );
// module function module
lua_call( L, 1, 0 );
// module
lua_setglobal( L, "system" );
// --
for ( i = 0; i < sizeof( channels ) / sizeof( channels[ 0 ] ); i++)
{
channels[ i ] = -1;
}
}