X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=vrfileman;a=blobdiff_plain;f=src%2Frtarg.cc;fp=src%2Frtarg.cc;h=84a91423b12142651831b04caef3bdda9e7b4eb6;hp=0000000000000000000000000000000000000000;hb=7c59a70219aa7bcf80291f41903a9e6fc9b6e073;hpb=5e07bfd4d034dc3d974c8db008c6446e62838d39 diff --git a/src/rtarg.cc b/src/rtarg.cc new file mode 100644 index 0000000..84a9142 --- /dev/null +++ b/src/rtarg.cc @@ -0,0 +1,262 @@ +#include "rtarg.h" +#include "texture.h" +#include "app.h" + +unsigned int RenderTarget::default_fbo = 0; + +RenderTarget::RenderTarget() +{ + width = height = 0; + fbo = 0; + rbuf_zstencil = 0; + color_tex = 0; + tex_face = 0; + tex_targ = 0; +} + +RenderTarget::~RenderTarget() +{ + cleanup(); +} + +bool RenderTarget::create(unsigned int fmt) +{ + return create(win_width, win_height, fmt); +} + +bool RenderTarget::create(int width, int height, unsigned int fmt) +{ + fprintf(stderr, "RenderTarget::create(%d, %d)\n", width, height); + cleanup(); + + tex_targ = GL_TEXTURE_2D; + this->width = width; + this->height = height; + int tex_width = next_pow2(width); + int tex_height = next_pow2(height); + + tex_matrix.scaling((float)width / (float)tex_width, (float)height / (float)tex_height, 1.0); + + color_tex = new Texture2D; + color_tex->create(tex_width, tex_height, fmt); + tex_face = 0; + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glBindTexture(GL_TEXTURE_2D, color_tex->get_id()); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex->get_id(), 0); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenRenderbuffers(1, &rbuf_zstencil); + glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil); +#ifdef GL_ES_VERSION_2_0 + // XXX really? 16bit zbuffer attachment is the best we can do on ES2? + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, tex_width, tex_height); +#else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height); +#endif + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); +#ifndef GL_ES_VERSION_2_0 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); +#endif + + glBindFramebuffer(GL_FRAMEBUFFER, RenderTarget::default_fbo); + return true; +} + +bool RenderTarget::create(Texture *tex, int face) +{ + fprintf(stderr, "RenderTarget::create(tex{%d, %d}, face:%d)\n", tex->get_size(0), + tex->get_size(1), face); + + tex_targ = GL_TEXTURE_2D; + if(dynamic_cast(tex)) { + if(face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { + tex_targ = face; + } else if(face >= 0 && face < 6) { + tex_targ = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + } else { + fprintf(stderr, "invalid face (%d) passed to RenderTarget::create(TextureCube*, int)\n", face); + return false; + } + } + + cleanup(); + + width = tex->get_size(0); + height = tex->get_size(1); + + tex_matrix = Mat4::identity; + + color_tex = tex; + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glBindTexture(tex_targ, color_tex->get_id()); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0); + glBindTexture(tex_targ, 0); + + glGenRenderbuffers(1, &rbuf_zstencil); + glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); + + glBindFramebuffer(GL_FRAMEBUFFER, RenderTarget::default_fbo); + return true; +} + +void RenderTarget::cleanup() +{ + delete color_tex; + color_tex = 0; + + if(fbo) { + glDeleteFramebuffers(1, &fbo); + } + if(rbuf_zstencil) { + glDeleteRenderbuffers(1, &rbuf_zstencil); + } + + fbo = rbuf_zstencil = 0; + width = height = 0; + tex_face = 0; + tex_targ = 0; +} + +bool RenderTarget::resize(int width, int height) +{ + if(width == this->width && height == this->height) { + return true; + } + + int tex_width = next_pow2(width); + int tex_height = next_pow2(height); + this->width = width; + this->height = height; + + if(tex_width != color_tex->get_size(0) || tex_height != color_tex->get_size(1)) { + printf("resizing render target (fbo %u): %dx%d [%dx%d]\n", fbo, width, height, tex_width, tex_height); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + color_tex->create(tex_width, tex_height, color_tex->get_format()); + color_tex->bind(); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0); + glBindTexture(tex_targ, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil); + + unsigned int depth_format; +#ifndef GL_ES_VERSION_2_0 + // desktop OpenGL, use typical depth24-stencil8 format + depth_format = GL_DEPTH24_STENCIL8; +#else // OpenGL ES + // OpenGL ES provides combined depth/stencil formats as an extension +#ifdef GL_OES_packed_depth_stencil + if(have_ext_packed_depth_stencil) { + depth_format = GL_DEPTH24_STENCIL8_OES; + } else +#endif // GL_OES_packed_depth_stencil + { + depth_format = GL_DEPTH_COMPONENT16; // no compile-time or runtime support for packed d/s + } +#endif // GL_ES_VERSION_2_0 + glRenderbufferStorage(GL_RENDERBUFFER, depth_format, tex_width, tex_height); + + glBindFramebuffer(GL_FRAMEBUFFER, RenderTarget::default_fbo); + } + + tex_matrix.scaling((float)width / (float)tex_width, (float)height / (float)tex_height, 1.0); + return true; +} + +int RenderTarget::get_width() const +{ + return width; +} + +int RenderTarget::get_height() const +{ + return height; +} + +Texture *RenderTarget::get_texture() const +{ + return color_tex; +} + +const Mat4 &RenderTarget::get_texture_matrix() const +{ + return tex_matrix; +} + + +static const char *fbstname[] = { + "GL_FRAMEBUFFER_COMPLETE", + "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", + "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", + "no such fbo error", + "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS", + "GL_FRAMEBUFFER_INCOMPLETE_FORMATS", + "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER", + "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER", + "GL_FRAMEBUFFER_UNSUPPORTED" +}; + +bool RenderTarget::check() const +{ + bool res = true; + +#ifndef GL_ES_VERSION_2_0 + int prev_fb = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prev_fb); +#endif + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + int status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if(status != GL_FRAMEBUFFER_COMPLETE) { + fprintf(stderr, "RenderTarget::check: incomplete FBO %u: %s\n", fbo, + fbstname[status - GL_FRAMEBUFFER_COMPLETE]); + res = false; + goto end; + } + +end: +#ifndef GL_ES_VERSION_2_0 + glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); +#endif + return res; +} + +void RenderTarget::bind() const +{ + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glViewport(0, 0, width, height); +} + +void set_render_target(const RenderTarget *rtarg) +{ + if(rtarg) { + rtarg->bind(); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, RenderTarget::default_fbo); + glViewport(0, 0, win_width, win_height); + } +} + +int next_pow2(int x) +{ + x--; + x = (x >> 1) | x; + x = (x >> 2) | x; + x = (x >> 4) | x; + x = (x >> 8) | x; + x = (x >> 16) | x; + return x + 1; +} +