#ifndef VIEWER_H #define VIEWER_H #include #include #include #include #include #include "flextGL.h" #include struct Vertex { float x, y; float u, v; }; class WithOpenGLBindings { private: OpenGLBindings *bindings; protected: WithOpenGLBindings() : bindings(0) {} virtual ~WithOpenGLBindings() {} virtual void onOpenGLBindingsChanged(OpenGLBindings *b) { } public: void gl(OpenGLBindings *bindings) { this->bindings = bindings; onOpenGLBindingsChanged(this->bindings); } OpenGLBindings *gl() { return bindings; } }; template struct ImageFormat { static const size_t BytesPerPixel = TBytesPerPixel; static const GLenum InternalFormat = TInternalFormat; static const GLenum Format = TFormat; static const GLenum Type = TType; }; typedef ImageFormat<1, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE> U8C1; typedef ImageFormat<2, GL_R16I, GL_RED_INTEGER, GL_SHORT> S16C1; typedef ImageFormat<2, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT> U16C1; typedef ImageFormat<4, GL_R32F, GL_RED, GL_FLOAT> F32C1; typedef ImageFormat<8, GL_RG32F, GL_RG, GL_FLOAT> F32C2; typedef ImageFormat<12, GL_RGB32F, GL_RGB, GL_FLOAT> F32C3; typedef ImageFormat<4, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE> F8C4; typedef ImageFormat<16, GL_RGBA32F, GL_RGBA, GL_FLOAT> F32C4; template struct Texture : public WithOpenGLBindings { protected: size_t bytes_per_pixel, height, width; public: GLuint texture; unsigned char *data; size_t size; Texture() : bytes_per_pixel(FormatT::BytesPerPixel), height(0), width(0), texture(0), data(0), size(0) { } void bindToUnit(GLenum unit) { gl()->glActiveTexture(unit); glBindTexture(GL_TEXTURE_RECTANGLE, texture); } void allocate(size_t new_width, size_t new_height) { width = new_width; height = new_height; size = height * width * bytes_per_pixel; data = new unsigned char[size]; glGenTextures(1, &texture); bindToUnit(GL_TEXTURE0); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_RECTANGLE, 0, FormatT::InternalFormat, width, height, 0, FormatT::Format, FormatT::Type, 0); } void deallocate() { glDeleteTextures(1, &texture); delete[] data; } void upload() { bindToUnit(GL_TEXTURE0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexSubImage2D(GL_TEXTURE_RECTANGLE, /*level*/0, /*xoffset*/0, /*yoffset*/0, width, height, FormatT::Format, FormatT::Type, data); } void download() { downloadToBuffer(data); } void downloadToBuffer(unsigned char *data) { glReadPixels(0, 0, width, height, FormatT::Format, FormatT::Type, data); } void flipY() { flipYBuffer(data); } void flipYBuffer(unsigned char *data) { typedef unsigned char type; size_t linestep = width * bytes_per_pixel / sizeof(type); type *first_line = reinterpret_cast(data), *last_line = reinterpret_cast(data) + (height - 1) * linestep; for (size_t y = 0; y < height / 2; ++y) { for (size_t x = 0; x < linestep; ++x, ++first_line, ++last_line) { std::swap(*first_line, *last_line); } last_line -= 2 * linestep; } } libfreenect2::Frame *downloadToNewFrame() { libfreenect2::Frame *f = new libfreenect2::Frame(width, height, bytes_per_pixel); downloadToBuffer(f->data); flipYBuffer(f->data); return f; } }; struct ShaderProgram : public WithOpenGLBindings { GLuint program, vertex_shader, fragment_shader; char error_buffer[2048]; ShaderProgram() : program(0), vertex_shader(0), fragment_shader(0) { } void setVertexShader(const std::string& src) { const char* src_ = src.c_str(); int length_ = src.length(); vertex_shader = gl()->glCreateShader(GL_VERTEX_SHADER); gl()->glShaderSource(vertex_shader, 1, &src_, &length_); } void setFragmentShader(const std::string& src) { const char* src_ = src.c_str(); int length_ = src.length(); fragment_shader = gl()->glCreateShader(GL_FRAGMENT_SHADER); gl()->glShaderSource(fragment_shader, 1, &src_, &length_); } void build() { GLint status; gl()->glCompileShader(vertex_shader); gl()->glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { gl()->glGetShaderInfoLog(vertex_shader, sizeof(error_buffer), NULL, error_buffer); std::cerr << "failed to compile vertex shader!" << std::endl << error_buffer << std::endl; } gl()->glCompileShader(fragment_shader); gl()->glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { gl()->glGetShaderInfoLog(fragment_shader, sizeof(error_buffer), NULL, error_buffer); std::cerr << "failed to compile fragment shader!" << std::endl << error_buffer << std::endl; } program = gl()->glCreateProgram(); gl()->glAttachShader(program, vertex_shader); gl()->glAttachShader(program, fragment_shader); gl()->glLinkProgram(program); gl()->glGetProgramiv(program, GL_LINK_STATUS, &status); if (status != GL_TRUE) { gl()->glGetProgramInfoLog(program, sizeof(error_buffer), NULL, error_buffer); std::cerr << "failed to link shader program!" << std::endl << error_buffer << std::endl; } } GLint getAttributeLocation(const std::string& name) { return gl()->glGetAttribLocation(program, name.c_str()); } void setUniform(const std::string& name, GLint value) { GLint idx = gl()->glGetUniformLocation(program, name.c_str()); if (idx == -1) return; gl()->glUniform1i(idx, value); } void setUniform(const std::string& name, GLfloat value) { GLint idx = gl()->glGetUniformLocation(program, name.c_str()); if (idx == -1) return; gl()->glUniform1f(idx, value); } void setUniformVector3(const std::string& name, GLfloat value[3]) { GLint idx = gl()->glGetUniformLocation(program, name.c_str()); if (idx == -1) return; gl()->glUniform3fv(idx, 1, value); } void setUniformMatrix3(const std::string& name, GLfloat value[9]) { GLint idx = gl()->glGetUniformLocation(program, name.c_str()); if (idx == -1) return; gl()->glUniformMatrix3fv(idx, 1, false, value); } void use() { gl()->glUseProgram(program); } }; class Viewer : WithOpenGLBindings { private: bool shouldStop; GLFWwindow* window; GLuint triangle_vbo, triangle_vao; ShaderProgram renderShader; ShaderProgram renderGrayShader; std::string shader_folder; std::map frames; Texture rgb; Texture ir; int win_width; int win_height; public: Viewer(); void initialize(); virtual void onOpenGLBindingsChanged(OpenGLBindings *b); bool render(); void addFrame(std::string id,libfreenect2::Frame* frame); void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); void winsize_callback(GLFWwindow* window, int w, int h); static void key_callbackstatic(GLFWwindow* window, int key, int scancode, int action, int mods); static void winsize_callbackstatic(GLFWwindow* window, int w, int h); }; #endif