+#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
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
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;
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");
}
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);
}
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
#include "renderer.h"
+class Scene;
+class Object;
+class Camera;
+
class RendererGL : public Renderer {
protected:
virtual void draw_object(Object *object) const override;
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
#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
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
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:
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;
};
#include <stdio.h>
#include "shader.h"
+ShaderProgram *current_program;
+
Shader::Shader() {}
Shader::~Shader()
{
ShaderProgram::ShaderProgram()
{
+ current_program = 0;
+
int len = sizeof shaders / sizeof *shaders;
for(int i=0; i<len; ++i) {
shaders[i] = 0;
{
assert(sdr->type < sizeof shaders / sizeof *shaders);
shaders[sdr->type] = sdr;
+}
+
+ShaderProgram *get_current_program()
+{
+ return current_program;
}
\ No newline at end of file
#ifndef SHADER_H_
#define SHADER_H_
+#include <vector>
+#include <string>
+
+#include <gmath/gmath.h>
+
+/*
+ Shader class
+*/
+
enum SType {
SDR_UNKNOWN,
SDR_VERTEX,
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_
--- /dev/null
+#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
--- /dev/null
+#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