dungeon_crawler

view prototype/src/renderer_deferred.cc @ 65:fc2b3d06d07c

made the deferred renderer draw into a texture, so that I can reuse the depth buffer for geometric post effects (particles), and implement other per-pixel post effects eventually
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 02 Oct 2012 13:42:18 +0300
parents 7f52d6310317
children 45172d087ebe
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <limits.h>
5 #include "opengl.h"
6 #include "renderer_deferred.h"
7 #include "level.h"
8 #include "sdr.h"
9 #include "datapath.h"
11 static unsigned int load_sdr(const char *vfname, const char *pfname);
12 static void attach_color_buffer(unsigned int fbo, int count, const unsigned int *tex);
13 static int round_pow2(int x);
15 DeferredRenderer::DeferredRenderer()
16 {
17 fbo = rbuf_depth = rend_tex = 0;
18 for(int i=0; i<MRT_COUNT; i++) {
19 mrt_tex[i] = 0;
20 }
21 tex_xsz = tex_ysz = 0;
23 mrt_prog = deferred_debug = deferred_omni = post_sdr = 0;
25 curr_prog = 0;
26 num_draw_bufs = 1;
27 }
29 DeferredRenderer::~DeferredRenderer()
30 {
31 if(mrt_prog) {
32 free_program(mrt_prog);
33 }
34 if(deferred_omni) {
35 free_program(deferred_omni);
36 }
37 if(deferred_debug) {
38 free_program(deferred_debug);
39 }
40 if(post_sdr) {
41 free_program(post_sdr);
42 }
44 if(mrt_tex[0]) {
45 glDeleteTextures(MRT_COUNT, mrt_tex);
46 }
47 if(rend_tex) {
48 glDeleteTextures(1, &rend_tex);
49 }
50 if(rbuf_depth) {
51 glDeleteRenderbuffersEXT(1, &rbuf_depth);
52 }
53 if(fbo) {
54 glDeleteFramebuffersEXT(1, &fbo);
55 }
56 }
58 bool DeferredRenderer::init(int xsz, int ysz)
59 {
60 width = xsz;
61 height = ysz;
63 if(!GLEW_ARB_texture_float) {
64 fprintf(stderr, "%s: error: no floating point texture support\n", __func__);
65 return false;
66 }
67 if(!GLEW_ARB_draw_buffers) {
68 fprintf(stderr, "%s: error: no multiple render target support\n", __func__);
69 return false;
70 }
72 int max_draw_buf;
73 glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buf);
74 printf("max draw buffers: %d\n", max_draw_buf);
75 if(max_draw_buf < MRT_COUNT) {
76 fprintf(stderr, "%s: error: not enough draw buffers (%d), %d required\n", __func__, max_draw_buf, MRT_COUNT);
77 return false;
78 }
79 num_draw_bufs = MRT_COUNT;
81 if(!create_fbo()) {
82 return false;
83 }
85 if(!(mrt_prog = load_sdr("mrt.v.glsl", "mrt.p.glsl"))) {
86 return false;
87 }
88 set_uniform_int(mrt_prog, "tex_dif", 0);
89 set_uniform_int(mrt_prog, "tex_norm", 1);
91 if(!(deferred_omni = load_sdr("deferred_omni.v.glsl", "deferred_omni.p.glsl"))) {
92 return false;
93 }
94 for(int i=0; i<MRT_COUNT; i++) {
95 char uname[32];
96 sprintf(uname, "mrt%d", i);
97 set_uniform_int(deferred_omni, uname, i);
98 }
100 if(!(post_sdr = load_sdr("post.v.glsl", "post.p.glsl"))) {
101 return false;
102 }
104 rend = this;
105 return true;
106 }
108 int DeferredRenderer::get_tangent_location() const
109 {
110 return get_attrib_loc(mrt_prog, "attr_tangent");
111 }
113 unsigned int DeferredRenderer::get_current_program() const
114 {
115 return curr_prog;
116 }
118 void DeferredRenderer::resize(int xsz, int ysz)
119 {
120 width = xsz;
121 height = ysz;
123 // if we need a bigger rendertarget ...
124 if(xsz > tex_xsz || ysz > tex_ysz) {
125 tex_xsz = round_pow2(xsz);
126 tex_ysz = round_pow2(ysz);
128 // ... resize all the color buffers
129 for(int i=0; i<MRT_COUNT; i++) {
130 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
131 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
132 }
134 // ... resize the render texture
135 glBindTexture(GL_TEXTURE_2D, rend_tex);
136 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
138 // ... resize the depth buffer
139 glBindRenderbufferEXT(GL_RENDERBUFFER, rbuf_depth);
140 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz);
141 }
143 // update the texture coordinate scaling factors
144 float tex_scale_x = (float)width / tex_xsz;
145 float tex_scale_y = (float)height / tex_ysz;
147 set_uniform_float2(deferred_omni, "tex_scale", tex_scale_x, tex_scale_y);
148 set_uniform_float2(deferred_omni, "fb_size", width, height);
149 }
151 void DeferredRenderer::render(const Level *level) const
152 {
153 render_pre(level);
155 // render into the MRT buffers
156 glUseProgram(mrt_prog);
157 curr_prog = mrt_prog;
159 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
160 attach_color_buffer(fbo, num_draw_bufs, mrt_tex);
162 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
163 level->draw();
165 attach_color_buffer(fbo, 1, &rend_tex);
166 glClear(GL_COLOR_BUFFER_BIT);
168 // post-process lighting
169 light_pass(level);
171 glUseProgram(0);
172 curr_prog = 0;
174 render_post(level);
176 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
178 // XXX this should be moved to render_post
179 glBindTexture(GL_TEXTURE_2D, rend_tex);
180 glEnable(GL_TEXTURE_2D);
182 glUseProgram(post_sdr);
183 glBegin(GL_QUADS);
184 glTexCoord2f(0, 0);
185 glVertex2f(-1, -1);
186 glTexCoord2f((float)width / tex_xsz, 0);
187 glVertex2f(1, -1);
188 glTexCoord2f((float)width / tex_xsz, (float)height / tex_ysz);
189 glVertex2f(1, 1);
190 glTexCoord2f(0, (float)height / tex_ysz);
191 glVertex2f(-1, 1);
192 glEnd();
193 glUseProgram(0);
194 }
196 void DeferredRenderer::light_pass(const Level *level) const
197 {
198 glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_TEXTURE_BIT);
200 glEnable(GL_BLEND);
201 glBlendFunc(GL_ONE, GL_ONE);
203 glDisable(GL_LIGHTING);
204 glDisable(GL_DEPTH_TEST);
205 glCullFace(GL_FRONT);
207 glUseProgram(deferred_omni);
208 curr_prog = deferred_omni;
210 for(int i=0; i<MRT_COUNT; i++) {
211 glActiveTexture(GL_TEXTURE0 + i);
212 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
213 glEnable(GL_TEXTURE_2D);
214 }
216 glDepthMask(0);
217 level->draw_lights();
218 glDepthMask(1);
220 for(int i=0; i<MRT_COUNT; i++) {
221 glActiveTexture(GL_TEXTURE0 + MRT_COUNT - i - 1);
222 glDisable(GL_TEXTURE_2D);
223 }
225 glPopAttrib();
226 }
228 static const char *fbstname[] = {
229 "GL_FRAMEBUFFER_COMPLETE",
230 "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
231 "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
232 "no such fbo error",
233 "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
234 "GL_FRAMEBUFFER_INCOMPLETE_FORMATS",
235 "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
236 "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
237 "GL_FRAMEBUFFER_UNSUPPORTED"
238 };
240 bool DeferredRenderer::create_fbo()
241 {
242 unsigned int clamp = GLEW_ARB_texture_border_clamp ? GL_CLAMP_TO_EDGE : GL_CLAMP;
244 // round the texture size up to the next power of 2
245 tex_xsz = round_pow2(width);
246 tex_ysz = round_pow2(height);
248 if(!glGenFramebuffersEXT) {
249 fprintf(stderr, "FBO support missing\n");
250 return false;
251 }
252 glGenFramebuffersEXT(1, &fbo);
253 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
255 // create the result render target
256 glGenTextures(1, &rend_tex);
257 glBindTexture(GL_TEXTURE_2D, rend_tex);
258 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
262 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
264 glGenTextures(MRT_COUNT, mrt_tex);
265 for(int i=0; i<MRT_COUNT; i++) {
266 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
267 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
269 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
270 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
271 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
273 // attach to fbo
274 GLenum color_att = GL_COLOR_ATTACHMENT0 + (num_draw_bufs == MRT_COUNT ? i : 0);
275 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, color_att, GL_TEXTURE_2D, mrt_tex[i], 0);
276 CHECKGLERR;
277 }
279 glGenRenderbuffersEXT(1, &rbuf_depth);
280 glBindRenderbufferEXT(GL_RENDERBUFFER, rbuf_depth);
281 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz);
282 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_depth);
284 int fbst = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
285 if(fbst != GL_FRAMEBUFFER_COMPLETE) {
286 fprintf(stderr, "incomplete fbo: %u (%s)\n", fbo, fbstname[fbst - GL_FRAMEBUFFER_COMPLETE]);
287 return false;
288 }
289 CHECKGLERR;
291 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
292 return true;
293 }
295 static unsigned int load_sdr(const char *vfname, const char *pfname)
296 {
297 unsigned int prog;
299 std::string vsfile = datafile_path(vfname);
300 std::string psfile = datafile_path(pfname);
302 const char *vs = vsfile.empty() ? 0 : vsfile.c_str();
303 const char *ps = psfile.empty() ? 0 : psfile.c_str();
305 if(!(prog = create_program_load(vs, ps))) {
306 fprintf(stderr, "failed to load shader program (%s, %s)\n", vs, ps);
307 return 0;
308 }
309 return prog;
310 }
312 static void attach_color_buffer(unsigned int fbo, int count, const unsigned int *tex)
313 {
314 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
316 for(int i=0; i<count; i++) {
317 GLenum color_att = GL_COLOR_ATTACHMENT0 + i;
318 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, color_att, GL_TEXTURE_2D, tex[i], 0);
319 CHECKGLERR;
320 }
322 static GLenum draw_bufs[] = {
323 GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT,
324 GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT,
325 GL_COLOR_ATTACHMENT4_EXT, GL_COLOR_ATTACHMENT5_EXT,
326 GL_COLOR_ATTACHMENT6_EXT, GL_COLOR_ATTACHMENT7_EXT
327 };
328 glDrawBuffersARB(count, draw_bufs);
329 }
331 static int round_pow2(int x)
332 {
333 x--;
334 x = (x >> 1) | x;
335 x = (x >> 2) | x;
336 x = (x >> 4) | x;
337 x = (x >> 8) | x;
338 x = (x >> 16) | x;
339 return x + 1;
340 }
342 #ifdef DBG_VIS_MRT
343 // visualize the MRT buffers
344 static void draw_deferred_debug()
345 {
346 glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
347 glUseProgram(deferred_debug);
348 glDisable(GL_DEPTH_TEST);
350 glMatrixMode(GL_PROJECTION);
351 glPushMatrix();
352 glLoadIdentity();
353 glMatrixMode(GL_MODELVIEW);
354 glPushMatrix();
355 glLoadIdentity();
357 for(int i=0; i<MRT_COUNT; i++) {
358 glActiveTexture(GL_TEXTURE0 + i);
359 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
360 glEnable(GL_TEXTURE_2D);
361 }
363 glBegin(GL_QUADS);
364 glTexCoord2f(0, 0);
365 glVertex2f(-1, -1);
366 glTexCoord2f(1, 0);
367 glVertex2f(1, -1);
368 glTexCoord2f(1, 1);
369 glVertex2f(1, 1);
370 glTexCoord2f(0, 1);
371 glVertex2f(-1, 1);
372 glEnd();
374 for(int i=0; i<MRT_COUNT; i++) {
375 glActiveTexture(GL_TEXTURE0 + MRT_COUNT - i - 1);
376 glDisable(GL_TEXTURE_2D);
377 }
379 glMatrixMode(GL_PROJECTION);
380 glPopMatrix();
381 glMatrixMode(GL_MODELVIEW);
382 glPopMatrix();
384 glUseProgram(0);
385 glPopAttrib();
386 }
387 #endif