diff --git a/wrap/gl/gl_surface.h b/wrap/gl/gl_surface.h new file mode 100644 index 00000000..148e64cc --- /dev/null +++ b/wrap/gl/gl_surface.h @@ -0,0 +1,533 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +/**************************************************************************** + History + +$Log: not supported by cvs2svn $ + + +****************************************************************************/ + +#ifndef VCGLIB_GL_SURFACE_H +#define VCGLIB_GL_SURFACE_H + +#include +#include + +namespace vcg +{ + +/**************************************************************************** +The gl_surface class simplify the render-to-texture OpenGL functionality. + +It provides a framebuffer composed of single or multiple color buffers and +a depth buffer; color-only and depth-only framebuffers can also be created. + +Sample usage: + +**************************************************************** +// *** declaration + +gl_surface my_srf; + + +*********************** +// *** initialization: single color render target, with depth buffer +{ + std::vector color_formats; + color_formats.push_back(GL_RGBA8); + + my_srf.set(width, height, color_formats, GL_DEPTH_COMPONENT); +} +*********************** + + +*********************** +// *** initialization: two color render targets, without depth buffer +// NOTE: the maximum number of color targets is implementation dependent. +// NOTE: DX10 class hardware allows different formats for each color target. +{ + std::vector color_formats; + color_formats.push_back(GL_RGBA8); + color_formats.push_back(GL_RGBA8); + + my_srf.set(width, height, color_formats, GL_NONE); +} +*********************** + + +*********************** +// *** usage: render-to-targets +{ + my_srf.begin_write(); + application_draw_code(); + my_srf.end_write(); +} +*********************** + + +*********************** +// *** usage: using rendered textures +{ + // 2 buffers + + // bind the second + glActiveTexture(GL_TEXTURE1); + my_srf.begin_read_color(1); // actually does a glBindTexture(); + + // bind the first + glActiveTexture(GL_TEXTURE0); + my_srf.begin_read_color(0); + + application_draw_code(); + + // unbind the second + glActiveTexture(GL_TEXTURE1); + my_srf.end_read_color(1); + + // unbind first + glActiveTexture(GL_TEXTURE0); + my_srf.end_read_color(0); +} + +*********************** +// *** usage: use depth map +{ + my_srf.begin_read_depth(); + + // use depth map here + application_draw_code(); + + my_srf.end_read_depth(); +} + +*********************** +// *** usage: cleanup +{ + my_srf.clear(); + // clear() is also safely called in the destructor. +} +*********************** + +Other commodity methods for getting/setting pixels are also provided. + +****************************************************************************/ + +class gl_surface +{ + public: + + typedef gl_surface this_type; + + gl_surface(void) : width(0), height(0), depth_tex(0), fb(0) + { + ; + } + + ~gl_surface(void) + { + this->clear(); + } + + bool set(int width, int height, const std::vector & color_formats, GLenum depth_format) + { + this->clear(); + + this->width = width; + this->height = height; + + this->color_formats = color_formats; + + this->color_texs.resize(color_formats.size()); + + for (size_t i=0; icolor_texs.size(); ++i) + { + glGenTextures (1, &(this->color_texs[i])); + glBindTexture (GL_TEXTURE_2D, this->color_texs[i]); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D (GL_TEXTURE_2D, 0, this->color_formats[i], this->width, this->height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); + } + + this->depth_format = depth_format; + if (this->depth_format != GL_NONE) + { + glGenTextures (1, &(this->depth_tex)); + glBindTexture (GL_TEXTURE_2D, this->depth_tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + glTexImage2D (GL_TEXTURE_2D, 0, this->depth_format, this->width, this->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0); + } + + glGenFramebuffersEXT(1, &(this->fb)); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->fb); + + std::vector sites(this->color_texs.size()); + for (size_t i=0; icolor_texs.size(); ++i) + { + sites[i] = GL_COLOR_ATTACHMENT0_EXT + i; + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, sites[i], GL_TEXTURE_2D, this->color_texs[i], 0); + } + + if (this->depth_format != GL_NONE) + { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, this->depth_tex, 0); + } + + if (!sites.empty()) + { + glDrawBuffers((GLsizei)(sites.size()), &(sites[0])); + } + + const GLenum s = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + const bool res = (s == GL_FRAMEBUFFER_COMPLETE_EXT); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + if (!res) + { + glDeleteFramebuffersEXT(1, &(this->fb)); + this->fb = 0; + + for (size_t i=0; icolor_texs.size(); ++i) + { + glDeleteTextures(1, &(this->color_texs[i])); + } + this->color_texs.clear(); + + this->color_formats.clear(); + + if (this->depth_tex != 0) + { + glDeleteTextures(1, &(this->depth_tex)); + this->depth_tex = 0; + } + + this->width = 0; + this->height = 0; + + return false; + } + + return true; + } + + bool set_simple(int width, int height) + { + std::vector c_formats; + c_formats.push_back(GL_RGBA8); + + return this->set(width, height, c_formats, GL_DEPTH_COMPONENT); + } + + bool set_color_only(int width, int height, GLenum color_format) + { + std::vector c_formats; + c_formats.push_back(color_format); + + return this->set(width, height, c_formats, GL_NONE); + } + + bool set_color_only(int width, int height, const std::vector & color_formats) + { + return this->set(width, height, color_formats, GL_NONE); + } + + bool set_depth_only(int width, int height, GLenum depth_format) + { + std::vector c_formats; + + return this->set(width, height, c_formats, depth_format); + } + + bool clear(void) + { + if (!this->is_valid()) return false; + + glDeleteFramebuffersEXT(1, &(this->fb)); + this->fb = 0; + + for (size_t i=0; icolor_texs.size(); ++i) + { + glDeleteTextures(1, &(this->color_texs[i])); + } + this->color_texs.clear(); + + this->color_formats.clear(); + + if (this->depth_tex != 0) + { + glDeleteTextures(1, &(this->depth_tex)); + this->depth_tex = 0; + } + + this->width = 0; + this->height = 0; + + return true; + } + + bool is_valid(void) const + { + return (this->fb != 0); + } + + int get_width(void) const + { + return this->width; + } + + int get_height(void) const + { + return this->height; + } + + int color_attachments_count(void) const + { + return ((int)(this->color_texs.size())); + } + + GLenum get_color_attachment_format(int attachment) const + { + if (!this->is_valid()) return GL_NONE; + if ((attachment < 0) || (attachment >= this->color_attachments_count())) return GL_NONE; + + return this->color_formats[attachment]; + } + + bool has_depth_attachment(void) const + { + return (this->depth_tex != 0); + } + + GLenum get_depth_attachment_format(void) const + { + if (!this->is_valid()) return GL_NONE; + if (!this->has_depth_attachment()) return GL_NONE; + + return this->depth_format; + } + + bool set_color_pixels(int attachment, GLenum format, GLenum type, const void * pixels) + { + if (!this->begin_read_color(attachment)) return false; + + glTexImage2D(GL_TEXTURE_2D, 0, this->color_formats[attachment], this->width, this->height, 0, format, type, pixels); + + this->end_read_color(attachment); + + return true; + } + + bool get_color_pixels(int attachment, GLenum format, GLenum type, void * pixels) + { + if (!this->begin_read_color(attachment)) return false; + + glGetTexImage(GL_TEXTURE_2D, 0, format, type, pixels); + + this->end_read_color(attachment); + + return true; + } + + bool set_depth_pixels(GLenum format, GLenum type, const void * pixels) + { + if (!this->is_valid()) return false; + if (!this->has_depth_attachment()) return false; + + glTexImage2D(GL_TEXTURE_2D, 0, this->depth_format, this->width, this->height, 0, format, type, pixels); + + return true; + } + + bool get_depth_pixels(GLenum format, GLenum type, void * pixels) + { + if (!this->begin_read_depth()) return false; + + glGetTexImage(GL_TEXTURE_2D, 0, format, type, pixels); + + this->end_read_depth(); + + return true; + } + + bool begin_read_color(int attachment) + { + if (!this->is_valid()) return false; + if ((attachment < 0) || (attachment >= this->color_attachments_count())) return false; + + glBindTexture(GL_TEXTURE_2D, this->color_texs[attachment]); + + return true; + } + + bool end_read_color(int attachment) + { + if (!this->is_valid()) return false; + if ((attachment < 0) || (attachment >= this->color_attachments_count())) return false; + + glBindTexture(GL_TEXTURE_2D, 0); + + return true; + } + + bool begin_read_depth(void) + { + if (!this->is_valid()) return false; + if (!this->has_depth_attachment()) return false; + + glBindTexture(GL_TEXTURE_2D, this->depth_tex); + + return true; + } + + bool end_read_depth(void) + { + if (!this->is_valid()) return false; + if (!this->has_depth_attachment()) return false; + + glBindTexture(GL_TEXTURE_2D, 0); + + return true; + } + + bool begin_write(void) + { + if (!this->is_valid()) return false; + + glPushAttrib(GL_VIEWPORT_BIT); + + glViewport(0, 0, this->width, this->height); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->fb); + + return true; + } + + bool end_write(void) + { + if (!this->is_valid()) return false; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + glPopAttrib(); + + return true; + } + + bool draw_color_attachment(int x, int y, int width, int height, int attachment) + { + if (!this->is_valid()) return false; + if ((attachment < 0) || (attachment >= this->color_attachments_count())) return false; + + glPushAttrib(GL_ALL_ATTRIB_BITS); + + glViewport(x, y, width, height); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + this->begin_read_color(attachment); + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f); + glEnd(); + this->end_read_color(attachment); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glPopAttrib(); + } + + bool draw_depth_attachment(int x, int y, int width, int height) + { + if (!this->is_valid()) return false; + if (!this->has_depth_attachment()) return false; + + glPushAttrib(GL_ALL_ATTRIB_BITS); + + glViewport(x, y, width, height); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + this->begin_read_depth(); + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f); + glEnd(); + this->end_read_depth(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glPopAttrib(); + } + + protected: + + int width; + int height; + std::vector color_formats; + std::vector color_texs; + GLenum depth_format; + GLuint depth_tex; + GLuint fb; +}; + +} // end namespace vcg + +#endif // VCGLIB_GL_SURFACE_H