#include <stdio.h>
#include <string.h>
+#include "state_manager.h"
#include "opengl/shader-gl.h"
+extern ShaderProgram *current_program;
+
ShaderGL::ShaderGL()
{
sdr = 0;
type = SDR_UNKNOWN;
}
-void ShaderGL::attach(unsigned int prog)
-{
- glAttachShader(prog, sdr);
-}
-
/* Shader Program */
ShaderProgramGL::ShaderProgramGL()
{
prog = 0;
memset(shaders, 0, sizeof shaders / sizeof *shaders);
+
+ current_program = 0;
+ is_linked = false;
}
ShaderProgramGL::~ShaderProgramGL()
destroy();
}
-void ShaderProgramGL::destroy()
-{
- glDeleteProgram(prog);
- prog = 0;
-
- delete_shaders();
-}
-
void ShaderProgramGL::delete_shaders()
{
for(unsigned int i=0; i<(sizeof shaders) / (sizeof *shaders); ++i) {
}
}
+bool ShaderProgramGL::create()
+{
+ prog = glCreateProgram();
+ if(!prog) {
+ fprintf(stderr, "Failed to create shader program.\n");
+ return false;
+ }
+ return true;
+}
+
bool ShaderProgramGL::link()
{
+ if(is_linked)
+ return true;
+
glLinkProgram(prog);
int status;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
- if(status)
+ if(status) {
printf("Successfully linked shader program.\n");
+ is_linked = true;
+ }
else
printf("Failed to link shader program.\n");
return status ? true : false;
}
-bool ShaderProgramGL::load(const char *vfname, const char *ffname)
+bool ShaderProgramGL::use()
{
- Shader *vsdr = new ShaderGL;
- if(!vsdr->load(vfname, SDR_VERTEX)) {
- delete vsdr;
+ if(!is_linked && !link()) {
return false;
}
- Shader *fsdr = new ShaderGL;
- if(!fsdr->load(ffname, SDR_FRAGMENT)) {
- delete vsdr;
- delete fsdr;
- return false;
+ if(!prog) {
+ glUseProgram(0);
+ current_program = 0;
}
- prog = glCreateProgram();
+ glUseProgram(prog);
+ current_program = this;
+
+ static void (*const set_uniform[16])(GLint, GLsizei, const GLfloat *) = {
+ 0, glUniform1fv, glUniform2fv, glUniform3fv, glUniform4fv
+ };
+
+ for(size_t i=0; i<uniforms.size(); i++) {
+ const State *st = state_manager.get_state(uniforms[i].state_idx);
+ if(st->num < 5) {
+ set_uniform[st->num](uniforms[i].location, 1, st->data);
+ }
+ else if(st->num == 16) {
+ glUniformMatrix4fv(uniforms[i].location, 1, GL_TRUE, st->data);
+ }
+ else {
+ fprintf(stderr, "Invalid number of floats in state %s: %d\n", st->name, st->num);
+ continue;
+ }
+ }
+ return true;
+}
- vsdr->attach(prog);
- fsdr->attach(prog);
+void ShaderProgramGL::destroy()
+{
+ glDeleteProgram(prog);
+ prog = 0;
+ is_linked = false;
- if(!link()) {
- delete vsdr;
- delete fsdr;
- glDeleteProgram(prog);
- return false;
+ delete_shaders();
+}
+
+void ShaderProgramGL::attach_shader(Shader *shader)
+{
+ glAttachShader(prog, ((ShaderGL *)shader)->sdr);
+ is_linked = false;
+}
+
+int ShaderProgramGL::get_uniform_location(const char *name) const
+{
+ if(!((ShaderProgramGL *)this)->use())
+ return -1;
+
+ return glGetUniformLocation(prog, name);
+}
+
+int ShaderProgramGL::get_attribute_location(const char *name) const
+{
+ if(!((ShaderProgramGL *)this)->use())
+ return -1;
+
+ return glGetAttribLocation(prog, name);
+}
+
+static int get_floats_num(unsigned int utype)
+{
+ switch(utype) {
+ case GL_FLOAT:
+ return 1;
+ case GL_FLOAT_VEC2:
+ return 2;
+ case GL_FLOAT_VEC3:
+ return 3;
+ case GL_FLOAT_VEC4:
+ return 4;
+ case GL_FLOAT_MAT2:
+ return 4;
+ case GL_FLOAT_MAT3:
+ return 9;
+ case GL_FLOAT_MAT4:
+ return 16;
+ default:
+ break;
}
- /* the order of shaders in the array is the order they have in
- enum Type, so atm it goes like: VS, FS, ... because we have SDR_VERTEX,
- SDR_FRAGMENT, ... */
+ return -1;
+}
- shaders[0] = vsdr;
- shaders[1] = fsdr;
+void ShaderProgramGL::cache_uniforms()
+{
+ uniforms.clear();
- return true;
+ int num_uniforms;
+ glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uniforms);
+
+ int max_ulength;
+ glGetProgramiv(prog, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_ulength);
+
+ char *name = new char[max_ulength + 1];
+ name[max_ulength] = 0;
+
+ for(int i=0; i<num_uniforms; i++) {
+ int usize;
+ unsigned int utype;
+ glGetActiveUniform(prog, i, max_ulength, 0, &usize, &utype, name);
+
+ if(strstr(name, "gl_") == name)
+ continue;
+
+ if(strstr(name, "st_") != name)
+ continue;
+
+ int num_floats = get_floats_num(utype);
+ if(num_floats == -1)
+ continue;
+
+ int idx = state_manager.add_state_element(name, num_floats);
+ if(idx == -1)
+ continue;
+
+ Uniform uniform;
+ uniform.name = name;
+ uniform.location = glGetUniformLocation(prog, name);
+ uniform.state_idx = idx;
+
+ uniforms.push_back(uniform);
+ }
+
+ delete [] name;
}
-void ShaderProgramGL::use()
+void ShaderProgramGL::set_uniformi(int location, int value)
{
- glUseProgram(prog);
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform1i(location, value);
+}
+
+void ShaderProgramGL::set_uniformi(int location, int x, int y)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform2i(location, x, y);
+}
+
+void ShaderProgramGL::set_uniformi(int location, int x, int y, int z)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform3i(location, x, y, z);
+}
+
+void ShaderProgramGL::set_uniformi(int location, int x, int y, int z, int w)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform4i(location, x, y, z, w);
+}
+
+void ShaderProgramGL::set_uniformf(int location, float value)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform1f(location, value);
+}
+
+void ShaderProgramGL::set_uniformf(int location, float x, float y)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform2f(location, x, y);
+}
+
+void ShaderProgramGL::set_uniformf(int location, float x, float y, float z)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform3f(location, x, y, z);
+}
+
+void ShaderProgramGL::set_uniformf(int location, float x, float y, float z, float w)
+{
+ if(!use() || location == -1) {
+ return;
+ }
+
+ glUniform4f(location, x, y, z, w);
+}
+
+void ShaderProgramGL::set_uniform_matrix(int location, const Mat4 &mat)
+{
+ if(!use() || location == -1) {
+ fprintf(stderr, "FOO\n");
+ return;
+ }
+
+ glUniformMatrix4fv(location, 1, GL_TRUE, (float *)&mat.m[0][0]);
}
\ No newline at end of file