simple ubershader system, reflection debugging
[laserbrain_demo] / src / renderer.cc
index bb274f2..deff1b9 100644 (file)
@@ -1,16 +1,65 @@
 #include "renderer.h"
+#include "rtarg.h"
+#include "app.h"
+#include "sdr.h"
+
+enum {
+       USE_TEXMAP = 1,
+       USE_MIRROR = 2,
+};
+static const char *use_flag_str[] = {
+       "#define USE_TEXMAP\n",
+       "#define USE_MIRROR\n"
+};
+#define NUM_USE_FLAGS  ((int)(sizeof use_flag_str / sizeof *use_flag_str))
+
+
+static RenderTarget *rtmirror;
 
 Renderer::Renderer()
 {
        mscn = 0;
+       ropt = RENDER_ALL;
+       shaders = 0;
 }
 
 Renderer::~Renderer()
 {
+       destroy();
+       delete [] shaders;
 }
 
 bool Renderer::init()
 {
+       static bool once;
+       if(!rtmirror && !once) {
+               once = true;
+               rtmirror = new RenderTarget;
+               if(!rtmirror->create(vp_width, vp_height, GL_SRGB)) {
+                       error_log("failed to create mirror render target (%dx%d)\n", vp_width, vp_height);
+               }
+       }
+
+       int numsdr = 1 << NUM_USE_FLAGS;
+       shaders = new unsigned int[numsdr];
+
+       for(int i=0; i<numsdr; i++) {
+               clear_shader_header(0);
+
+               for(int j=0; j<NUM_USE_FLAGS; j++) {
+                       if(i & (1 << j)) {
+                               add_shader_header(0, use_flag_str[j]);
+                       }
+               }
+
+               if(!(shaders[i] = create_program_load("sdr/lightmap.v.glsl", "sdr/lightmap.p.glsl"))) {
+                       return false;
+               }
+               set_uniform_int(shaders[i], "texmap", MTL_TEX_DIFFUSE);
+               set_uniform_int(shaders[i], "lightmap", MTL_TEX_LIGHTMAP);
+               set_uniform_int(shaders[i], "mirrortex", MTL_TEX_REFLECT);
+       }
+
        return true;
 }
 
@@ -28,16 +77,43 @@ MetaScene *Renderer::get_scene() const
        return mscn;
 }
 
+// render mirror reflections if ...
+#define DO_MIRRORS     \
+       mscn->mirrors &&                        /* scene contains mirrors */ \
+       (ropt & RENDER_MIRRORS) &&      /* mirror rendering is enabled */ \
+       rtmirror                                        /* mirror render target succesfully created */
+
 void Renderer::draw() const
 {
        if(!mscn) return;
 
+       if(DO_MIRRORS && current_render_target() != rtmirror) {
+               // check if the render target needs resizing
+               if(rtmirror->get_width() != vp_width || rtmirror->get_height() != vp_height) {
+                       if(!rtmirror->resize(vp_width, vp_height)) {
+                               error_log("failed to resize mirror render target (%dx%d)\n", vp_width, vp_height);
+                               goto abort_mirrors;
+                       }
+               }
+
+               FlatMirror *mir = mscn->mirrors;
+               while(mir) {
+                       draw_mirror(mir);
+                       mir = mir->next;
+               }
+       }
+abort_mirrors:
+
        int num = (int)mscn->scenes.size();
        for(int i=0; i<num; i++) {
                Scene *scn = mscn->scenes[i];
 
                int nobj = (int)scn->objects.size();
                for(int j=0; j<nobj; j++) {
+                       // don't draw mirrors, we already did that earlier (if mirror rendering enabled)
+                       if((ropt & RENDER_MIRRORS) && scn->objects[j]->mtl.flat_mirror) {
+                               continue;
+                       }
                        draw_object(scn->objects[j]);
                }
        }
@@ -56,6 +132,64 @@ void Renderer::draw_object(Object *obj) const
        }
 
        if(vis) {
+               unsigned int use_mask = 0;
+               if(obj->mtl.stdtex[MTL_TEX_DIFFUSE]) {
+                       use_mask |= USE_TEXMAP;
+               }
+               if(obj->mtl.stdtex[MTL_TEX_REFLECT] && obj->mtl.flat_mirror) {
+                       use_mask |= USE_MIRROR;
+               }
+
+               unsigned int sdr = shaders[use_mask];
+               if(use_mask & USE_MIRROR) {
+                       float sx = 1.0f / rtmirror->texture()->get_width();
+                       float sy = 1.0f / rtmirror->texture()->get_height();
+                       set_uniform_float2(sdr, "mirtex_scale", sx, sy);
+                       set_uniform_float(sdr, "reflectivity", obj->mtl.reflect);
+               }
+               bind_program(sdr);
+
                obj->draw();
        }
 }
+
+void Renderer::draw_mirror(FlatMirror *mir) const
+{
+       push_render_target(rtmirror);
+       glClearColor(1, 0, 0, 1);
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       glClearColor(1, 1, 1, 1);
+
+       glMatrixMode(GL_MODELVIEW);
+       glPushMatrix();
+
+       // TODO update mirror plane for movable mirrors?
+
+       Mat4 mirmat;
+       mirmat.mirror(mir->wplane.normal, dot(mir->wplane.normal, mir->wplane.pt));
+       glMultMatrixf(mirmat[0]);
+
+       glFrontFace(GL_CW);
+       draw();
+       glFrontFace(GL_CCW);
+
+       glPopMatrix();
+       pop_render_target();
+
+       if(dbg_key_pending & 1) {
+               dump_gl_texture(rtmirror->texture()->get_id(), "mirror.ppm");
+               dbg_key_pending &= ~1;
+       }
+
+       int nobj = mir->objects.size();
+       for(int i=0; i<nobj; i++) {
+               Object *obj = (Object*)mir->objects[i];
+
+               Texture *prev_refl_tex = obj->mtl.stdtex[MTL_TEX_REFLECT];
+               obj->mtl.stdtex[MTL_TEX_REFLECT] = rtmirror->texture();
+
+               draw_object(mir->objects[i]);
+
+               obj->mtl.stdtex[MTL_TEX_REFLECT] = prev_refl_tex;
+       }
+}