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