diff --git a/src/api/types/shaderBlock.c b/src/api/types/shaderBlock.c index 979dec54..293f4402 100644 --- a/src/api/types/shaderBlock.c +++ b/src/api/types/shaderBlock.c @@ -2,11 +2,9 @@ #include "graphics/shader.h" #include "math/transform.h" -int l_lovrShaderBlockGetOffset(lua_State* L) { +int l_lovrShaderBlockIsWritable(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); - const char* field = luaL_checkstring(L, 2); - const Uniform* uniform = lovrShaderBlockGetUniform(block, field); - lua_pushinteger(L, uniform->offset); + lua_pushboolean(L, lovrShaderBlockGetType(block) == BLOCK_STORAGE); return 1; } @@ -16,9 +14,11 @@ int l_lovrShaderBlockGetSize(lua_State* L) { return 1; } -int l_lovrShaderBlockIsWritable(lua_State* L) { +int l_lovrShaderBlockGetOffset(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); - lua_pushboolean(L, lovrShaderBlockGetType(block) == BLOCK_STORAGE); + const char* field = luaL_checkstring(L, 2); + const Uniform* uniform = lovrShaderBlockGetUniform(block, field); + lua_pushinteger(L, uniform->offset); return 1; } @@ -42,10 +42,20 @@ int l_lovrShaderBlockSend(lua_State* L) { } } +int l_lovrShaderBlockGetShaderCode(lua_State* L) { + ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); + const char* blockName = luaL_checkstring(L, 2); + size_t length; + char* code = lovrShaderBlockGetShaderCode(block, blockName, &length); + lua_pushlstring(L, code, length); + return 1; +} + const luaL_Reg lovrShaderBlock[] = { - { "getOffset", l_lovrShaderBlockGetOffset }, - { "getSize", l_lovrShaderBlockGetSize }, { "isWritable", l_lovrShaderBlockIsWritable }, + { "getSize", l_lovrShaderBlockGetSize }, + { "getOffset", l_lovrShaderBlockGetOffset }, { "send", l_lovrShaderBlockSend }, + { "getShaderCode", l_lovrShaderBlockGetShaderCode }, { NULL, NULL } }; diff --git a/src/graphics/opengl.c b/src/graphics/opengl.c index f48518b7..92356207 100644 --- a/src/graphics/opengl.c +++ b/src/graphics/opengl.c @@ -320,6 +320,58 @@ static int getUniformComponents(GLenum type) { } } +static size_t getUniformTypeLength(const Uniform* uniform) { + size_t size = 0; + + if (uniform->count > 1) { + size += 2 + floor(log10(uniform->count)) + 1; // "[count]" + } + + switch (uniform->type) { + case UNIFORM_MATRIX: size += 3; break; + case UNIFORM_FLOAT: size += uniform->components == 1 ? 5 : 4; break; + case UNIFORM_INT: size += uniform->components == 1 ? 3 : 5; break; + default: break; + } + + return size; +} + +static const char* getUniformTypeName(const Uniform* uniform) { + switch (uniform->type) { + case UNIFORM_FLOAT: + switch (uniform->components) { + case 1: return "float"; + case 2: return "vec2"; + case 3: return "vec3"; + case 4: return "vec4"; + } + break; + + case UNIFORM_INT: + switch (uniform->components) { + case 1: return "int"; + case 2: return "ivec2"; + case 3: return "ivec3"; + case 4: return "ivec4"; + } + break; + + case UNIFORM_MATRIX: + switch (uniform->components) { + case 2: return "mat2"; + case 3: return "mat3"; + case 4: return "mat4"; + } + break; + + default: break; + } + + lovrThrow("Unreachable"); + return ""; +} + // GPU static void lovrGpuBindFramebuffer(uint32_t framebuffer) { @@ -1704,6 +1756,45 @@ BlockType lovrShaderBlockGetType(ShaderBlock* block) { return block->type; } +char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, size_t* length) { + + // Calculate + size_t size = 0; + size_t tab = 2; + size += block->type == BLOCK_UNIFORM ? 7 : 6; // "uniform" || "buffer" + size += 1; // " " + size += strlen(blockName); + size += 3; // " {\n" + for (int i = 0; i < block->uniforms.length; i++) { + size += tab; + size += getUniformTypeLength(&block->uniforms.data[i]); + size += 1; // " " + size += strlen(block->uniforms.data[i].name); + size += 2; // ";\n" + } + size += 3; // "};\n" + + // Allocate + char* code = malloc(size + 1); + + // Concatenate + char* s = code; + s += sprintf(s, "%s %s {\n", block->type == BLOCK_UNIFORM ? "uniform" : "buffer", blockName); + for (int i = 0; i < block->uniforms.length; i++) { + const Uniform* uniform = &block->uniforms.data[i]; + if (uniform->count > 1) { + s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count); + } else { + s += sprintf(s, " %s %s;\n", getUniformTypeName(uniform), uniform->name); + } + } + s += sprintf(s, "};\n"); + *s = '\0'; + + *length = size; + return code; +} + const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name) { int* index = map_get(&block->uniformMap, name); if (!index) return NULL; diff --git a/src/graphics/shader.h b/src/graphics/shader.h index f9537213..561fd7d2 100644 --- a/src/graphics/shader.h +++ b/src/graphics/shader.h @@ -76,6 +76,7 @@ ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms, BlockType type, Buff void lovrShaderBlockDestroy(void* ref); size_t lovrShaderBlockGetSize(ShaderBlock* block); BlockType lovrShaderBlockGetType(ShaderBlock* block); +char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, size_t* length); const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name); void* lovrShaderBlockMap(ShaderBlock* block); void lovrShaderBlockUnmap(ShaderBlock* block);