From: Eleni Maria Stea Date: Sun, 16 Jul 2017 12:40:53 +0000 (+0300) Subject: quick backup: X-Git-Url: https://eleni.mutantstargoat.com/git/?p=demo;a=commitdiff_plain;h=369d75c73bf926a6dbcf4d740c8664bbb401602a quick backup: - camera - state manager - shaders - renderer - mesh drawing functions missing: renderer drawing functions, renderers for our meshes --- diff --git a/src/camera.cc b/src/camera.cc index d7839b5..4db7286 100644 --- a/src/camera.cc +++ b/src/camera.cc @@ -1,20 +1,53 @@ +#include + #include + #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 diff --git a/src/camera.h b/src/camera.h index 8b3a895..cbd543f 100644 --- a/src/camera.h +++ b/src/camera.h @@ -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 diff --git a/src/main.cc b/src/main.cc index 4e6677a..4d77441 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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); } diff --git a/src/opengl/renderer-gl.cc b/src/opengl/renderer-gl.cc index 5b81be3..1773f40 100644 --- a/src/opengl/renderer-gl.cc +++ b/src/opengl/renderer-gl.cc @@ -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; iobjects.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 diff --git a/src/opengl/renderer-gl.h b/src/opengl/renderer-gl.h index 195df58..88ba727 100644 --- a/src/opengl/renderer-gl.h +++ b/src/opengl/renderer-gl.h @@ -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 diff --git a/src/opengl/shader-gl.cc b/src/opengl/shader-gl.cc index c5b57a7..c82a7d7 100644 --- a/src/opengl/shader-gl.cc +++ b/src/opengl/shader-gl.cc @@ -2,8 +2,11 @@ #include #include +#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; inum < 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 #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; itype < sizeof shaders / sizeof *shaders); shaders[sdr->type] = sdr; +} + +ShaderProgram *get_current_program() +{ + return current_program; } \ No newline at end of file diff --git a/src/shader.h b/src/shader.h index 28832f6..abfe364 100644 --- a/src/shader.h +++ b/src/shader.h @@ -1,6 +1,15 @@ #ifndef SHADER_H_ #define SHADER_H_ +#include +#include + +#include + +/* + 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 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 index 0000000..a375cff --- /dev/null +++ b/src/state_manager.cc @@ -0,0 +1,106 @@ +#include +#include +#include + +#include + +#include "state_manager.h" + +StateManager state_manager; + +State *StateManager::get_state(const char *name) +{ + std::map::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 index 0000000..4894644 --- /dev/null +++ b/src/state_manager.h @@ -0,0 +1,48 @@ +#ifndef STATE_MANAGER_H_ +#define STATE_MANAGER_H_ + +#include +#include + +#include +#include + +struct State { + int num; + char *name; + float *data; +}; + +class StateManager { +private: + std::map statemap; + State *get_state(const char *name); + +public: + std::vector 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