quick backup:
authorEleni Maria Stea <estea@igalia.com>
Sun, 16 Jul 2017 12:40:53 +0000 (15:40 +0300)
committerEleni Maria Stea <estea@igalia.com>
Sun, 16 Jul 2017 12:40:53 +0000 (15:40 +0300)
- camera
- state manager
- shaders
- renderer
- mesh drawing functions

missing: renderer drawing functions, renderers for our meshes

12 files changed:
src/camera.cc
src/camera.h
src/main.cc
src/opengl/renderer-gl.cc
src/opengl/renderer-gl.h
src/opengl/shader-gl.cc
src/opengl/shader-gl.h
src/renderer.h
src/shader.cc
src/shader.h
src/state_manager.cc [new file with mode: 0644]
src/state_manager.h [new file with mode: 0644]

index d7839b5..4db7286 100644 (file)
@@ -1,20 +1,53 @@
+#include <math.h>
+
 #include <gmath/gmath.h>
+
 #include "camera.h"
+#include "state_manager.h"
 
-Camera::Camera()
+Camera::Camera() {}
+Camera::~Camera() {}
+
+void Camera::use() const
+{
+       state_manager.set_state("st_view_matrix", get_view_matrix());
+}
+
+OrbitCamera::OrbitCamera()
 {
        phi = theta = distance = 0;
-       fov = 0;
-       m_projection = Mat4::identity;
 }
 
-Camera::Camera(float phi, float theta, float distance, float fov)
+OrbitCamera::~OrbitCamera() {}
+
+void OrbitCamera::set_orbit_params(float phi, float theta, float distance)
 {
        this->phi = phi;
        this->theta = theta;
        this->distance = distance;
+}
+
+Mat4 OrbitCamera::get_view_matrix() const
+{
+       Mat4 view_matrix;
+       view_matrix.translate(Vec3(0, 0, -distance));
+       view_matrix.rotate_x(phi * (float)M_PI / 180);
+       view_matrix.rotate_y(theta * (float)M_PI / 180);
 
-       this->fov = fov;
+       return view_matrix;
 }
 
-Camera::~Camera() {}
\ No newline at end of file
+Mat4 calc_projection_matrix(float f, float n, float aspect, float fov)
+{
+       float tmp;
+       tmp = 1 / tan(fov / 2.0);
+
+       Mat4 pmat = Mat4(
+                       -tmp/aspect,    0,              0,                                      0,
+                       0,                              tmp,    0,                                      0,
+                       0,                              0,      (f + n) / (n - f),      (2 * f * n) / (n - f),
+                       0,                              0,              -1,                                     0
+                   );
+
+       return pmat;
+}
\ No newline at end of file
index 8b3a895..cbd543f 100644 (file)
@@ -5,16 +5,30 @@
 
 class Camera {
 public:
-       float phi;
+       Camera();
+       Camera(float phi, float theta, float distance, float fov);
+       virtual ~Camera();
+
+       virtual Mat4 get_view_matrix() const = 0;
+       virtual void use() const;
+};
+
+class OrbitCamera : public Camera {
+protected:
        float theta;
+       float phi;
        float distance;
 
-       Mat4 m_projection;
-       float fov;
+public:
+       OrbitCamera();
+       OrbitCamera(float theta, float phi, float distance);
+       virtual ~OrbitCamera();
 
-       Camera();
-       Camera(float phi, float theta, float distance, float fov);
-       ~Camera();
+       virtual Mat4 get_view_matrix() const override;
+
+       void set_orbit_params(float phi, float theta, float distance);
 };
 
+Mat4 calc_projection_matrix(float f, float n, float aspect, float fov);
+
 #endif // CAMERA_H_
\ No newline at end of file
index 4e6677a..4d77441 100644 (file)
@@ -30,9 +30,13 @@ GLFWwindow *win;
 int win_w = 800;
 int win_h = 600;
 
