fixed reflections in VR
[laserbrain_demo] / src / rtarg.cc
index f90c1d3..8a232b0 100644 (file)
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include "rtarg.h"
 
 struct RTStackItem {
@@ -33,7 +34,7 @@ RenderTarget *current_render_target()
        return rstack[rtop].rt;
 }
 
-bool push_render_target(RenderTarget *rt)
+bool push_render_target(RenderTarget *rt, unsigned int flags)
 {
        if(!rt) {
                error_log("push_render_target(0) is invalid\n");
@@ -43,34 +44,39 @@ bool push_render_target(RenderTarget *rt)
                warning_log("push_render_target: overflow\n");
                return false;
        }
-       int *vp = rstack[rtop + 1].saved_vp;
-       RenderTarget *prev = current_render_target();
 
-       if(prev) {
-               vp[0] = vp[1] = 0;
-               vp[2] = prev->get_width();
-               vp[3] = prev->get_height();
-       } else {
-               memcpy(vp, rstack[rtop].saved_vp, 4 * sizeof(int));
+       if(!(flags & RT_NO_VPORT)) {
+               int *vp = rstack[rtop + 1].saved_vp;
+               glGetIntegerv(GL_VIEWPORT, vp);
        }
        rstack[++rtop].rt = rt;
+
+       if(!(flags & RT_NO_BIND)) {
+               rt->bind();
+       }
        return true;
 }
 
-bool pop_render_target()
+bool pop_render_target(unsigned int flags)
 {
        if(rtop <= 0) {
-               error_log("pop_render_target: undeflow\n");
+               error_log("pop_render_target: underflow\n");
                return false;
        }
 
-       int *vp = rstack[rtop].saved_vp;
-       glViewport(vp[0], vp[1], vp[2], vp[3]);
+       if(!(flags & RT_NO_VPORT)) {
+               int *vp = rstack[rtop].saved_vp;
+               glViewport(vp[0], vp[1], vp[2], vp[3]);
+       }
+
+       --rtop;
 
-       if(rstack[--rtop].rt) {
-               rstack[rtop].rt->bind();
-       } else {
-               glBindFramebuffer(GL_FRAMEBUFFER, 0);
+       if(!(flags & RT_NO_BIND)) {
+               if(rstack[rtop].rt) {
+                       rstack[rtop].rt->bind(RT_NO_VPORT);
+               } else {
+                       glBindFramebuffer(GL_FRAMEBUFFER, 0);
+               }
        }
        return true;
 }
@@ -79,14 +85,17 @@ RenderTarget::RenderTarget()
 {
        fbo = 0;
        rbdepth = 0;
+       rbdepth_fmt = 0;
        width = height = tex_width = tex_height = 0;
        auto_vport = true;
        rtcount = 0;
 
+       own_fbo = true;
        for(int i=0; i<4; i++) {
                tex[i] = 0;
                own_texture[i] = true;
        }
+       depth = 0;
 }
 
 RenderTarget::~RenderTarget()
@@ -103,6 +112,7 @@ bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsig
 {
        glGenFramebuffers(1, &fbo);
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+       own_fbo = true;
 
        width = xsz;
        height = ysz;
@@ -118,6 +128,7 @@ bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsig
                        tex[i]->create(tex_width, tex_height, TEX_2D, fmt);
                        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
                                        tex[i]->get_id(), 0);
+                       glBindTexture(GL_TEXTURE_2D, 0);
                        own_texture[i] = true;
                }
        } else {
@@ -131,30 +142,31 @@ bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsig
        }
 
        if(flags & (RT_DEPTH | RT_STENCIL)) {
-               unsigned int fmt, attachment;
+               unsigned int attachment;
 
                glGenRenderbuffers(1, &rbdepth);
                glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
 
                switch(flags & (RT_DEPTH | RT_STENCIL)) {
                case RT_DEPTH:
-                       fmt = GL_DEPTH_COMPONENT24;
+                       rbdepth_fmt = GL_DEPTH_COMPONENT24;
                        attachment = GL_DEPTH_ATTACHMENT;
                        break;
 
                case RT_STENCIL:
-                       fmt = GL_STENCIL_INDEX8;
+                       rbdepth_fmt = GL_STENCIL_INDEX8;
                        attachment = GL_STENCIL_ATTACHMENT;
                        break;
 
                case RT_DEPTH | RT_STENCIL:
-                       fmt = GL_DEPTH24_STENCIL8;
+                       rbdepth_fmt = GL_DEPTH24_STENCIL8;
                        attachment = GL_DEPTH_STENCIL_ATTACHMENT;
                        break;
                }
 
-               glRenderbufferStorage(GL_RENDERBUFFER, fmt, width, height);
+               glRenderbufferStorage(GL_RENDERBUFFER, rbdepth_fmt, width, height);
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbdepth);
+               glBindRenderbuffer(GL_RENDERBUFFER, 0);
 
        } else if(depth) {
                attach_depth_texture(depth);
@@ -164,6 +176,20 @@ bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsig
        return true;
 }
 
+bool RenderTarget::create_wrap_fbo(unsigned int fbo, int xsz, int ysz)
+{
+       this->fbo = fbo;
+       own_fbo = false;
+
+       width = tex_width = xsz;
+       height = tex_height = ysz;
+       rtcount = 1;
+
+       texmat = Mat4::identity;
+
+       return true;
+}
+
 void RenderTarget::destroy()
 {
        for(int i=0; i<4; i++) {
@@ -176,12 +202,44 @@ void RenderTarget::destroy()
                glDeleteRenderbuffers(1, &rbdepth);
                rbdepth = 0;
        }
-       if(fbo) {
+       if(fbo && own_fbo) {
                glDeleteFramebuffers(1, &fbo);
                fbo = 0;
        }
 }
 
+bool RenderTarget::resize(int xsz, int ysz)
+{
+       if(!own_fbo) return false;      /* TODO */
+
+       int new_tx = next_pow2(xsz);
+       int new_ty = next_pow2(ysz);
+
+       if(new_tx != tex_width || new_ty != tex_height) {
+               tex_width = new_tx;
+               tex_height = new_ty;
+
+               for(int i=0; i<4; i++) {
+                       if(tex[i]) {
+                               tex[i]->create(new_tx, new_ty, TEX_2D, tex[i]->get_format());
+                       }
+               }
+
+               if(depth) {
+                       depth->create(new_tx, new_ty, TEX_2D, depth->get_format());
+               }
+       }
+
+       if(rbdepth) {
+               glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
+               glRenderbufferStorage(GL_RENDERBUFFER, rbdepth_fmt, xsz, ysz);
+       }
+
+       width = xsz;
+       height = ysz;
+       return true;
+}
+
 int RenderTarget::get_width() const
 {
        return width;
@@ -239,11 +297,11 @@ bool RenderTarget::auto_viewport() const
        return auto_vport;
 }
 
-void RenderTarget::bind() const
+void RenderTarget::bind(unsigned int flags) const
 {
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 
-       if(auto_vport) {
+       if(auto_vport && !(flags & RT_NO_VPORT)) {
                glViewport(0, 0, width, height);
        }
 }
@@ -282,7 +340,7 @@ static void attach_depth_texture(Texture *tex)
 
        default:
                error_log("failed to attach depth/stencil texture: unexpected texture format: %x\n", fmt);
-               break;
+               return;
        }
 
        glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex->get_id(), 0);