/**************************************************************************** * 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 $ Revision 1.1 2007/07/26 16:22:47 m_di_benedetto First Commit. ****************************************************************************/ #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 + ((GLenum)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