#include "api.h" #include "graphics/buffer.h" #include "graphics/shader.h" #include "data/blob.h" #include #include #include #include static int l_lovrShaderBlockGetType(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); luax_pushenum(L, BlockType, lovrShaderBlockGetType(block)); return 1; } static int l_lovrShaderBlockGetSize(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); Buffer* buffer = lovrShaderBlockGetBuffer(block); lua_pushinteger(L, lovrBufferGetSize(buffer)); return 1; } static int l_lovrShaderBlockGetOffset(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); const char* name = luaL_checkstring(L, 2); const Uniform* uniform = lovrShaderBlockGetUniform(block, name); lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name); lua_pushinteger(L, uniform->offset); return 1; } static int l_lovrShaderBlockSend(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); Buffer* buffer = lovrShaderBlockGetBuffer(block); if (lua_type(L, 2) == LUA_TSTRING) { const char* name = luaL_checkstring(L, 2); const Uniform* uniform = lovrShaderBlockGetUniform(block, name); lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name); uint8_t* data = lovrBufferMap(buffer, uniform->offset, false); luax_checkuniform(L, 3, uniform, data, name); lovrBufferFlush(buffer, uniform->offset, uniform->size); return 0; } else { Blob* blob = luax_checktype(L, 2, Blob); size_t srcOffset = luaL_optinteger(L, 3, 0); size_t dstOffset = luaL_optinteger(L, 4, 0); size_t bufferSize = lovrBufferGetSize(buffer); // TODO make/use shared helper to check srcOffset/dstOffset/size are non-negative to make these errors better lovrAssert(srcOffset <= blob->size, "Source offset is bigger than the Blob size (%d > %d)", srcOffset, blob->size); lovrAssert(dstOffset <= bufferSize, "Destination offset is bigger than the ShaderBlock size (%d > %d)", dstOffset, bufferSize); size_t maxSize = MIN(blob->size - srcOffset, bufferSize - dstOffset); size_t size = luaL_optinteger(L, 5, maxSize); lovrAssert(size <= blob->size - srcOffset, "Source offset plus copy size exceeds Blob size (%d > %d)", srcOffset + size, blob->size); lovrAssert(size <= bufferSize - dstOffset, "Destination offset plus copy size exceeds ShaderBlock size (%d > %d)", dstOffset + size, bufferSize); char* dst = lovrBufferMap(buffer, dstOffset, false); char* src = (char*) blob->data + srcOffset; memcpy(dst, src, size); lovrBufferFlush(buffer, dstOffset, size); lua_pushinteger(L, size); return 1; } } static int l_lovrShaderBlockRead(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); const char* name = luaL_checkstring(L, 2); const Uniform* uniform = lovrShaderBlockGetUniform(block, name); lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name); Buffer* buffer = lovrShaderBlockGetBuffer(block); lovrAssert(lovrBufferIsReadable(buffer), "ShaderBlock:read requires the ShaderBlock to be created with the readable flag"); union { float* floats; int* ints; } data = { .floats = lovrBufferMap(buffer, uniform->offset, false) }; int components = uniform->components; if (uniform->type == UNIFORM_MATRIX) { components *= components; } lua_createtable(L, uniform->count, 0); for (int i = 0; i < uniform->count; i++) { if (components == 1) { switch (uniform->type) { case UNIFORM_FLOAT: lua_pushnumber(L, data.floats[i]); lua_rawseti(L, -2, i + 1); break; case UNIFORM_INT: lua_pushinteger(L, data.ints[i]); lua_rawseti(L, -2, i + 1); break; default: break; } } else { lua_createtable(L, components, 0); for (int j = 0; j < components; j++) { switch (uniform->type) { case UNIFORM_FLOAT: case UNIFORM_MATRIX: lua_pushnumber(L, data.floats[i * components + j]); lua_rawseti(L, -2, j + 1); break; case UNIFORM_INT: lua_pushinteger(L, data.ints[i * components + j]); lua_rawseti(L, -2, j + 1); break; default: break; } } lua_rawseti(L, -2, i + 1); } } return 1; } static int l_lovrShaderBlockGetShaderCode(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); const char* blockName = luaL_checkstring(L, 2); const char* namespace = luaL_optstring(L, 3, NULL); size_t length; char* code = lovrShaderBlockGetShaderCode(block, blockName, namespace, &length); lua_pushlstring(L, code, length); free(code); return 1; } const luaL_Reg lovrShaderBlock[] = { { "getType", l_lovrShaderBlockGetType }, { "getSize", l_lovrShaderBlockGetSize }, { "getOffset", l_lovrShaderBlockGetOffset }, { "read", l_lovrShaderBlockRead }, { "send", l_lovrShaderBlockSend }, { "getShaderCode", l_lovrShaderBlockGetShaderCode }, { NULL, NULL } };