quick backup:
[demo] / src / opengl / shader-gl.cc
index c5b57a7..c82a7d7 100644 (file)
@@ -2,8 +2,11 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "state_manager.h"
 #include "opengl/shader-gl.h"
 
+extern ShaderProgram *current_program;
+
 ShaderGL::ShaderGL()
 {
        sdr = 0;
@@ -73,17 +76,15 @@ void ShaderGL::destroy()
        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()
@@ -91,14 +92,6 @@ 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) {
@@ -106,14 +99,29 @@ void ShaderProgramGL::delete_shaders()
        }
 }
 
+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");
 
@@ -131,44 +139,216 @@ bool ShaderProgramGL::link()
        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