dungeon_crawler

annotate prototype/src/renderer_deferred.cc @ 69:45172d087ebe

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