2022-04-26 22:32:54 +00:00
# include "api.h"
# include "graphics/graphics.h"
# include "data/blob.h"
# include "util.h"
# include <stdlib.h>
# include <string.h>
2022-04-27 07:28:39 +00:00
static const uint32_t vectorComponents [ MAX_VECTOR_TYPES ] = {
[ V_VEC2 ] = 2 ,
[ V_VEC3 ] = 3 ,
[ V_VEC4 ] = 4 ,
2022-04-30 22:58:09 +00:00
[ V_QUAT ] = 4 ,
2022-04-27 07:28:39 +00:00
[ V_MAT4 ] = 16
} ;
2023-01-16 13:15:13 +00:00
Buffer * luax_checkbuffer ( lua_State * L , int index ) {
Buffer * buffer = luax_checktype ( L , index , Buffer ) ;
lovrCheck ( lovrBufferIsValid ( buffer ) , " Buffers created with getBuffer can only be used for a single frame (unable to use this Buffer again because lovr.graphics.submit has been called since it was created) " ) ;
return buffer ;
}
2022-04-27 07:28:39 +00:00
static const uint32_t fieldComponents [ ] = {
2023-06-24 02:11:30 +00:00
[ TYPE_I8x4 ] = 4 ,
[ TYPE_U8x4 ] = 4 ,
[ TYPE_SN8x4 ] = 4 ,
[ TYPE_UN8x4 ] = 4 ,
[ TYPE_UN10x3 ] = 3 ,
[ TYPE_I16 ] = 1 ,
[ TYPE_I16x2 ] = 2 ,
[ TYPE_I16x4 ] = 4 ,
[ TYPE_U16 ] = 1 ,
[ TYPE_U16x2 ] = 2 ,
[ TYPE_U16x4 ] = 4 ,
[ TYPE_SN16x2 ] = 2 ,
[ TYPE_SN16x4 ] = 4 ,
[ TYPE_UN16x2 ] = 2 ,
[ TYPE_UN16x4 ] = 4 ,
[ TYPE_I32 ] = 1 ,
[ TYPE_I32x2 ] = 2 ,
[ TYPE_I32x3 ] = 3 ,
[ TYPE_I32x4 ] = 4 ,
[ TYPE_U32 ] = 1 ,
[ TYPE_U32x2 ] = 2 ,
[ TYPE_U32x3 ] = 3 ,
[ TYPE_U32x4 ] = 4 ,
[ TYPE_F16x2 ] = 2 ,
[ TYPE_F16x4 ] = 4 ,
[ TYPE_F32 ] = 1 ,
[ TYPE_F32x2 ] = 2 ,
[ TYPE_F32x3 ] = 3 ,
[ TYPE_F32x4 ] = 4 ,
[ TYPE_MAT2 ] = 4 ,
[ TYPE_MAT3 ] = 9 ,
[ TYPE_MAT4 ] = 16 ,
[ TYPE_INDEX16 ] = 1 ,
[ TYPE_INDEX32 ] = 1
2022-04-27 07:28:39 +00:00
} ;
typedef union {
void * raw ;
int8_t * i8 ;
uint8_t * u8 ;
int16_t * i16 ;
uint16_t * u16 ;
int32_t * i32 ;
uint32_t * u32 ;
float * f32 ;
} FieldPointer ;
2023-06-24 02:11:30 +00:00
static void luax_tofield ( lua_State * L , int index , DataType type , void * data ) {
2022-04-27 07:28:39 +00:00
FieldPointer p = { . raw = data } ;
if ( lua_isuserdata ( L , index ) ) {
VectorType vectorType ;
float * v = luax_tovector ( L , index , & vectorType ) ;
2023-01-16 13:15:13 +00:00
lovrCheck ( vectorComponents [ vectorType ] = = fieldComponents [ type ] , " Vector type is incompatible with field type (expected %d components, got %d) " , fieldComponents [ type ] , vectorComponents [ vectorType ] ) ;
2022-04-27 07:28:39 +00:00
switch ( type ) {
2023-06-24 02:11:30 +00:00
case TYPE_I8x4 : for ( int i = 0 ; i < 4 ; i + + ) p . i8 [ i ] = ( int8_t ) v [ i ] ; break ;
case TYPE_U8x4 : for ( int i = 0 ; i < 4 ; i + + ) p . u8 [ i ] = ( uint8_t ) v [ i ] ; break ;
case TYPE_SN8x4 : for ( int i = 0 ; i < 4 ; i + + ) p . i8 [ i ] = ( int8_t ) CLAMP ( v [ i ] , - 1.f , 1.f ) * INT8_MAX ; break ;
case TYPE_UN8x4 : for ( int i = 0 ; i < 4 ; i + + ) p . u8 [ i ] = ( uint8_t ) CLAMP ( v [ i ] , 0.f , 1.f ) * UINT8_MAX ; break ;
case TYPE_UN10x3 : for ( int i = 0 ; i < 3 ; i + + ) p . u32 [ 0 ] | = ( uint32_t ) ( CLAMP ( v [ i ] , 0.f , 1.f ) * 1023.f ) < < ( 10 * ( 2 - i ) ) ; break ;
case TYPE_I16x2 : for ( int i = 0 ; i < 2 ; i + + ) p . i16 [ i ] = ( int16_t ) v [ i ] ; break ;
case TYPE_I16x4 : for ( int i = 0 ; i < 4 ; i + + ) p . i16 [ i ] = ( int16_t ) v [ i ] ; break ;
case TYPE_U16x2 : for ( int i = 0 ; i < 2 ; i + + ) p . u16 [ i ] = ( uint16_t ) v [ i ] ; break ;
case TYPE_U16x4 : for ( int i = 0 ; i < 4 ; i + + ) p . u16 [ i ] = ( uint16_t ) v [ i ] ; break ;
case TYPE_SN16x2 : for ( int i = 0 ; i < 2 ; i + + ) p . i16 [ i ] = ( int16_t ) CLAMP ( v [ i ] , - 1.f , 1.f ) * INT16_MAX ; break ;
case TYPE_SN16x4 : for ( int i = 0 ; i < 4 ; i + + ) p . i16 [ i ] = ( int16_t ) CLAMP ( v [ i ] , - 1.f , 1.f ) * INT16_MAX ; break ;
case TYPE_UN16x2 : for ( int i = 0 ; i < 2 ; i + + ) p . u16 [ i ] = ( uint16_t ) CLAMP ( v [ i ] , 0.f , 1.f ) * UINT16_MAX ; break ;
case TYPE_UN16x4 : for ( int i = 0 ; i < 4 ; i + + ) p . u16 [ i ] = ( uint16_t ) CLAMP ( v [ i ] , 0.f , 1.f ) * UINT16_MAX ; break ;
case TYPE_I32x2 : for ( int i = 0 ; i < 2 ; i + + ) p . i32 [ i ] = ( int32_t ) v [ i ] ; break ;
case TYPE_I32x3 : for ( int i = 0 ; i < 3 ; i + + ) p . i32 [ i ] = ( int32_t ) v [ i ] ; break ;
case TYPE_I32x4 : for ( int i = 0 ; i < 4 ; i + + ) p . i32 [ i ] = ( int32_t ) v [ i ] ; break ;
case TYPE_U32x2 : for ( int i = 0 ; i < 2 ; i + + ) p . u32 [ i ] = ( uint32_t ) v [ i ] ; break ;
case TYPE_U32x3 : for ( int i = 0 ; i < 3 ; i + + ) p . u32 [ i ] = ( uint32_t ) v [ i ] ; break ;
case TYPE_U32x4 : for ( int i = 0 ; i < 4 ; i + + ) p . u32 [ i ] = ( uint32_t ) v [ i ] ; break ;
case TYPE_F16x2 : for ( int i = 0 ; i < 2 ; i + + ) p . u16 [ i ] = float32to16 ( v [ i ] ) ; break ;
case TYPE_F16x4 : for ( int i = 0 ; i < 4 ; i + + ) p . u16 [ i ] = float32to16 ( v [ i ] ) ; break ;
case TYPE_F32x2 : memcpy ( data , v , 2 * sizeof ( float ) ) ; break ;
case TYPE_F32x3 : memcpy ( data , v , 3 * sizeof ( float ) ) ; break ;
case TYPE_F32x4 : memcpy ( data , v , 4 * sizeof ( float ) ) ; break ;
case TYPE_MAT4 : memcpy ( data , v , 16 * sizeof ( float ) ) ; break ;
2022-04-27 07:28:39 +00:00
default : lovrUnreachable ( ) ;
}
} else {
for ( uint32_t i = 0 ; i < fieldComponents [ type ] ; i + + ) {
double x = lua_tonumber ( L , index + i ) ;
switch ( type ) {
2023-06-24 02:11:30 +00:00
case TYPE_I8x4 : p . i8 [ i ] = ( int8_t ) x ; break ;
case TYPE_U8x4 : p . u8 [ i ] = ( uint8_t ) x ; break ;
case TYPE_SN8x4 : p . i8 [ i ] = ( int8_t ) CLAMP ( x , - 1.f , 1.f ) * INT8_MAX ; break ;
case TYPE_UN8x4 : p . u8 [ i ] = ( uint8_t ) CLAMP ( x , 0.f , 1.f ) * UINT8_MAX ; break ;
case TYPE_UN10x3 : p . u32 [ 0 ] | = ( uint32_t ) ( CLAMP ( x , 0.f , 1.f ) * 1023.f ) < < ( 10 * ( 2 - i ) ) ; break ;
case TYPE_I16 : p . i16 [ i ] = ( int16_t ) x ; break ;
case TYPE_I16x2 : p . i16 [ i ] = ( int16_t ) x ; break ;
case TYPE_I16x4 : p . i16 [ i ] = ( int16_t ) x ; break ;
case TYPE_U16 : p . u16 [ i ] = ( uint16_t ) x ; break ;
case TYPE_U16x2 : p . u16 [ i ] = ( uint16_t ) x ; break ;
case TYPE_U16x4 : p . u16 [ i ] = ( uint16_t ) x ; break ;
case TYPE_SN16x2 : p . i16 [ i ] = ( int16_t ) CLAMP ( x , - 1.f , 1.f ) * INT16_MAX ; break ;
case TYPE_SN16x4 : p . i16 [ i ] = ( int16_t ) CLAMP ( x , - 1.f , 1.f ) * INT16_MAX ; break ;
case TYPE_UN16x2 : p . u16 [ i ] = ( uint16_t ) CLAMP ( x , 0.f , 1.f ) * UINT16_MAX ; break ;
case TYPE_UN16x4 : p . u16 [ i ] = ( uint16_t ) CLAMP ( x , 0.f , 1.f ) * UINT16_MAX ; break ;
case TYPE_I32 : p . i32 [ i ] = ( int32_t ) x ; break ;
case TYPE_I32x2 : p . i32 [ i ] = ( int32_t ) x ; break ;
case TYPE_I32x3 : p . i32 [ i ] = ( int32_t ) x ; break ;
case TYPE_I32x4 : p . i32 [ i ] = ( int32_t ) x ; break ;
case TYPE_U32 : p . u32 [ i ] = ( uint32_t ) x ; break ;
case TYPE_U32x2 : p . u32 [ i ] = ( uint32_t ) x ; break ;
case TYPE_U32x3 : p . u32 [ i ] = ( uint32_t ) x ; break ;
case TYPE_U32x4 : p . i32 [ i ] = ( uint32_t ) x ; break ;
case TYPE_F16x2 : p . u16 [ i ] = float32to16 ( x ) ; break ;
case TYPE_F16x4 : p . u16 [ i ] = float32to16 ( x ) ; break ;
case TYPE_F32 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_F32x2 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_F32x3 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_F32x4 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_MAT2 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_MAT3 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_MAT4 : p . f32 [ i ] = ( float ) x ; break ;
case TYPE_INDEX16 : p . u16 [ i ] = ( uint16_t ) x - 1 ; break ;
case TYPE_INDEX32 : p . u32 [ i ] = ( uint32_t ) x - 1 ; break ;
2022-04-27 07:28:39 +00:00
default : lovrUnreachable ( ) ;
}
}
}
}
2023-04-29 20:34:20 +00:00
static void luax_checkstruct ( lua_State * L , int index , const BufferField * field , char * data ) {
2023-01-16 13:15:13 +00:00
lovrCheck ( lua_istable ( L , index ) , " Expected table for struct data " ) ;
2023-05-26 23:47:58 +00:00
index = index > 0 ? index : lua_gettop ( L ) + 1 + index ;
2022-04-27 07:28:39 +00:00
2023-01-16 13:15:13 +00:00
if ( ! field - > children [ 0 ] . name | | luax_len ( L , index ) > 0 ) {
for ( uint32_t i = 0 , j = 1 ; i < field - > childCount ; i + + ) {
const BufferField * child = & field - > children [ i ] ;
2023-04-30 06:02:37 +00:00
int n = 1 ;
2022-04-27 07:28:39 +00:00
2023-01-16 13:15:13 +00:00
lua_rawgeti ( L , index , j ) ;
if ( child - > length = = 0 & & child - > childCount = = 0 & & lua_type ( L , - 1 ) = = LUA_TNUMBER ) {
for ( uint32_t c = fieldComponents [ child - > type ] ; c > 1 ; c - - , n + + ) {
lua_rawgeti ( L , index , j + n ) ;
}
}
2023-03-01 23:15:04 +00:00
2023-04-30 01:25:58 +00:00
luax_checkbufferdata ( L , - n , child , data + child - > offset ) ;
2023-01-16 13:15:13 +00:00
lua_pop ( L , n ) ;
j + = n ;
}
} else {
for ( uint32_t i = 0 ; i < field - > childCount ; i + + ) {
const BufferField * child = & field - > children [ i ] ;
lua_pushstring ( L , child - > name ) ;
lua_rawget ( L , index ) ;
2023-04-30 01:25:58 +00:00
luax_checkbufferdata ( L , - 1 , child , data + child - > offset ) ;
2023-01-16 13:15:13 +00:00
lua_pop ( L , 1 ) ;
}
}
}
2023-03-01 23:15:04 +00:00
2023-04-29 20:34:20 +00:00
static void luax_checkarray ( lua_State * L , int index , uint32_t offset , uint32_t count , const BufferField * field , char * data ) {
2023-01-16 13:15:13 +00:00
lovrCheck ( lua_istable ( L , index ) , " Expected table for array data " ) ;
if ( field - > childCount > 0 ) {
for ( uint32_t i = 0 ; i < count ; i + + , data + = field - > stride ) {
lua_rawgeti ( L , index , i + offset + 1 ) ;
2023-04-29 20:34:20 +00:00
luax_checkstruct ( L , - 1 , field , data ) ;
2022-04-27 07:28:39 +00:00
lua_pop ( L , 1 ) ;
}
} else {
2023-01-16 13:15:13 +00:00
int n = fieldComponents [ field - > type ] ;
2023-04-30 01:25:58 +00:00
lua_rawgeti ( L , index , 1 ) ;
int type = lua_type ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
2023-02-06 05:44:30 +00:00
if ( type = = LUA_TUSERDATA | | type = = LUA_TLIGHTUSERDATA ) {
2023-01-16 13:15:13 +00:00
for ( uint32_t i = 0 ; i < count ; i + + , data + = field - > stride ) {
lua_rawgeti ( L , index , i + offset + 1 ) ;
lovrCheck ( lua_isuserdata ( L , - 1 ) , " Expected vector object for array value (arrays must use the same type for all elements) " ) ;
2023-04-29 20:34:20 +00:00
luax_tofield ( L , - 1 , field - > type , data ) ;
2023-01-16 13:15:13 +00:00
lua_pop ( L , 1 ) ;
}
} else if ( type = = LUA_TNUMBER ) {
for ( uint32_t i = 0 ; i < count ; i + + , data + = field - > stride ) {
for ( int c = 1 ; c < = n ; c + + ) {
lua_rawgeti ( L , index , i * n + offset + c ) ;
2022-04-27 07:28:39 +00:00
}
2023-04-29 20:34:20 +00:00
luax_tofield ( L , - n , field - > type , data ) ;
2022-04-27 07:28:39 +00:00
lua_pop ( L , n ) ;
}
2023-01-16 13:15:13 +00:00
} else if ( type = = LUA_TTABLE ) {
for ( uint32_t i = 0 ; i < count ; i + + , data + = field - > stride ) {
lua_rawgeti ( L , index , i + offset + 1 ) ;
lovrCheck ( lua_istable ( L , - 1 ) , " Expected nested table for array value (arrays must use the same type for all elements) " ) ;
for ( int c = 1 , j = - 1 ; c < = n ; c + + , j - - ) {
lua_rawgeti ( L , j , c ) ;
}
2023-04-29 20:34:20 +00:00
luax_tofield ( L , - n , field - > type , data ) ;
2023-01-16 13:15:13 +00:00
lua_pop ( L , n + 1 ) ;
}
} else {
lovrThrow ( " Expected number, table, or vector for array contents " ) ;
2022-04-27 07:28:39 +00:00
}
}
}
2023-04-30 01:25:58 +00:00
void luax_checkbufferdata ( lua_State * L , int index , const BufferField * field , char * data ) {
2023-01-16 13:15:13 +00:00
if ( field - > length > 0 ) {
2023-04-30 01:25:58 +00:00
luax_checkarray ( L , index , 0 , field - > length , field , data ) ;
2023-01-16 13:15:13 +00:00
} else if ( field - > childCount > 0 ) {
2023-04-29 20:34:20 +00:00
luax_checkstruct ( L , index , field , data ) ;
2023-01-16 13:15:13 +00:00
} else if ( lua_type ( L , index ) = = LUA_TTABLE ) {
int n = fieldComponents [ field - > type ] ;
for ( int c = 0 ; c < n ; c + + ) {
lua_rawgeti ( L , index < 0 ? index - c : index , c + 1 ) ;
}
2023-04-29 20:34:20 +00:00
luax_tofield ( L , - n , field - > type , data ) ;
2023-01-16 13:15:13 +00:00
lua_pop ( L , n ) ;
} else {
2023-04-29 20:34:20 +00:00
luax_tofield ( L , index , field - > type , data ) ;
2023-01-16 13:15:13 +00:00
}
}
2023-04-30 01:25:58 +00:00
static int luax_pushcomponents ( lua_State * L , const BufferField * field , char * data ) {
FieldPointer p = { . raw = data } ;
int n = ( int ) fieldComponents [ field - > type ] ;
switch ( field - > type ) {
2023-06-24 02:11:30 +00:00
case TYPE_I8x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . i8 [ i ] ) ; return n ;
case TYPE_U8x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . u8 [ i ] ) ; return n ;
case TYPE_SN8x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , MAX ( ( float ) p . i8 [ i ] / 127 , - 1.f ) ) ; return n ;
case TYPE_UN8x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , ( float ) p . u8 [ i ] / 255 ) ; return n ;
case TYPE_UN10x3 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , ( float ) ( ( p . u32 [ 0 ] > > ( 10 * ( 2 - i ) ) ) & 0x3ff ) / 1023.f ) ; return n ;
case TYPE_I16x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . i16 [ i ] ) ; return n ;
case TYPE_I16x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . i16 [ i ] ) ; return n ;
case TYPE_U16x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . u16 [ i ] ) ; return n ;
case TYPE_U16x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . u16 [ i ] ) ; return n ;
case TYPE_SN16x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , MAX ( ( float ) p . i16 [ i ] / 32767 , - 1.f ) ) ; return n ;
case TYPE_SN16x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , MAX ( ( float ) p . i16 [ i ] / 32767 , - 1.f ) ) ; return n ;
case TYPE_UN16x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , ( float ) p . u16 [ i ] / 65535 ) ; return n ;
case TYPE_UN16x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , ( float ) p . u16 [ i ] / 65535 ) ; return n ;
case TYPE_I32 : lua_pushinteger ( L , p . i32 [ 0 ] ) ; return n ;
case TYPE_I32x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . i32 [ i ] ) ; return n ;
case TYPE_I32x3 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . i32 [ i ] ) ; return n ;
case TYPE_I32x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . i32 [ i ] ) ; return n ;
case TYPE_U32 : lua_pushinteger ( L , p . u32 [ 0 ] ) ; return n ;
case TYPE_U32x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . u32 [ i ] ) ; return n ;
case TYPE_U32x3 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . u32 [ i ] ) ; return n ;
case TYPE_U32x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushinteger ( L , p . u32 [ i ] ) ; return n ;
case TYPE_F16x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , float16to32 ( p . u16 [ i ] ) ) ; return n ;
case TYPE_F16x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , float16to32 ( p . u16 [ i ] ) ) ; return n ;
case TYPE_F32 : lua_pushnumber ( L , p . f32 [ 0 ] ) ; return n ;
case TYPE_F32x2 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , p . f32 [ i ] ) ; return n ;
case TYPE_F32x3 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , p . f32 [ i ] ) ; return n ;
case TYPE_F32x4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , p . f32 [ i ] ) ; return n ;
case TYPE_MAT2 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , p . f32 [ i ] ) ; return n ;
case TYPE_MAT3 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , p . f32 [ i ] ) ; return n ;
case TYPE_MAT4 : for ( int i = 0 ; i < n ; i + + ) lua_pushnumber ( L , p . f32 [ i ] ) ; return n ;
case TYPE_INDEX16 : lua_pushinteger ( L , p . u16 [ 0 ] + 1 ) ; return n ;
case TYPE_INDEX32 : lua_pushinteger ( L , p . u32 [ 0 ] + 1 ) ; return n ;
2023-04-30 01:25:58 +00:00
default : lovrUnreachable ( ) ; return 0 ;
2023-01-16 13:15:13 +00:00
}
2023-04-30 01:25:58 +00:00
}
2023-01-16 13:15:13 +00:00
2023-04-30 01:25:58 +00:00
static int luax_pushstruct ( lua_State * L , const BufferField * field , char * data ) {
lua_createtable ( L , 0 , field - > childCount ) ;
for ( uint32_t i = 0 ; i < field - > childCount ; i + + ) {
if ( field - > childCount > 0 | | field - > length > 0 | | fieldComponents [ field - > type ] = = 1 ) {
luax_pushbufferdata ( L , & field - > children [ i ] , data + field - > children [ i ] . offset ) ;
} else {
int n = fieldComponents [ field - > type ] ;
lua_createtable ( L , n , 0 ) ;
luax_pushbufferdata ( L , & field - > children [ i ] , data + field - > children [ i ] . offset ) ;
for ( int j = n + 1 , k = n ; k > = 1 ; k + + , j - - ) {
lua_rawseti ( L , - j , k ) ;
}
}
lua_setfield ( L , - 2 , field - > children [ i ] . name ) ;
}
return 1 ;
}
2023-01-16 13:15:13 +00:00
2023-04-30 01:25:58 +00:00
int luax_pushbufferdata ( lua_State * L , const BufferField * field , char * data ) {
if ( field - > length > 0 ) {
lua_createtable ( L , field - > length , 0 ) ;
if ( field - > childCount > 0 ) {
for ( uint32_t i = 0 ; i < field - > length ; i + + ) {
luax_pushstruct ( L , & field - > children [ i ] , data ) ;
lua_rawseti ( L , - 2 , i + 1 ) ;
data + = field - > stride ;
}
} else {
for ( uint32_t i = 0 ; i < field - > length ; i + + ) {
int n = ( int ) fieldComponents [ field - > type ] ;
if ( n > 1 ) {
lua_createtable ( L , n , 0 ) ;
luax_pushcomponents ( L , field , data ) ;
for ( int j = n + 1 , k = n ; k > = 1 ; k - - , j - - ) {
lua_rawseti ( L , - j , k ) ;
}
} else {
luax_pushcomponents ( L , field , data ) ;
}
lua_rawseti ( L , - 2 , i + 1 ) ;
data + = field - > stride ;
}
}
return 1 ;
} else if ( field - > childCount > 0 ) {
return luax_pushstruct ( L , field , data ) ;
2023-01-16 13:15:13 +00:00
} else {
2023-04-30 01:25:58 +00:00
return luax_pushcomponents ( L , field , data ) ;
2023-01-16 13:15:13 +00:00
}
}
2022-04-26 22:32:54 +00:00
static int l_lovrBufferGetSize ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2022-04-26 22:32:54 +00:00
const BufferInfo * info = lovrBufferGetInfo ( buffer ) ;
2023-01-16 13:15:13 +00:00
lua_pushinteger ( L , info - > size ) ;
2022-04-26 22:32:54 +00:00
return 1 ;
}
static int l_lovrBufferGetLength ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2022-04-26 22:32:54 +00:00
const BufferInfo * info = lovrBufferGetInfo ( buffer ) ;
2023-01-16 13:15:13 +00:00
uint32_t length = info - > fields ? info - > fields [ 0 ] . length : 0 ;
lua_pushinteger ( L , length ) ;
2022-04-26 22:32:54 +00:00
return 1 ;
}
static int l_lovrBufferGetStride ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2022-04-26 22:32:54 +00:00
const BufferInfo * info = lovrBufferGetInfo ( buffer ) ;
2023-01-16 13:15:13 +00:00
uint32_t stride = info - > fields & & info - > fields [ 0 ] . length > 0 ? info - > fields [ 0 ] . stride : 0 ;
lua_pushinteger ( L , stride ) ;
2022-04-26 22:32:54 +00:00
return 1 ;
}
2023-01-16 13:15:13 +00:00
static void luax_pushbufferformat ( lua_State * L , const BufferField * fields , uint32_t count , bool root ) {
lua_createtable ( L , count , 0 ) ;
for ( uint32_t i = 0 ; i < count ; i + + ) {
const BufferField * field = & fields [ i ] ;
lua_newtable ( L ) ;
if ( field - > name ) {
lua_pushstring ( L , field - > name ) ;
lua_setfield ( L , - 2 , " name " ) ;
}
if ( field - > location ! = ~ 0u ) {
lua_pushinteger ( L , field - > location ) ;
lua_setfield ( L , - 2 , " location " ) ;
}
if ( field - > childCount > 0 ) {
luax_pushbufferformat ( L , field - > children , field - > childCount , false ) ;
} else {
2023-06-24 02:11:30 +00:00
luax_pushenum ( L , DataType , field - > type ) ;
2023-01-16 13:15:13 +00:00
}
2022-04-29 03:19:11 +00:00
lua_setfield ( L , - 2 , " type " ) ;
2022-04-26 22:32:54 +00:00
lua_pushinteger ( L , field - > offset ) ;
2022-04-29 03:19:11 +00:00
lua_setfield ( L , - 2 , " offset " ) ;
2023-01-16 13:15:13 +00:00
if ( field - > length > 0 & & ! root ) {
lua_pushinteger ( L , field - > length ) ;
lua_setfield ( L , - 2 , " length " ) ;
lua_pushinteger ( L , field - > stride ) ;
lua_setfield ( L , - 2 , " stride " ) ;
2022-08-24 02:17:54 +00:00
}
2022-04-26 22:32:54 +00:00
lua_rawseti ( L , - 2 , i + 1 ) ;
}
2023-01-16 13:15:13 +00:00
}
static int l_lovrBufferGetFormat ( lua_State * L ) {
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
const BufferInfo * info = lovrBufferGetInfo ( buffer ) ;
if ( info - > fieldCount = = 0 ) {
lua_pushnil ( L ) ;
} else if ( info - > fields [ 0 ] . childCount > 0 ) {
luax_pushbufferformat ( L , info - > fields [ 0 ] . children , info - > fields [ 0 ] . childCount , true ) ;
} else {
luax_pushbufferformat ( L , info - > fields , 1 , true ) ;
}
2022-04-26 22:32:54 +00:00
return 1 ;
}
2022-04-27 07:28:39 +00:00
static int l_lovrBufferGetPointer ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2023-04-30 01:25:58 +00:00
void * pointer = lovrBufferSetData ( buffer , 0 , ~ 0u ) ;
2022-04-27 07:28:39 +00:00
lua_pushlightuserdata ( L , pointer ) ;
return 1 ;
}
static int l_lovrBufferIsTemporary ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2022-04-27 07:28:39 +00:00
bool temporary = lovrBufferIsTemporary ( buffer ) ;
lua_pushboolean ( L , temporary ) ;
return 1 ;
}
2023-04-30 01:25:58 +00:00
static int l_lovrBufferNewReadback ( lua_State * L ) {
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
uint32_t offset = luax_optu32 ( L , 2 , 0 ) ;
uint32_t extent = luax_optu32 ( L , 3 , ~ 0u ) ;
Readback * readback = lovrReadbackCreateBuffer ( buffer , offset , extent ) ;
luax_pushtype ( L , Readback , readback ) ;
lovrRelease ( readback , lovrReadbackDestroy ) ;
return 1 ;
}
static int l_lovrBufferGetData ( lua_State * L ) {
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
const BufferInfo * info = lovrBufferGetInfo ( buffer ) ;
void * data = lovrBufferGetData ( buffer , 0 , info - > size ) ;
return luax_pushbufferdata ( L , info - > fields , data ) ;
}
2022-04-27 07:28:39 +00:00
static int l_lovrBufferSetData ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2023-04-30 01:25:58 +00:00
const BufferInfo * info = lovrBufferGetInfo ( buffer ) ;
if ( lua_istable ( L , 2 ) ) {
lovrCheck ( info - > fields , " Buffer must be created with format information to copy a table to it " ) ;
if ( info - > fields [ 0 ] . length = = 0 ) {
void * data = lovrBufferSetData ( buffer , 0 , info - > size ) ;
luax_checkbufferdata ( L , 2 , info - > fields , data ) ;
} else {
lua_rawgeti ( L , 2 , 1 ) ;
bool nested = lua_istable ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
BufferField * array = & info - > fields [ 0 ] ;
uint32_t tableLength = luax_len ( L , 2 ) ;
uint32_t dstIndex = luax_optu32 ( L , 3 , 1 ) - 1 ;
uint32_t srcIndex = luax_optu32 ( L , 4 , 1 ) - 1 ;
uint32_t limit = nested ? MIN ( array - > length - dstIndex , tableLength - srcIndex ) : array - > length - dstIndex ;
uint32_t count = luax_optu32 ( L , 5 , limit ) ;
lovrCheck ( dstIndex + count < = array - > length , " Buffer copy range exceeds the length of the target Buffer " ) ;
void * data = lovrBufferSetData ( buffer , dstIndex * array - > stride , count * array - > stride ) ;
luax_checkarray ( L , 2 , srcIndex , count , array , data ) ;
}
return 0 ;
}
Blob * blob = luax_totype ( L , 2 , Blob ) ;
if ( blob ) {
uint32_t dstOffset = luax_optu32 ( L , 3 , 0 ) ;
uint32_t srcOffset = luax_optu32 ( L , 4 , 0 ) ;
lovrCheck ( dstOffset < info - > size , " Buffer offset is bigger than the size of the Buffer " ) ;
lovrCheck ( srcOffset < blob - > size , " Blob offset is bigger than the size of the Blob " ) ;
2023-04-30 06:02:37 +00:00
uint32_t limit = ( uint32_t ) MIN ( info - > size - dstOffset , blob - > size - srcOffset ) ;
2023-04-30 01:25:58 +00:00
uint32_t extent = luax_optu32 ( L , 5 , limit ) ;
lovrCheck ( extent < = info - > size - dstOffset , " Buffer copy range exceeds the size of the target Buffer " ) ;
lovrCheck ( extent < = blob - > size - srcOffset , " Buffer copy range exceeds the size of the source Blob " ) ;
void * data = lovrBufferSetData ( buffer , dstOffset , extent ) ;
memcpy ( data , ( char * ) blob - > data + srcOffset , extent ) ;
return 0 ;
}
Buffer * src = luax_totype ( L , 2 , Buffer ) ;
if ( src ) {
Buffer * dst = buffer ;
uint32_t dstOffset = luax_optu32 ( L , 3 , 0 ) ;
uint32_t srcOffset = luax_optu32 ( L , 4 , 0 ) ;
const BufferInfo * dstInfo = lovrBufferGetInfo ( dst ) ;
const BufferInfo * srcInfo = lovrBufferGetInfo ( src ) ;
uint32_t limit = MIN ( dstInfo - > size - dstOffset , srcInfo - > size - srcOffset ) ;
uint32_t extent = luax_optu32 ( L , 5 , limit ) ;
lovrBufferCopy ( src , dst , srcOffset , dstOffset , extent ) ;
return 0 ;
}
return luax_typeerror ( L , 2 , " table, Blob, or Buffer " ) ;
2022-04-27 07:28:39 +00:00
}
static int l_lovrBufferClear ( lua_State * L ) {
2022-08-23 03:30:09 +00:00
Buffer * buffer = luax_checkbuffer ( L , 1 ) ;
2023-01-16 13:15:13 +00:00
uint32_t offset = luax_optu32 ( L , 2 , 0 ) ;
2023-04-30 01:25:58 +00:00
uint32_t extent = luax_optu32 ( L , 3 , ~ 0u ) ;
2023-01-16 13:15:13 +00:00
lovrBufferClear ( buffer , offset , extent ) ;
2022-04-27 07:28:39 +00:00
return 0 ;
}
2022-04-26 22:32:54 +00:00
const luaL_Reg lovrBuffer [ ] = {
{ " getSize " , l_lovrBufferGetSize } ,
{ " getLength " , l_lovrBufferGetLength } ,
{ " getStride " , l_lovrBufferGetStride } ,
{ " getFormat " , l_lovrBufferGetFormat } ,
2022-04-27 07:28:39 +00:00
{ " getPointer " , l_lovrBufferGetPointer } ,
{ " isTemporary " , l_lovrBufferIsTemporary } ,
2023-04-30 01:25:58 +00:00
{ " newReadback " , l_lovrBufferNewReadback } ,
{ " getData " , l_lovrBufferGetData } ,
2022-04-27 07:28:39 +00:00
{ " setData " , l_lovrBufferSetData } ,
{ " clear " , l_lovrBufferClear } ,
2022-04-26 22:32:54 +00:00
{ NULL , NULL }
} ;