2017-12-10 20:40:37 +00:00
# include "api.h"
2019-04-05 11:58:29 +00:00
# include "graphics/buffer.h"
2017-03-11 11:08:07 +00:00
# include "graphics/shader.h"
2019-05-20 09:47:33 +00:00
# include "core/maf.h"
2019-06-02 07:20:10 +00:00
# include <stdlib.h>
2016-08-10 06:28:17 +00:00
2017-10-21 20:39:50 +00:00
struct TempData {
void * data ;
2018-07-28 22:40:13 +00:00
int size ;
2017-10-21 20:39:50 +00:00
} ;
2018-08-18 02:52:34 +00:00
// Not thread safe
2017-10-21 20:39:50 +00:00
static struct TempData tempData ;
2018-08-01 01:23:04 +00:00
int luax_checkuniform ( lua_State * L , int index , const Uniform * uniform , void * dest , const char * debug ) {
Blob * blob = luax_totype ( L , index , Blob ) ;
2018-11-27 23:03:05 +00:00
UniformType uniformType = uniform - > type ;
2018-08-01 01:23:04 +00:00
int components = uniform - > components ;
int count = uniform - > count ;
2017-10-22 22:58:56 +00:00
2018-11-27 23:03:05 +00:00
if ( uniformType = = UNIFORM_MATRIX ) {
2018-08-01 01:23:04 +00:00
components * = components ;
}
2016-08-28 20:36:54 +00:00
2018-08-01 01:23:04 +00:00
if ( blob ) {
size_t elements = count * components ;
const char * s = elements = = 1 ? " " : " s " ;
size_t capacity ;
2016-08-28 20:36:54 +00:00
2018-11-27 23:03:05 +00:00
switch ( uniformType ) {
2018-08-01 01:23:04 +00:00
case UNIFORM_FLOAT :
case UNIFORM_MATRIX :
capacity = blob - > size / sizeof ( float ) ;
2018-08-01 06:07:28 +00:00
lovrAssert ( capacity > = elements , " Blob can only hold %d float%s, at least %d needed for uniform '%s' " , capacity , s , elements , debug ) ;
2018-08-01 01:23:04 +00:00
memcpy ( dest , blob - > data , elements * sizeof ( float ) ) ;
break ;
2016-11-27 02:58:58 +00:00
2018-08-01 01:23:04 +00:00
case UNIFORM_INT :
capacity = blob - > size / sizeof ( int ) ;
2018-08-01 06:07:28 +00:00
lovrAssert ( capacity > = elements , " Blob can only hold %d int%s, at least %d needed for uniform '%s' " , capacity , s , elements , debug ) ;
2018-08-01 01:23:04 +00:00
memcpy ( dest , blob - > data , elements * sizeof ( int ) ) ;
break ;
2017-10-21 20:39:50 +00:00
2018-08-18 02:52:34 +00:00
case UNIFORM_SAMPLER : lovrThrow ( " Sampler uniform '%s' can not be updated with a Blob " , debug ) ;
case UNIFORM_IMAGE : lovrThrow ( " Image uniform '%s' can not be updated with a Blob " , debug ) ;
2017-10-21 20:39:50 +00:00
}
2018-08-01 01:23:04 +00:00
return 0 ;
2017-10-21 20:39:50 +00:00
}
2016-08-28 20:36:54 +00:00
2018-08-01 01:23:04 +00:00
if ( components = = 1 ) {
bool isTable = lua_istable ( L , index ) ;
2019-03-17 07:58:01 +00:00
int length = isTable ? luax_len ( L , index ) : count ;
2018-08-10 02:25:51 +00:00
length = MIN ( length , count ) ;
for ( int i = 0 ; i < count ; i + + ) {
int j = index + i ;
if ( isTable ) {
2018-08-01 01:23:04 +00:00
lua_rawgeti ( L , index , i + 1 ) ;
2018-08-10 02:25:51 +00:00
j = - 1 ;
}
2018-11-27 23:03:05 +00:00
switch ( uniformType ) {
2019-01-29 10:28:55 +00:00
case UNIFORM_FLOAT : * ( ( float * ) dest + i ) = luax_optfloat ( L , j , 0.f ) ; break ;
2018-10-06 23:15:38 +00:00
case UNIFORM_INT : * ( ( int * ) dest + i ) = luaL_optinteger ( L , j , 0 ) ; break ;
2020-01-23 19:18:04 +00:00
case UNIFORM_SAMPLER : {
2018-08-10 02:25:51 +00:00
* ( ( Texture * * ) dest + i ) = luax_checktype ( L , j , Texture ) ;
TextureType type = lovrTextureGetType ( * ( ( Texture * * ) dest + i ) ) ;
2020-03-14 23:46:35 +00:00
lovrAssert ( type = = uniform - > textureType , " Attempt to send %s texture to %s sampler uniform " , TextureTypes [ type ] . string , TextureTypes [ uniform - > textureType ] . string ) ;
2018-08-10 02:25:51 +00:00
break ;
2020-01-23 19:18:04 +00:00
}
2018-08-18 02:52:34 +00:00
case UNIFORM_IMAGE : {
Image * image = ( Image * ) dest + i ;
image - > texture = luax_checktype ( L , j , Texture ) ;
2018-09-04 13:58:54 +00:00
image - > slice = - 1 ;
2018-08-18 02:52:34 +00:00
image - > mipmap = 0 ;
image - > access = ACCESS_READ_WRITE ;
TextureType type = lovrTextureGetType ( image - > texture ) ;
lovrAssert ( type = = uniform - > textureType , " Attempt to send %s texture to %s image uniform " , TextureTypes [ type ] , TextureTypes [ uniform - > textureType ] ) ;
break ;
}
2018-08-10 02:25:51 +00:00
default : break ;
2016-08-28 20:36:54 +00:00
}
2018-08-10 02:25:51 +00:00
if ( isTable ) {
lua_pop ( L , 1 ) ;
2016-08-28 20:36:54 +00:00
}
2018-08-01 01:23:04 +00:00
}
} else {
2019-01-08 17:14:10 +00:00
bool wrappedTable = false ;
if ( lua_istable ( L , index ) ) {
lua_rawgeti ( L , index , 1 ) ;
wrappedTable = ! lua_isnumber ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
}
2018-08-01 01:23:04 +00:00
if ( wrappedTable ) {
2019-03-17 07:58:01 +00:00
int length = luax_len ( L , index ) ;
2018-08-01 06:07:28 +00:00
length = MIN ( length , count ) ;
2018-08-01 01:23:04 +00:00
for ( int i = 0 ; i < length ; i + + ) {
lua_rawgeti ( L , index , i + 1 ) ;
2018-11-27 23:03:05 +00:00
if ( uniformType = = UNIFORM_MATRIX & & components = = 16 ) {
2019-07-01 09:16:13 +00:00
VectorType type ;
mat4 m = luax_tovector ( L , - 1 , & type ) ;
if ( m & & type = = V_MAT4 ) {
2018-11-27 23:03:05 +00:00
mat4_init ( ( float * ) dest + i * components , m ) ;
lua_pop ( L , 1 ) ;
continue ;
}
} else if ( uniformType = = UNIFORM_FLOAT & & components = = 3 ) {
2019-07-01 09:16:13 +00:00
VectorType type ;
vec3 v = luax_tovector ( L , - 1 , & type ) ;
if ( v & & type = = V_VEC3 ) {
2018-11-27 23:03:05 +00:00
vec3_init ( ( float * ) dest + i * components , v ) ;
lua_pop ( L , 1 ) ;
continue ;
}
2018-08-01 01:23:04 +00:00
}
2018-11-27 23:03:05 +00:00
luaL_checktype ( L , - 1 , LUA_TTABLE ) ;
2018-08-01 01:23:04 +00:00
for ( int j = 0 ; j < components ; j + + ) {
lua_rawgeti ( L , - 1 , j + 1 ) ;
2018-11-27 23:03:05 +00:00
switch ( uniformType ) {
2018-08-01 01:23:04 +00:00
case UNIFORM_FLOAT :
case UNIFORM_MATRIX :
2019-01-29 10:28:55 +00:00
* ( ( float * ) dest + i * components + j ) = luax_optfloat ( L , - 1 , 0.f ) ;
2018-09-05 17:13:04 +00:00
break ;
2018-08-01 01:23:04 +00:00
case UNIFORM_INT :
2018-10-06 23:15:38 +00:00
* ( ( int * ) dest + i * components + j ) = luaL_optinteger ( L , - 1 , 0 ) ;
2018-08-01 01:23:04 +00:00
break ;
2018-08-18 02:52:34 +00:00
case UNIFORM_SAMPLER :
case UNIFORM_IMAGE :
lovrThrow ( " Unreachable " ) ;
2017-10-21 20:39:50 +00:00
}
2016-12-30 19:57:15 +00:00
lua_pop ( L , 1 ) ;
}
2018-08-01 01:23:04 +00:00
lua_pop ( L , 1 ) ;
2016-12-30 19:57:15 +00:00
}
2018-08-01 01:23:04 +00:00
} else {
for ( int i = 0 ; i < count ; i + + ) {
2018-11-27 23:03:05 +00:00
if ( uniformType = = UNIFORM_MATRIX & & components = = 16 ) {
2019-07-01 09:16:13 +00:00
VectorType type ;
mat4 m = luax_tovector ( L , index + i , & type ) ;
if ( m & & type = = V_MAT4 ) {
2018-11-27 23:03:05 +00:00
mat4_init ( ( float * ) dest + i * components , m ) ;
continue ;
}
} else if ( uniformType = = UNIFORM_FLOAT & & components = = 3 ) {
2019-07-01 09:16:13 +00:00
VectorType type ;
vec3 v = luax_tovector ( L , index + i , & type ) ;
if ( v & & type = = V_VEC3 ) {
2018-11-27 23:03:05 +00:00
vec3_init ( ( float * ) dest + i * components , v ) ;
continue ;
}
2018-08-01 01:23:04 +00:00
}
luaL_checktype ( L , index + i , LUA_TTABLE ) ;
for ( int j = 0 ; j < components ; j + + ) {
lua_rawgeti ( L , index + i , j + 1 ) ;
2018-11-27 23:03:05 +00:00
switch ( uniformType ) {
2018-08-01 01:23:04 +00:00
case UNIFORM_FLOAT :
case UNIFORM_MATRIX :
2019-01-29 10:28:55 +00:00
* ( ( float * ) dest + i * components + j ) = luax_optfloat ( L , - 1 , 0.f ) ;
2018-08-01 01:23:04 +00:00
break ;
case UNIFORM_INT :
2019-01-12 06:37:54 +00:00
* ( ( int * ) dest + i * components + j ) = luaL_optinteger ( L , - 1 , 0 ) ;
2018-08-01 01:23:04 +00:00
break ;
2018-08-18 02:52:34 +00:00
case UNIFORM_SAMPLER :
case UNIFORM_IMAGE :
lovrThrow ( " Unreachable " ) ;
2018-08-01 01:23:04 +00:00
}
2017-02-18 23:18:30 +00:00
}
2016-08-28 20:36:54 +00:00
}
2018-08-01 01:23:04 +00:00
}
}
return 0 ;
}
2016-08-28 20:36:54 +00:00
2019-02-17 22:52:22 +00:00
static int l_lovrShaderGetType ( lua_State * L ) {
2018-08-07 23:58:14 +00:00
Shader * shader = luax_checktype ( L , 1 , Shader ) ;
2020-02-17 02:31:02 +00:00
luax_pushenum ( L , ShaderTypes , lovrShaderGetType ( shader ) ) ;
2018-08-07 23:58:14 +00:00
return 1 ;
}
2019-02-17 22:52:22 +00:00
static int l_lovrShaderHasUniform ( lua_State * L ) {
2018-08-01 01:23:04 +00:00
Shader * shader = luax_checktype ( L , 1 , Shader ) ;
const char * name = luaL_checkstring ( L , 2 ) ;
lua_pushboolean ( L , lovrShaderHasUniform ( shader , name ) ) ;
return 1 ;
}
2020-01-31 02:26:05 +00:00
static int l_lovrShaderHasBlock ( lua_State * L ) {
Shader * shader = luax_checktype ( L , 1 , Shader ) ;
const char * name = luaL_checkstring ( L , 2 ) ;
lua_pushboolean ( L , lovrShaderHasBlock ( shader , name ) ) ;
return 1 ;
}
2019-02-17 22:52:22 +00:00
static int l_lovrShaderSend ( lua_State * L ) {
2018-08-01 01:23:04 +00:00
Shader * shader = luax_checktype ( L , 1 , Shader ) ;
const char * name = luaL_checkstring ( L , 2 ) ;
const Uniform * uniform = lovrShaderGetUniform ( shader , name ) ;
2020-02-28 04:20:02 +00:00
if ( ! uniform ) {
lua_pushboolean ( L , false ) ;
return 1 ;
}
2018-08-01 01:23:04 +00:00
if ( tempData . size < uniform - > size ) {
tempData . size = uniform - > size ;
tempData . data = realloc ( tempData . data , tempData . size ) ;
2016-08-28 20:36:54 +00:00
}
2018-08-01 01:23:04 +00:00
luax_checkuniform ( L , 3 , uniform , tempData . data , name ) ;
2018-08-06 20:44:46 +00:00
switch ( uniform - > type ) {
2018-08-18 02:52:34 +00:00
case UNIFORM_FLOAT : lovrShaderSetFloats ( shader , uniform - > name , tempData . data , 0 , uniform - > count * uniform - > components ) ; break ;
case UNIFORM_INT : lovrShaderSetInts ( shader , uniform - > name , tempData . data , 0 , uniform - > count * uniform - > components ) ; break ;
case UNIFORM_MATRIX : lovrShaderSetMatrices ( shader , uniform - > name , tempData . data , 0 , uniform - > count * uniform - > components * uniform - > components ) ; break ;
case UNIFORM_SAMPLER : lovrShaderSetTextures ( shader , uniform - > name , tempData . data , 0 , uniform - > count ) ; break ;
case UNIFORM_IMAGE : lovrShaderSetImages ( shader , uniform - > name , tempData . data , 0 , uniform - > count ) ; break ;
2018-08-06 20:44:46 +00:00
}
2020-02-28 04:20:02 +00:00
lua_pushboolean ( L , true ) ;
return 1 ;
2016-08-28 20:36:54 +00:00
}
2017-03-11 11:08:07 +00:00
2019-02-17 22:52:22 +00:00
static int l_lovrShaderSendBlock ( lua_State * L ) {
2018-07-28 22:46:46 +00:00
Shader * shader = luax_checktype ( L , 1 , Shader ) ;
const char * name = luaL_checkstring ( L , 2 ) ;
2020-01-31 02:26:05 +00:00
lovrAssert ( lovrShaderHasBlock ( shader , name ) , " Unknown shader block '%s' " , name ) ;
2018-07-28 22:46:46 +00:00
ShaderBlock * block = luax_checktype ( L , 3 , ShaderBlock ) ;
2020-02-17 02:31:02 +00:00
UniformAccess access = luax_checkenum ( L , 4 , UniformAccesses , " readwrite " , " UniformAccess " ) ;
2018-12-27 21:50:42 +00:00
Buffer * buffer = lovrShaderBlockGetBuffer ( block ) ;
lovrShaderSetBlock ( shader , name , buffer , 0 , lovrBufferGetSize ( buffer ) , access ) ;
2018-07-28 22:46:46 +00:00
return 0 ;
}
2019-02-17 22:52:22 +00:00
static int l_lovrShaderSendImage ( lua_State * L ) {
2018-08-18 02:52:34 +00:00
int index = 1 ;
Shader * shader = luax_checktype ( L , index + + , Shader ) ;
const char * name = luaL_checkstring ( L , index + + ) ;
int start = 0 ;
if ( lua_type ( L , index ) = = LUA_TNUMBER ) {
start = lua_tointeger ( L , index + + ) ;
}
Texture * texture = luax_checktype ( L , index + + , Texture ) ;
int slice = luaL_optinteger ( L , index + + , 0 ) - 1 ; // Default is -1
int mipmap = luax_optmipmap ( L , index + + , texture ) ;
2020-02-17 02:31:02 +00:00
UniformAccess access = luax_checkenum ( L , index + + , UniformAccesses , " readwrite " , " UniformAccess " ) ;
2018-08-18 02:52:34 +00:00
Image image = { . texture = texture , . slice = slice , . mipmap = mipmap , . access = access } ;
lovrShaderSetImages ( shader , name , & image , start , 1 ) ;
return 0 ;
}
2017-03-11 11:08:07 +00:00
const luaL_Reg lovrShader [ ] = {
2018-08-07 23:58:14 +00:00
{ " getType " , l_lovrShaderGetType } ,
2017-10-22 22:58:56 +00:00
{ " hasUniform " , l_lovrShaderHasUniform } ,
2020-01-31 02:26:05 +00:00
{ " hasBlock " , l_lovrShaderHasBlock } ,
2017-03-11 11:08:07 +00:00
{ " send " , l_lovrShaderSend } ,
2018-08-18 02:52:34 +00:00
{ " sendBlock " , l_lovrShaderSendBlock } ,
{ " sendImage " , l_lovrShaderSendImage } ,
2017-03-11 11:08:07 +00:00
{ NULL , NULL }
} ;