-Camera *camera;
+OrbitCamera *camera;
 
 /* variables */
+static float phi = 25;
+static float theta = 0;
+static float dist = 4;
+
 // TODO: remove just for test:
 static Scene scene;
 
@@ -90,7 +94,8 @@ static bool init()
                        return false;
        }
 
-       camera = new Camera(25, 25, 4, 45);
+       camera = new OrbitCamera;
+       camera->set_orbit_params(phi, theta, dist);
 
        if(!scene.load("data/spot/spot_control_mesh.obj")) {
                fprintf(stderr, "Failed to load scene.\n");
@@ -127,34 +132,37 @@ static void key_clbk(GLFWwindow *win, int key, int scancode, int action, int mod
 }
 
 static double prev_x, prev_y;
-static int bnstate[8];
+static int button;
 
 static void motion_clbk(GLFWwindow *win, double x, double y)
 {
-       int dx = x - prev_x;
-       int dy = y - prev_y;
+       switch(button) {
+       case GLFW_MOUSE_BUTTON_LEFT:
+               theta += x - prev_x;
+               phi += y - prev_y;
+
+               if(phi < -90)
+                       phi = -90;
+               if(phi > 90)
+                       phi = 90;
+
+               break;
+
+       case GLFW_MOUSE_BUTTON_RIGHT:
+               dist *= (y - prev_y) * 0.01 + 1;
+               if(dist < 0.0) {
+                       dist = 0.0;
+               }
+               break;
+       }
 
        prev_x = x;
        prev_y = y;
-
-       if(!dx && !dy) return;
-
-       if(bnstate[0]) {
-               camera->theta += dx * 0.5;
-               camera->phi += dy * 0.5;
-
-               if(camera->phi < -90) camera->phi = -90;
-               if(camera->phi > 90) camera->phi = 90;
-       }
-       if(bnstate[2]) {
-               camera->distance += dy * 0.1;
-               if(camera->distance < 0.0) camera->distance = 0.0;
-       }
 }
 
 static void mouse_clbk(GLFWwindow *win, int bn, int action, int mods)
 {
-       bnstate[bn - GLFW_MOUSE_BUTTON_LEFT] = action == GLFW_PRESS ? 1 : 0;
+       button = bn;
        glfwGetCursorPos(win, &prev_x, &prev_y);
 }
 
index 5b81be3..1773f40 100644 (file)
@@ -24,64 +24,26 @@ RendererGL::RendererGL(ShaderProgram *sprog, Scene *scene, Camera *camera)
 
 RendererGL::~RendererGL()
 {
-       destroy_shaders();
 }
 
-void RendererGL::draw() const
+bool RendererGL::load_shader_program(const char *vfname, const char *ffname)
 {
-       /* use shaders */
-       if(!sprog) {
-               fprintf(stderr, "No active shaders found. Using default.\n");
-               glUseProgram(0);
-       }
-       else {
-               sprog->use();
-       }
-
-       /* draw all scene components */
-       for(size_t i=0; i<scene->objects.size(); ++i) {
-               draw_object(scene->objects[i]);
-       }
+       return true;
 }
 
-
-bool RendererGL::init_shaders(const char *vfname, const char *ffname)
+void RendererGL::use_shader_program()
 {
-       if(sprog)
-               delete sprog;
-
-       sprog = new ShaderProgramGL;
-       if(!sprog->load(vfname, ffname))
-               goto error;
-
-       if(!sprog->link())
-               goto error;
-
-       sprog->use();
-
-       glEnable(GL_DEPTH_TEST);
-       glEnable(GL_CULL_FACE);
-
-       return true;
-
-error:
-       destroy_shaders();
-       return false;
 }
 
-void RendererGL::destroy_shaders()
+bool RendererGL::create()
 {
-       if(sprog) {
-               delete sprog;
-               sprog = 0;
-       }
+       return true;
 }
 
 void RendererGL::draw_object(Object *object) const
 {
-       object->material->dtex->bind();
-
-
+}
 
-       object->mesh->draw();
+void RendererGL::draw() const
+{
 }
\ No newline at end of file
index 195df58..88ba727 100644 (file)
@@ -3,6 +3,10 @@
 
 #include "renderer.h"
 
+class Scene;
+class Object;
+class Camera;
+
 class RendererGL : public Renderer {
 protected:
        virtual void draw_object(Object *object) const override;
@@ -12,10 +16,11 @@ public:
 
        virtual ~RendererGL();
 
-       virtual bool init_shaders(const char *vname, const char *fname) override;
-       virtual void destroy_shaders() override;
+       virtual bool load_shader_program(const char *vfname, const char *ffname) override;
+       virtual void use_shader_program() override;
 
-       virtual void draw() const override;
+       virtual bool create() override; // load shader prog, scene data etc
+       virtual void draw() const override; // set state from camera, set uniforms
 };
 
 #endif // RENDERER_GL_H_
\ No newline at end of file
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
index e5e6390..8c81afb 100644 (file)
@@ -6,30 +6,49 @@
 class ShaderGL : public Shader {
 protected:
        /* bsz for vulkan, in opengl buf is 0 terminated */
-       unsigned int sdr;
        virtual bool create(char *buf, unsigned int bsz, const char *fname);
 
 public:
+       unsigned int sdr;
+
        ShaderGL();
        virtual ~ShaderGL();
 
        virtual void destroy() override;
-       virtual void attach(unsigned int prog) override;
 };
 
 class ShaderProgramGL : public ShaderProgram {
 protected:
        unsigned int prog;
+       bool is_linked;
 
 public:
        ShaderProgramGL();
        virtual ~ShaderProgramGL();
 
-       void destroy();
-       void delete_shaders();
+       virtual void cache_uniforms() override;
+       virtual void delete_shaders() override;
+
        virtual bool link() override;
-       virtual bool load(const char *vfname, const char *ffname) override;
-       virtual void use() override;
+       virtual bool use() override;
+       virtual bool create() override;
+       virtual void destroy() override;
+       virtual void attach_shader(Shader *shader) override;
+
+       int get_uniform_location(const char *name) const;
+       int get_attribute_location(const char *name) const;
+
+       virtual void set_uniformi(int location, int value) override;
+       virtual void set_uniformi(int location, int x, int y) override;
+       virtual void set_uniformi(int location, int x, int y, int z) override;
+       virtual void set_uniformi(int location, int x, int y, int z, int w) override;
+
+       virtual void set_uniformf(int location, float value) override;
+       virtual void set_uniformf(int location, float x, float y) override;
+       virtual void set_uniformf(int location, float x, float y, float z) override;
+       virtual void set_uniformf(int location, float x, float y, float z, float w) override;
+
+       virtual void set_uniform_matrix(int location, const Mat4 &mat) override;
 };
 
 #endif // SHADER_GL_H_
\ No newline at end of file
index 6ea7c02..776ad9d 100644 (file)
@@ -6,10 +6,12 @@
        atm we are going to have 1 renderer per scene and 1 shader program
        for the scene
  */
+
+
 class Camera;
+class Object;
 class Scene;
 class ShaderProgram;
-class Object;
 
 class Renderer {
 protected:
@@ -24,13 +26,10 @@ public:
        Renderer(ShaderProgram *sprog, Scene *scene, Camera *camera);
        virtual ~Renderer();
 
-       /* for the moment each Renderer creates and destroys the ShaderProgram
-       because we are using only a couple of shaders, in the future we might need a shader
-       manager that stores the shaders and replace these functions with something like:
-       void set_shader_program(ShaderProgram *sprog) */
-       virtual bool init_shaders(const char *vfname, const char *ffname) = 0;
-       virtual void destroy_shaders() = 0;
+       virtual bool load_shader_program(const char *vfname, const char *ffname) = 0;
+       virtual void use_shader_program() = 0;
 
+       virtual bool create() = 0;
        virtual void draw() const = 0;
 };
 
index 8fa50ae..3bd46e2 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdio.h>
 #include "shader.h"
 
+ShaderProgram *current_program;
+
 Shader::Shader() {}
 Shader::~Shader()
 {
@@ -56,6 +58,8 @@ bool Shader::load(const char *fname, SType type)
 
 ShaderProgram::ShaderProgram()
 {
+       current_program = 0;
+
        int len = sizeof shaders / sizeof *shaders;
        for(int i=0; i<len; ++i) {
                shaders[i] = 0;
@@ -75,4 +79,9 @@ void ShaderProgram::add_shader(Shader *sdr)
 {
        assert(sdr->type < sizeof shaders / sizeof *shaders);
        shaders[sdr->type] = sdr;
+}
+
+ShaderProgram *get_current_program()
+{
+       return current_program;
 }
\ No newline at end of file
index 28832f6..abfe364 100644 (file)
@@ -1,6 +1,15 @@
 #ifndef SHADER_H_
 #define SHADER_H_
 
+#include <vector>
+#include <string>
+
+#include <gmath/gmath.h>
+
+/*
+       Shader class
+*/
+
 enum SType {
        SDR_UNKNOWN,
        SDR_VERTEX,
@@ -17,27 +26,57 @@ public:
        Shader();
        virtual ~Shader() = 0;
 
-       virtual void destroy() = 0;
        virtual bool load(const char *fname, SType type);
-       virtual void attach(unsigned int prog) = 0; // if vulkan -> leave empty
+       virtual void destroy() = 0;
+};
+
+/* Shader Program */
+
+struct Uniform {
+       int location;
+       std::string name;
+       int state_idx;
 };
 
 class ShaderProgram {
 protected:
        Shader *shaders[2];
+       std::vector<Uniform> uniforms;
 
 public:
        ShaderProgram();
        virtual ~ShaderProgram();
 
+       virtual void cache_uniforms() = 0;
+
        virtual void add_shader(Shader *sdr);
+       virtual void delete_shaders() = 0;
+
+       virtual bool create() = 0;
        virtual bool link() = 0;
-       virtual bool load(const char *vfname, const char *ffname) = 0;
-       virtual void use() = 0;
+       virtual bool use() = 0;
+       virtual void destroy() = 0;
+       virtual void attach_shader(Shader *shader) = 0;
+
+       /*
+               THIS PART MIGHT NEED SEVERAL CHANGES: on vulkan we set the uniforms
+               using descriptor sets. The current design is suitable for OpenGL and
+               it *might* have to be rewritten to work with both APIs later
+       */
 
-       /* THIS PART IS GOING TO BE CHANGED: on vulkan we set the uniforms
-          using descriptor sets. The current design is suitable for OpenGL and
-          it has to become more generic to work with both APIs later. */
+       virtual void set_uniformi(int location, int value) = 0;
+       virtual void set_uniformi(int location, int x, int y) = 0;
+       virtual void set_uniformi(int location, int x, int y, int z) = 0;
+       virtual void set_uniformi(int location, int x, int y, int z, int w) = 0;
+
+       virtual void set_uniformf(int location, float value) = 0;
+       virtual void set_uniformf(int location, float x, float y) = 0;
+       virtual void set_uniformf(int location, float x, float y, float z) = 0;
+       virtual void set_uniformf(int location, float x, float y, float z, float w) = 0;
+
+       virtual void set_uniform_matrix(int location, const Mat4 &mat) = 0;
 };
 
+ShaderProgram *get_current_program();
+
 #endif // SHADER_H_
diff --git a/src/state_manager.cc b/src/state_manager.cc
new file mode 100644 (file)
index 0000000..a375cff
--- /dev/null
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <map>
+#include <string>
+
+#include <gmath/gmath.h>
+
+#include "state_manager.h"
+
+StateManager state_manager;
+
+State *StateManager::get_state(const char *name)
+{
+       std::map<std::string, int>::iterator it;
+       it = statemap.find(name);
+       return it == statemap.end() ? 0 : &states[it->second];
+}
+
+int StateManager::add_state_element(const char *name, int num_floats)
+{
+       State *st = get_state(name);
+       if(st) {
+               if(st->num != num_floats) {
+                       fprintf(stderr, "Uniform %s, type mismatch!\n", name);
+                       return -1;
+               }
+
+               return st - &states[0];
+       }
+
+       State state;
+       state.num = num_floats;
+
+       state.name = new char[strlen(name) + 1];
+       strcpy(state.name, name);
+
+       int sz = sizeof *state.data * num_floats;
+       state.data = new float[sz];
+       memset(state.data, 0, sz);
+
+       int idx = (int)states.size();
+       states.push_back(state);
+
+       statemap[name] = idx;
+
+       printf("State manager: added state %s with %d float data.\n", name, num_floats);
+       return idx;
+}
+
+void StateManager::set_state(const char *name, float value)
+{
+       set_state(name, Vec4(value, 0, 0, 1));
+}
+
+void StateManager::set_state(const char *name, const Vec3 &vec)
+{
+       set_state(name, Vec4(vec.x, vec.y, vec.z, 1));
+}
+
+void StateManager::set_state(const char *name, const Vec4 &vec)
+{
+       State *state = get_state(name);
+       if(!state)
+               return;
+
+       switch(state->num) {
+       case 4:
+               state->data[3] = vec.w;
+       case 3:
+               state->data[2] = vec.z;
+       case 2:
+               state->data[1] = vec.y;
+       case 1:
+               state->data[0] = vec.x;
+       default:
+               break;
+       }
+}
+
+void StateManager::set_state(const char *name, const Mat4 &mat)
+{
+       State *state = get_state(name);
+
+       if(!state)
+               return;
+
+       if(state->num != 16) {
+               fprintf(stderr, "State manager: state %s can only be a 4x4 matrix.\n", name);
+               return;
+       }
+
+       for(int j=0; j<4; j++) {
+               for(int i=0; i<4; i++) {
+                       state->data[4 * i + j] = mat.m[i][j];
+               }
+       }
+}
+
+const State *StateManager::get_state(const char *name) const
+{
+       return ((StateManager *)this)->get_state(name);
+}
+
+const State *StateManager::get_state(int idx) const
+{
+       return &states[idx];
+}
\ No newline at end of file
diff --git a/src/state_manager.h b/src/state_manager.h
new file mode 100644 (file)
index 0000000..4894644
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef STATE_MANAGER_H_
+#define STATE_MANAGER_H_
+
+#include <gmath/gmath.h>
+#include <map>
+
+#include <string>
+#include <vector>
+
+struct State {
+       int num;
+       char *name;
+       float *data;
+};
+
+class StateManager {
+private:
+       std::map<std::string, int> statemap;
+       State *get_state(const char *name);
+
+public:
+       std::vector<State> states;
+
+       /*
+               adds a state returns an idx:
+               the num_floats indicates the number of floats that form
+               the state element.
+               For example:
+               a float value consists of 1 float => num_floats = 1,
+               a Vec2 consists of 2 floats, a Vec3 from 3, a Vec4 from 4
+
+               see also:
+               set_state(const char *name, const Mat4 &mat implementation)
+       */
+       int add_state_element(const char *name, int num_floats);
+
+       void set_state(const char *name, float value);
+       void set_state(const char *name, const Vec3 &vec);
+       void set_state(const char *name, const Vec4 &vec);
+       void set_state(const char *name, const Mat4 &mat);
+
+       const State *get_state(const char *name) const;
+       const State *get_state(int idx) const;
+};
+
+extern StateManager state_manager;
+
+#endif // STATE_MANAGER_H_
\ No newline at end of file