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;
|
2018-08-18 02:52:34 +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));
|
2018-08-18 02:52:34 +00:00
|
|
|
lovrAssert(type == uniform->textureType, "Attempt to send %s texture to %s sampler uniform", TextureTypes[type], TextureTypes[uniform->textureType]);
|
2018-08-10 02:25:51 +00:00
|
|
|
break;
|
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);
|
|
|
|
lua_pushstring(L, ShaderTypes[lovrShaderGetType(shader)]);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
lovrAssert(uniform, "Unknown shader variable '%s'", name);
|
|
|
|
|
|
|
|
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
|
|
|
}
|
2016-08-28 20:36:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
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);
|
|
|
|
ShaderBlock* block = luax_checktype(L, 3, ShaderBlock);
|
2018-08-17 22:09:13 +00:00
|
|
|
UniformAccess access = luaL_checkoption(L, 4, "readwrite", UniformAccesses);
|
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);
|
|
|
|
UniformAccess access = luaL_checkoption(L, index++, "readwrite", UniformAccesses);
|
|
|
|
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 },
|
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 }
|
|
|
|
};
|