diff --git a/src/api/types/shader.c b/src/api/types/shader.c index c6c78576..c1098203 100644 --- a/src/api/types/shader.c +++ b/src/api/types/shader.c @@ -3,163 +3,134 @@ #include "graphics/shader.h" #include "math/transform.h" +struct TempData { + void* data; + size_t size; +}; + +static struct TempData tempData; + int l_lovrShaderSend(lua_State* L) { Shader* shader = luax_checktype(L, 1, Shader); const char* name = luaL_checkstring(L, 2); lua_settop(L, 3); - int id = lovrShaderGetUniformId(shader, name); - if (id == -1) { + Uniform* uniform = lovrShaderGetUniform(shader, name); + + if (!uniform) { return luaL_error(L, "Unknown shader variable '%s'", name); } - GLenum type; - int size; - lovrShaderGetUniformType(shader, name, &type, &size); - lovrGraphicsBindProgram(shader->id); - float data[16]; - int n; - vec_float_t values; - vec_init(&values); - - switch (type) { - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - case GL_INT: - lovrShaderSendInt(shader, id, luaL_checkinteger(L, 3)); - break; - - case GL_FLOAT: - lovrShaderSendFloat(shader, id, luaL_checknumber(L, 3)); - break; - - case GL_FLOAT_VEC2: - luaL_checktype(L, 3, LUA_TTABLE); - lua_rawgeti(L, 3, 1); - if (!lua_istable(L, -1)) { - lua_newtable(L); - lua_pushvalue(L, 3); - lua_rawseti(L, -2, 1); - } else { - lua_pop(L, 1); - } - - n = lua_objlen(L, -1); - if (n < size) { - return luaL_error(L, "Expected %d vec3s, got %d", size, n); - } - - for (int i = 0; i < size; i++) { - lua_rawgeti(L, -1, i + 1); - for (int j = 0; j < 2; j++) { - lua_rawgeti(L, -1, j + 1); - vec_push(&values, lua_tonumber(L, -1)); - lua_pop(L, 1); - } - lua_pop(L, 1); - } - - lovrShaderSendFloatVec2(shader, id, size, values.data); - break; - - case GL_FLOAT_VEC3: - luaL_checktype(L, 3, LUA_TTABLE); - lua_rawgeti(L, 3, 1); - if (!lua_istable(L, -1)) { - lua_newtable(L); - lua_pushvalue(L, 3); - lua_rawseti(L, -2, 1); - } else { - lua_pop(L, 1); - } - - n = lua_objlen(L, -1); - if (n < size) { - return luaL_error(L, "Expected %d vec3s, got %d", size, n); - } - - for (int i = 0; i < size; i++) { - lua_rawgeti(L, -1, i + 1); - for (int j = 0; j < 3; j++) { - lua_rawgeti(L, -1, j + 1); - vec_push(&values, lua_tonumber(L, -1)); - lua_pop(L, 1); - } - lua_pop(L, 1); - } - - lovrShaderSendFloatVec3(shader, id, size, values.data); - break; - - case GL_FLOAT_VEC4: - luaL_checktype(L, 3, LUA_TTABLE); - lua_rawgeti(L, 3, 1); - if (!lua_istable(L, -1)) { - lua_newtable(L); - lua_pushvalue(L, 3); - lua_rawseti(L, -2, 1); - } else { - lua_pop(L, 1); - } - - n = lua_objlen(L, -1); - if (n < size) { - return luaL_error(L, "Expected %d vec3s, got %d", size, n); - } - - for (int i = 0; i < size; i++) { - lua_rawgeti(L, -1, i + 1); - for (int j = 0; j < 4; j++) { - lua_rawgeti(L, -1, j + 1); - vec_push(&values, lua_tonumber(L, -1)); - lua_pop(L, 1); - } - lua_pop(L, 1); - } - - lovrShaderSendFloatVec4(shader, id, size, values.data); - break; - - case GL_FLOAT_MAT2: - luaL_checktype(L, 3, LUA_TTABLE); - for (int i = 0; i < 4; i++) { - lua_rawgeti(L, 3, i + 1); - data[i] = lua_tonumber(L, -1); - lua_pop(L, 1); - } - lovrShaderSendFloatMat2(shader, id, data); - break; - - case GL_FLOAT_MAT3: - luaL_checktype(L, 3, LUA_TTABLE); - for (int i = 0; i < 9; i++) { - lua_rawgeti(L, 3, i + 1); - data[i] = lua_tonumber(L, -1); - lua_pop(L, 1); - } - lovrShaderSendFloatMat3(shader, id, data); - break; - - case GL_FLOAT_MAT4: - if (lua_isuserdata(L, 3)) { - Transform* transform = luax_checktype(L, 3, Transform); - memcpy(data, transform->matrix, 16 * sizeof(float)); - } else { - luaL_checktype(L, 3, LUA_TTABLE); - for (int i = 0; i < 16; i++) { - lua_rawgeti(L, 3, i + 1); - data[i] = lua_tonumber(L, -1); - lua_pop(L, 1); - } - } - lovrShaderSendFloatMat4(shader, id, data); - break; - - default: - return luaL_error(L, "Unknown uniform type %d", type); + if (!tempData.data) { + tempData.data = malloc(uniform->size); + } else if (tempData.size < uniform->size) { + tempData.size = uniform->size; + tempData.data = realloc(tempData.data, tempData.size); } - vec_deinit(&values); + int* ints = (int*) tempData.data; + float* floats = (float*) tempData.data; + Texture** textures = (Texture**) tempData.data; + + int n = 1; + int components = uniform->components; + + if (components > 1) { + luaL_checktype(L, 3, LUA_TTABLE); + lua_rawgeti(L, 3, 1); + if (!lua_istable(L, -1)) { + lua_newtable(L); + lua_pushvalue(L, 3); + lua_rawseti(L, -2, 1); + } else { + lua_pop(L, 1); + } + + n = lua_objlen(L, -1); + if (n != uniform->count) { + const char* elements = uniform->count == 1 ? "element" : "elements"; + return luaL_error(L, "Expected %d %s for array '%s', got %d", uniform->count, elements, uniform->name, n); + } + } + + switch (uniform->type) { + case UNIFORM_FLOAT: + if (components == 1) { + floats[0] = luaL_checkinteger(L, 3); + } else { + luaL_checktype(L, 3, LUA_TTABLE); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + if (lua_type(L, -1) != LUA_TTABLE || (int) lua_objlen(L, -1) != components) { + return luaL_error(L, "Expected %d components for uniform '%s' #%d, got %d", components, uniform->name, lua_objlen(L, -1)); + } + for (int j = 0; j < components; j++) { + lua_rawgeti(L, -1, j + 1); + floats[i * components + j] = luaL_checknumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + } + lovrShaderSetFloat(shader, name, floats, n); + break; + + case UNIFORM_INT: + if (components == 1) { + ints[0] = luaL_checkinteger(L, 3); + } else { + luaL_checktype(L, 3, LUA_TTABLE); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + if (lua_type(L, -1) != LUA_TTABLE || (int) lua_objlen(L, -1) != components) { + return luaL_error(L, "Expected %d components for uniform '%s' #%d, got %d", components, uniform->name, lua_objlen(L, -1)); + } + for (int j = 0; j < components; j++) { + lua_rawgeti(L, -1, j + 1); + ints[i * components + j] = luaL_checkinteger(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + } + lovrShaderSetInt(shader, name, ints, n); + break; + + case UNIFORM_MATRIX: + if (components == 4 && lua_isuserdata(L, 3)) { + Transform* transform = luax_checktype(L, 3, Transform); + memcpy(floats, transform->matrix, 16 * sizeof(float)); + } else { + luaL_checktype(L, 3, LUA_TTABLE); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + for (int j = 0; j < components * components; j++) { + lua_rawgeti(L, -1, j + 1); + floats[i * components * components + j] = luaL_checknumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + } + lovrShaderSetMatrix(shader, name, floats, n); + break; + + case UNIFORM_SAMPLER: + if (components == 1) { + textures[0] = luax_checktype(L, 3, Texture); + } else { + luaL_checktype(L, 3, LUA_TTABLE); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + textures[i] = luax_checktype(L, -1, Texture); + lua_pop(L, 1); + } + } + lovrShaderSetTexture(shader, name, textures, n); + break; + + default: break; + } return 0; } diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index c99daf39..bb37c3cf 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -87,8 +87,36 @@ void lovrGraphicsPrepare() { mat4 model = state.transforms[state.transform][MATRIX_MODEL]; mat4 view = state.transforms[state.transform][MATRIX_VIEW]; mat4 projection = state.canvases[state.canvas].projection; + lovrShaderSetMatrix(shader, "lovrModel", model, 16); + lovrShaderSetMatrix(shader, "lovrView", view, 16); + lovrShaderSetMatrix(shader, "lovrProjection", projection, 16); + + float transform[16]; + mat4_multiply(mat4_set(transform, view), model); + lovrShaderSetMatrix(shader, "lovrTransform", transform, 16); + + if (lovrShaderGetUniform(shader, "lovrNormalMatrix")) { + if (mat4_invert(transform)) { + mat4_transpose(transform); + } else { + mat4_identity(transform); + } + + float normalMatrix[9] = { + transform[0], transform[1], transform[2], + transform[4], transform[5], transform[6], + transform[8], transform[9], transform[10] + }; + + lovrShaderSetMatrix(shader, "lovrNormalMatrix", normalMatrix, 9); + } + + // Color + float color[4] = { state.color.r / 255., state.color.g / 255., state.color.b / 255., state.color.a / 255. }; + lovrShaderSetFloat(shader, "lovrColor", color, 4); + lovrGraphicsBindProgram(shader->id); - lovrShaderBind(shader, model, view, projection, state.color, 0); + lovrShaderBind(shader); } void lovrGraphicsCreateWindow(int w, int h, int fullscreen, int msaa, const char* title, const char* icon) { diff --git a/src/graphics/shader.c b/src/graphics/shader.c index a6f605af..8aff4cf5 100644 --- a/src/graphics/shader.c +++ b/src/graphics/shader.c @@ -5,6 +5,63 @@ #include #include +static UniformType getUniformType(GLenum type, const char* debug) { + switch (type) { + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + return UNIFORM_FLOAT; + + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return UNIFORM_INT; + + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + return UNIFORM_MATRIX; + + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return UNIFORM_SAMPLER; + + default: + lovrThrow("Unsupported type for uniform '%s'", debug); + return UNIFORM_FLOAT; + } +} + +static int getUniformComponents(GLenum type) { + switch (type) { + case GL_FLOAT: + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return 1; + + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_FLOAT_MAT2: + return 2; + + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_FLOAT_MAT3: + return 3; + + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT4: + return 4; + + default: + return 1; + } +} + static GLuint compileShader(GLenum type, const char* source) { GLuint shader = glCreateShader(type); @@ -79,46 +136,103 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) { // Link GLuint id = linkShaders(vertexShader, fragmentShader); + shader->id = id; - // Compute information about uniforms + lovrGraphicsBindProgram(id); + + // Uniform introspection GLint uniformCount; + int textureSlot = 0; GLsizei bufferSize = LOVR_MAX_UNIFORM_LENGTH / sizeof(GLchar); map_init(&shader->uniforms); glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); for (int i = 0; i < uniformCount; i++) { Uniform uniform; - glGetActiveUniform(id, i, bufferSize, NULL, &uniform.count, &uniform.type, uniform.name); + glGetActiveUniform(id, i, bufferSize, NULL, &uniform.count, &uniform.glType, uniform.name); + char* subscript = strchr(uniform.name, '['); if (subscript) { *subscript = '\0'; } - uniform.location = glGetUniformLocation(id, uniform.name); + uniform.index = i; + uniform.location = glGetUniformLocation(id, uniform.name); + uniform.type = getUniformType(uniform.glType, uniform.name); + uniform.components = getUniformComponents(uniform.glType); + uniform.baseTextureSlot = (uniform.type == UNIFORM_SAMPLER) ? textureSlot : -1; + + switch (uniform.type) { + case UNIFORM_FLOAT: + uniform.size = uniform.components * uniform.count * sizeof(float); + uniform.value.data = malloc(uniform.size); + break; + + case UNIFORM_INT: + uniform.size = uniform.components * uniform.count * sizeof(int); + uniform.value.data = malloc(uniform.size); + break; + + case UNIFORM_MATRIX: + uniform.size = uniform.components * uniform.components * uniform.count * sizeof(int); + uniform.value.data = malloc(uniform.size); + break; + + case UNIFORM_SAMPLER: + uniform.size = uniform.components * uniform.count * MAX(sizeof(Texture*), sizeof(int)); + uniform.value.data = malloc(uniform.size); + + // Use the value for ints to bind texture slots, but use the value for textures afterwards. + for (int i = 0; i < uniform.count; i++) { + uniform.value.ints[i] = uniform.baseTextureSlot + i; + } + glUniform1iv(uniform.location, uniform.count, uniform.value.ints); + break; + } + + memset(uniform.value.data, 0, uniform.size); + + size_t offset = 0; + for (int j = 0; j < uniform.count; j++) { + int location = uniform.location; + + if (uniform.count > 1) { + char name[LOVR_MAX_UNIFORM_LENGTH]; + snprintf(name, LOVR_MAX_UNIFORM_LENGTH, "%s[%d]", uniform.name, j); + location = glGetUniformLocation(id, name); + } + + switch (uniform.type) { + case UNIFORM_FLOAT: + glGetUniformfv(id, location, &uniform.value.floats[offset]); + offset += uniform.components; + break; + + case UNIFORM_INT: + glGetUniformiv(id, location, &uniform.value.ints[offset]); + offset += uniform.components; + break; + + case UNIFORM_MATRIX: + glGetUniformfv(id, location, &uniform.value.floats[offset]); + offset += uniform.components * uniform.components; + break; + + default: + break; + } + } + map_set(&shader->uniforms, uniform.name, uniform); + textureSlot += (uniform.type == UNIFORM_SAMPLER) ? uniform.count : 0; } - // Initial state - shader->id = id; - mat4_identity(shader->model); - mat4_identity(shader->view); - mat4_identity(shader->projection); - shader->color = (Color) { 0, 0, 0, 0 }; - - // Send initial uniform values to shader - lovrGraphicsBindProgram(id); - lovrShaderBind(shader, shader->model, shader->view, shader->projection, shader->color, 1); - return shader; } Shader* lovrShaderCreateDefault(DefaultShader type) { switch (type) { case SHADER_DEFAULT: return lovrShaderCreate(NULL, NULL); - case SHADER_SKYBOX: { - Shader* shader = lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader); - lovrShaderSendInt(shader, lovrShaderGetUniformId(shader, "cube"), 1); - return shader; - } + case SHADER_SKYBOX: return lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader); break; case SHADER_FONT: return lovrShaderCreate(NULL, lovrFontFragmentShader); case SHADER_FULLSCREEN: return lovrShaderCreate(lovrNoopVertexShader, NULL); default: lovrThrow("Unknown default shader type"); @@ -132,64 +246,54 @@ void lovrShaderDestroy(const Ref* ref) { free(shader); } -void lovrShaderBind(Shader* shader, mat4 model, mat4 view, mat4 projection, Color color, int force) { - int dirtyModel = force || memcmp(shader->model, model, 16 * sizeof(float)); - int dirtyView = force || memcmp(shader->view, view, 16 * sizeof(float)); - int dirtyTransform = dirtyModel || dirtyView; - int dirtyProjection = force || memcmp(shader->projection, projection, 16 * sizeof(float)); - int dirtyColor = force || memcmp(&shader->color, &color, sizeof(Color)); +void lovrShaderBind(Shader* shader) { + map_iter_t iter = map_iter(&shader->uniforms); + const char* key; + while ((key = map_next(&shader->uniforms, &iter)) != NULL) { + Uniform* uniform = map_get(&shader->uniforms, key); - if (dirtyModel) { - int uniformId = lovrShaderGetUniformId(shader, "lovrModel"); - lovrShaderSendFloatMat4(shader, uniformId, model); - memcpy(shader->model, model, 16 * sizeof(float)); - } - - if (dirtyView) { - int uniformId = lovrShaderGetUniformId(shader, "lovrView"); - lovrShaderSendFloatMat4(shader, uniformId, view); - memcpy(shader->view, view, 16 * sizeof(float)); - } - - if (dirtyTransform) { - float matrix[16]; - int uniformId = lovrShaderGetUniformId(shader, "lovrTransform"); - - mat4_multiply(mat4_set(matrix, view), model); - - if (uniformId > -1) { - lovrShaderSendFloatMat4(shader, uniformId, matrix); + if (uniform->type != UNIFORM_SAMPLER && !uniform->dirty) { + continue; } - if (mat4_invert(matrix)) { - mat4_transpose(matrix); - } else { - mat4_identity(matrix); + uniform->dirty = 0; + int count = uniform->count; + void* data = uniform->value.data; + + switch (uniform->type) { + case UNIFORM_FLOAT: + switch (uniform->components) { + case 1: glUniform1fv(uniform->location, count, data); break; + case 2: glUniform2fv(uniform->location, count, data); break; + case 3: glUniform3fv(uniform->location, count, data); break; + case 4: glUniform4fv(uniform->location, count, data); break; + } + break; + + case UNIFORM_INT: + switch (uniform->components) { + case 1: glUniform1iv(uniform->location, count, data); break; + case 2: glUniform2iv(uniform->location, count, data); break; + case 3: glUniform3iv(uniform->location, count, data); break; + case 4: glUniform4iv(uniform->location, count, data); break; + } + break; + + case UNIFORM_MATRIX: + switch (uniform->components) { + case 2: glUniformMatrix2fv(uniform->location, count, GL_FALSE, data); break; + case 3: glUniformMatrix3fv(uniform->location, count, GL_FALSE, data); break; + case 4: glUniformMatrix4fv(uniform->location, count, GL_FALSE, data); break; + } + break; + + case UNIFORM_SAMPLER: + for (int i = 0; i < count; i++) { + TextureType type = uniform->glType == GL_SAMPLER_2D ? TEXTURE_2D : TEXTURE_CUBE; + lovrGraphicsBindTexture(uniform->value.textures[i], type, uniform->baseTextureSlot + i); + } + break; } - - float normalMatrix[9] = { - matrix[0], matrix[1], matrix[2], - matrix[4], matrix[5], matrix[6], - matrix[8], matrix[9], matrix[10] - }; - - uniformId = lovrShaderGetUniformId(shader, "lovrNormalMatrix"); - if (uniformId > -1) { - lovrShaderSendFloatMat3(shader, uniformId, normalMatrix); - } - } - - if (dirtyProjection) { - int uniformId = lovrShaderGetUniformId(shader, "lovrProjection"); - lovrShaderSendFloatMat4(shader, uniformId, projection); - memcpy(shader->projection, projection, 16 * sizeof(float)); - } - - if (dirtyColor) { - int uniformId = lovrShaderGetUniformId(shader, "lovrColor"); - float c[4] = { color.r / 255., color.g / 255., color.b / 255., color.a / 255. }; - lovrShaderSendFloatVec4(shader, uniformId, 1, c); - shader->color = color; } } @@ -201,51 +305,39 @@ int lovrShaderGetAttributeId(Shader* shader, const char* name) { return glGetAttribLocation(shader->id, name); } -int lovrShaderGetUniformId(Shader* shader, const char* name) { - Uniform* uniform = map_get(&shader->uniforms, name); - return uniform ? uniform->location : -1; +Uniform* lovrShaderGetUniform(Shader* shader, const char* name) { + return map_get(&shader->uniforms, name); } -int lovrShaderGetUniformType(Shader* shader, const char* name, GLenum* type, int* count) { +static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int count, size_t size, const char* debug) { Uniform* uniform = map_get(&shader->uniforms, name); - if (!uniform) { - return 1; + return; } - *type = uniform->type; - *count = uniform->count; - return 0; + lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, uniform->name); + lovrAssert(count * size == uniform->size, "Expected %d %ss for uniform %s, got %d", uniform->count, debug, uniform->name, count); + + if (!uniform->dirty && !memcmp(uniform->value.data, data, count * size)) { + return; + } + + memcpy(uniform->value.data, data, count * size); + uniform->dirty = 1; } -void lovrShaderSendInt(Shader* shader, int id, int value) { - glUniform1i(id, value); +void lovrShaderSetFloat(Shader* shader, const char* name, float* data, int count) { + lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, data, count, sizeof(float), "float"); } -void lovrShaderSendFloat(Shader* shader, int id, float value) { - glUniform1f(id, value); +void lovrShaderSetInt(Shader* shader, const char* name, int* data, int count) { + lovrShaderSetUniform(shader, name, UNIFORM_INT, data, count, sizeof(int), "int"); } -void lovrShaderSendFloatVec2(Shader* shader, int id, int count, float* vector) { - glUniform2fv(id, count, vector); +void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int count) { + lovrShaderSetUniform(shader, name, UNIFORM_MATRIX, data, count, sizeof(float), "float"); } -void lovrShaderSendFloatVec3(Shader* shader, int id, int count, float* vector) { - glUniform3fv(id, count, vector); -} - -void lovrShaderSendFloatVec4(Shader* shader, int id, int count, float* vector) { - glUniform4fv(id, count, vector); -} - -void lovrShaderSendFloatMat2(Shader* shader, int id, float* matrix) { - glUniformMatrix2fv(id, 1, GL_FALSE, matrix); -} - -void lovrShaderSendFloatMat3(Shader* shader, int id, float* matrix) { - glUniformMatrix3fv(id, 1, GL_FALSE, matrix); -} - -void lovrShaderSendFloatMat4(Shader* shader, int id, float* matrix) { - glUniformMatrix4fv(id, 1, GL_FALSE, matrix); +void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int count) { + lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, count, sizeof(Texture*), "texture"); } diff --git a/src/graphics/shader.h b/src/graphics/shader.h index 100544e1..4795c0ad 100644 --- a/src/graphics/shader.h +++ b/src/graphics/shader.h @@ -1,3 +1,4 @@ +#include "graphics/texture.h" #include "math/math.h" #include "lib/map/map.h" #include "lib/glfw.h" @@ -10,6 +11,20 @@ #define LOVR_SHADER_TEX_COORD 2 #define LOVR_MAX_UNIFORM_LENGTH 256 +typedef enum { + UNIFORM_FLOAT, + UNIFORM_MATRIX, + UNIFORM_INT, + UNIFORM_SAMPLER +} UniformType; + +typedef union { + void* data; + int* ints; + float* floats; + Texture** textures; +} UniformValue; + typedef enum { SHADER_DEFAULT, SHADER_SKYBOX, @@ -19,10 +34,16 @@ typedef enum { typedef struct { GLchar name[LOVR_MAX_UNIFORM_LENGTH]; + GLenum glType; int index; int location; - GLenum type; int count; + int components; + size_t size; + UniformType type; + UniformValue value; + int baseTextureSlot; + int dirty; } Uniform; typedef map_t(Uniform) map_uniform_t; @@ -40,15 +61,10 @@ typedef struct { Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource); Shader* lovrShaderCreateDefault(DefaultShader type); void lovrShaderDestroy(const Ref* ref); -void lovrShaderBind(Shader* shader, mat4 model, mat4 view, mat4 projection, Color color, int force); +void lovrShaderBind(Shader* shader); int lovrShaderGetAttributeId(Shader* shader, const char* name); -int lovrShaderGetUniformId(Shader* shader, const char* name); -int lovrShaderGetUniformType(Shader* shader, const char* name, GLenum* type, int* count); -void lovrShaderSendInt(Shader* shader, int id, int value); -void lovrShaderSendFloat(Shader* shader, int id, float value); -void lovrShaderSendFloatVec2(Shader* shader, int id, int count, float* vector); -void lovrShaderSendFloatVec3(Shader* shader, int id, int count,float* vector); -void lovrShaderSendFloatVec4(Shader* shader, int id, int count, float* vector); -void lovrShaderSendFloatMat2(Shader* shader, int id, float* matrix); -void lovrShaderSendFloatMat3(Shader* shader, int id, float* matrix); -void lovrShaderSendFloatMat4(Shader* shader, int id, float* matrix); +Uniform* lovrShaderGetUniform(Shader* shader, const char* name); +void lovrShaderSetFloat(Shader* shader, const char* name, float* data, int count); +void lovrShaderSetInt(Shader* shader, const char* name, int* data, int count); +void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int count); +void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int count);