fixed reflections in VR
[laserbrain_demo] / src / renderer.cc
1 #include "renderer.h"
2 #include "rtarg.h"
3 #include "app.h"
4 #include "sdr.h"
5
6 enum {
7         USE_TEXMAP = 1,
8         USE_MIRROR = 2,
9 };
10 static const char *use_flag_str[] = {
11         "#define USE_TEXMAP\n",
12         "#define USE_MIRROR\n"
13 };
14 #define NUM_USE_FLAGS   ((int)(sizeof use_flag_str / sizeof *use_flag_str))
15
16
17 static RenderTarget *rtmirror;
18 static int cur_vport[4];
19
20 Renderer::Renderer()
21 {
22         mscn = 0;
23         ropt = RENDER_ALL;
24         shaders = 0;
25 }
26
27 Renderer::~Renderer()
28 {
29         destroy();
30         delete [] shaders;
31 }
32
33 bool Renderer::init()
34 {
35         static bool once;
36         if(!rtmirror && !once) {
37                 once = true;
38                 rtmirror = new RenderTarget;
39                 if(!rtmirror->create(vp_width, vp_height, GL_SRGB)) {
40                         error_log("failed to create mirror render target (%dx%d)\n", vp_width, vp_height);
41                 }
42         }
43
44         int numsdr = 1 << NUM_USE_FLAGS;
45         shaders = new unsigned int[numsdr];
46
47         for(int i=0; i<numsdr; i++) {
48                 clear_shader_header(0);
49
50                 for(int j=0; j<NUM_USE_FLAGS; j++) {
51                         if(i & (1 << j)) {
52                                 add_shader_header(0, use_flag_str[j]);
53                         }
54                 }
55
56                 if(!(shaders[i] = create_program_load("sdr/lightmap.v.glsl", "sdr/lightmap.p.glsl"))) {
57                         return false;
58                 }
59                 set_uniform_int(shaders[i], "texmap", MTL_TEX_DIFFUSE);
60                 set_uniform_int(shaders[i], "lightmap", MTL_TEX_LIGHTMAP);
61                 set_uniform_int(shaders[i], "mirrortex", MTL_TEX_REFLECT);
62         }
63
64         return true;
65 }
66
67 void Renderer::destroy()
68 {
69 }
70
71 void Renderer::set_scene(MetaScene *mscn)
72 {
73         this->mscn = mscn;
74 }
75
76 MetaScene *Renderer::get_scene() const
77 {
78         return mscn;
79 }
80
81 // render mirror reflections if ...
82 #define DO_MIRRORS      \
83         mscn->mirrors &&                        /* scene contains mirrors */ \
84         (ropt & RENDER_MIRRORS) &&      /* mirror rendering is enabled */ \
85         rtmirror                                        /* mirror render target succesfully created */
86
87 void Renderer::draw() const
88 {
89         if(!mscn) return;
90
91         if(DO_MIRRORS && current_render_target() != rtmirror) {
92                 // check if the render target needs resizing
93                 if(rtmirror->get_width() != vp_width || rtmirror->get_height() != vp_height) {
94                         info_log("resizing mirror render target to %dx%d\n", vp_width, vp_height);
95                         if(!rtmirror->resize(vp_width, vp_height)) {
96                                 error_log("failed to resize mirror render target (%dx%d)\n", vp_width, vp_height);
97                                 goto abort_mirrors;
98                         }
99                 }
100
101                 glGetIntegerv(GL_VIEWPORT, cur_vport);
102
103                 FlatMirror *mir = mscn->mirrors;
104                 while(mir) {
105                         draw_mirror(mir);
106                         mir = mir->next;
107                 }
108         }
109 abort_mirrors:
110
111         int num = (int)mscn->scenes.size();
112         for(int i=0; i<num; i++) {
113                 Scene *scn = mscn->scenes[i];
114
115                 int nobj = (int)scn->objects.size();
116                 for(int j=0; j<nobj; j++) {
117                         // don't draw mirrors, we already did that earlier (if mirror rendering enabled)
118                         if((ropt & RENDER_MIRRORS) && scn->objects[j]->mtl.flat_mirror) {
119                                 continue;
120                         }
121                         draw_object(scn->objects[j]);
122                 }
123         }
124 }
125
126 void Renderer::draw_object(Object *obj) const
127 {
128         bool vis = true;
129         SceneNode *n = obj->node;
130         while(n) {
131                 if(!n->visible) {
132                         vis = false;
133                         break;
134                 }
135                 n = n->get_parent();
136         }
137
138         if(vis) {
139                 unsigned int use_mask = 0;
140                 if(obj->mtl.stdtex[MTL_TEX_DIFFUSE]) {
141                         use_mask |= USE_TEXMAP;
142                 }
143                 if(obj->mtl.stdtex[MTL_TEX_REFLECT] && obj->mtl.flat_mirror) {
144                         use_mask |= USE_MIRROR;
145                 }
146
147                 unsigned int sdr = shaders[use_mask];
148                 if(use_mask & USE_MIRROR) {
149                         float sx = 1.0f / rtmirror->texture()->get_width();
150                         float sy = 1.0f / rtmirror->texture()->get_height();
151                         set_uniform_float2(sdr, "mirtex_offs", -cur_vport[0], -cur_vport[1]);
152                         set_uniform_float2(sdr, "mirtex_scale", sx, sy);
153                         set_uniform_float(sdr, "reflectivity", obj->mtl.reflect);
154                 }
155                 bind_program(sdr);
156
157                 obj->draw();
158         }
159 }
160
161 void Renderer::draw_mirror(FlatMirror *mir) const
162 {
163         push_render_target(rtmirror);
164         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
165
166         glMatrixMode(GL_MODELVIEW);
167         glPushMatrix();
168
169         // TODO update mirror plane for movable mirrors?
170
171         Mat4 mirmat;
172         mirmat.mirror(mir->wplane.normal, -dot(mir->wplane.normal, mir->wplane.pt));
173         glMultMatrixf(mirmat[0]);
174
175         glFrontFace(GL_CW);
176         draw();
177         glFrontFace(GL_CCW);
178
179         glPopMatrix();
180         pop_render_target();
181
182         if(dbg_key_pending & 1) {
183                 dump_gl_texture(rtmirror->texture()->get_id(), "mirror.ppm");
184                 dbg_key_pending &= ~1;
185         }
186
187         int nobj = mir->objects.size();
188         for(int i=0; i<nobj; i++) {
189                 Object *obj = (Object*)mir->objects[i];
190
191                 Texture *prev_refl_tex = obj->mtl.stdtex[MTL_TEX_REFLECT];
192                 obj->mtl.stdtex[MTL_TEX_REFLECT] = rtmirror->texture();
193
194                 draw_object(mir->objects[i]);
195
196                 obj->mtl.stdtex[MTL_TEX_REFLECT] = prev_refl_tex;
197         }
198 }