dungeon_crawler

annotate prototype/src/renderer_deferred.cc @ 45:dfd3a413ef9e

particle system 1
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 12 Sep 2012 06:04:20 +0300
parents
children aa86119e3295
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@41 12 static int round_pow2(int x);
nuclear@41 13
nuclear@41 14 DeferredRenderer::DeferredRenderer()
nuclear@41 15 {
nuclear@41 16 fbo = rbuf_depth = 0;
nuclear@41 17 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 18 mrt_tex[i] = 0;
nuclear@41 19 }
nuclear@41 20 tex_xsz = tex_ysz = 0;
nuclear@41 21
nuclear@41 22 mrt_prog = deferred_debug = deferred_omni = 0;
nuclear@41 23
nuclear@41 24 curr_prog = 0;
nuclear@41 25 }
nuclear@41 26
nuclear@41 27 DeferredRenderer::~DeferredRenderer()
nuclear@41 28 {
nuclear@41 29 if(mrt_prog) {
nuclear@41 30 free_program(mrt_prog);
nuclear@41 31 }
nuclear@41 32 if(deferred_omni) {
nuclear@41 33 free_program(deferred_omni);
nuclear@41 34 }
nuclear@41 35 if(deferred_debug) {
nuclear@41 36 free_program(deferred_debug);
nuclear@41 37 }
nuclear@41 38
nuclear@41 39 if(mrt_tex[0]) {
nuclear@41 40 glDeleteTextures(MRT_COUNT, mrt_tex);
nuclear@41 41 }
nuclear@41 42 if(fbo) {
nuclear@41 43 glDeleteFramebuffersEXT(1, &fbo);
nuclear@41 44 }
nuclear@41 45 }
nuclear@41 46
nuclear@41 47 bool DeferredRenderer::init(int xsz, int ysz)
nuclear@41 48 {
nuclear@41 49 width = xsz;
nuclear@41 50 height = ysz;
nuclear@41 51
nuclear@41 52 if(!GLEW_ARB_texture_float) {
nuclear@41 53 fprintf(stderr, "%s: error: no floating point texture support\n", __func__);
nuclear@41 54 return false;
nuclear@41 55 }
nuclear@41 56 if(!GLEW_ARB_draw_buffers) {
nuclear@41 57 fprintf(stderr, "%s: error: no multiple render target support\n", __func__);
nuclear@41 58 return false;
nuclear@41 59 }
nuclear@41 60
nuclear@41 61 int max_draw_buf;
nuclear@41 62 glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buf);
nuclear@41 63 printf("max draw buffers: %d\n", max_draw_buf);
nuclear@41 64 if(max_draw_buf < MRT_COUNT) {
nuclear@41 65 fprintf(stderr, "%s: error: not enough draw buffers (%d), %d required\n", __func__, max_draw_buf, MRT_COUNT);
nuclear@41 66 return false;
nuclear@41 67 }
nuclear@41 68
nuclear@41 69 if(!create_fbo()) {
nuclear@41 70 return false;
nuclear@41 71 }
nuclear@41 72
nuclear@41 73 if(!(mrt_prog = load_sdr("mrt.v.glsl", "mrt.p.glsl"))) {
nuclear@41 74 return false;
nuclear@41 75 }
nuclear@41 76 set_uniform_int(mrt_prog, "tex_dif", 0);
nuclear@41 77 set_uniform_int(mrt_prog, "tex_norm", 1);
nuclear@41 78
nuclear@41 79 if(!(deferred_omni = load_sdr("deferred_omni.v.glsl", "deferred_omni.p.glsl"))) {
nuclear@41 80 return false;
nuclear@41 81 }
nuclear@41 82 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 83 char uname[32];
nuclear@41 84 sprintf(uname, "mrt%d", i);
nuclear@41 85 set_uniform_int(deferred_omni, uname, i);
nuclear@41 86 }
nuclear@41 87
nuclear@41 88 rend = this;
nuclear@41 89 return true;
nuclear@41 90 }
nuclear@41 91
nuclear@41 92 int DeferredRenderer::get_tangent_location() const
nuclear@41 93 {
nuclear@41 94 return get_attrib_loc(mrt_prog, "attr_tangent");
nuclear@41 95 }
nuclear@41 96
nuclear@41 97 unsigned int DeferredRenderer::get_current_program() const
nuclear@41 98 {
nuclear@41 99 return curr_prog;
nuclear@41 100 }
nuclear@41 101
nuclear@41 102 void DeferredRenderer::resize(int xsz, int ysz)
nuclear@41 103 {
nuclear@41 104 width = xsz;
nuclear@41 105 height = ysz;
nuclear@41 106
nuclear@41 107 // if we need a bigger rendertarget ...
nuclear@41 108 if(xsz > tex_xsz || ysz > tex_ysz) {
nuclear@41 109 tex_xsz = round_pow2(xsz);
nuclear@41 110 tex_ysz = round_pow2(ysz);
nuclear@41 111
nuclear@41 112 // ... resize all the color buffers
nuclear@41 113 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 114 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
nuclear@41 115 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
nuclear@41 116 }
nuclear@41 117
nuclear@41 118 // ... resize the depth buffer
nuclear@41 119 glBindRenderbufferEXT(GL_RENDERBUFFER, rbuf_depth);
nuclear@41 120 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz);
nuclear@41 121 }
nuclear@41 122
nuclear@41 123 // update the texture coordinate scaling factors
nuclear@41 124 float tex_scale_x = (float)width / tex_xsz;
nuclear@41 125 float tex_scale_y = (float)height / tex_ysz;
nuclear@41 126
nuclear@41 127 set_uniform_float2(deferred_omni, "tex_scale", tex_scale_x, tex_scale_y);
nuclear@41 128 set_uniform_float2(deferred_omni, "fb_size", width, height);
nuclear@41 129 }
nuclear@41 130
nuclear@41 131 void DeferredRenderer::render(const Level *level) const
nuclear@41 132 {
nuclear@41 133 // render into the MRT buffers
nuclear@41 134 glUseProgram(mrt_prog);
nuclear@41 135 curr_prog = mrt_prog;
nuclear@41 136
nuclear@41 137 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
nuclear@41 138
nuclear@41 139 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@41 140 level->draw();
nuclear@41 141
nuclear@41 142 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
nuclear@41 143
nuclear@41 144 // post-process lighting
nuclear@41 145 glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
nuclear@41 146
nuclear@41 147 glEnable(GL_BLEND);
nuclear@41 148 glBlendFunc(GL_ONE, GL_ONE);
nuclear@41 149
nuclear@41 150 glDisable(GL_LIGHTING);
nuclear@41 151 glDisable(GL_DEPTH_TEST);
nuclear@41 152 glCullFace(GL_FRONT);
nuclear@41 153
nuclear@41 154 glUseProgram(deferred_omni);
nuclear@41 155 curr_prog = deferred_omni;
nuclear@41 156
nuclear@41 157 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 158 glActiveTexture(GL_TEXTURE0 + i);
nuclear@41 159 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
nuclear@41 160 glEnable(GL_TEXTURE_2D);
nuclear@41 161 }
nuclear@41 162
nuclear@41 163 glDepthMask(0);
nuclear@41 164 level->draw_lights();
nuclear@41 165 glDepthMask(1);
nuclear@41 166
nuclear@41 167 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 168 glActiveTexture(GL_TEXTURE0 + MRT_COUNT - i - 1);
nuclear@41 169 glDisable(GL_TEXTURE_2D);
nuclear@41 170 }
nuclear@41 171
nuclear@41 172 glUseProgram(0);
nuclear@41 173 curr_prog = 0;
nuclear@41 174 glPopAttrib();
nuclear@41 175 }
nuclear@41 176
nuclear@41 177 static const char *fbstname[] = {
nuclear@41 178 "GL_FRAMEBUFFER_COMPLETE",
nuclear@41 179 "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
nuclear@41 180 "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
nuclear@41 181 "no such fbo error",
nuclear@41 182 "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
nuclear@41 183 "GL_FRAMEBUFFER_INCOMPLETE_FORMATS",
nuclear@41 184 "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
nuclear@41 185 "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
nuclear@41 186 "GL_FRAMEBUFFER_UNSUPPORTED"
nuclear@41 187 };
nuclear@41 188
nuclear@41 189 bool DeferredRenderer::create_fbo()
nuclear@41 190 {
nuclear@41 191 unsigned int clamp = GLEW_ARB_texture_border_clamp ? GL_CLAMP_TO_EDGE : GL_CLAMP;
nuclear@41 192
nuclear@41 193 // round the texture size up to the next power of 2
nuclear@41 194 tex_xsz = round_pow2(width);
nuclear@41 195 tex_ysz = round_pow2(height);
nuclear@41 196
nuclear@41 197 if(!glGenFramebuffersEXT) {
nuclear@41 198 fprintf(stderr, "FBO support missing\n");
nuclear@41 199 return false;
nuclear@41 200 }
nuclear@41 201 glGenFramebuffersEXT(1, &fbo);
nuclear@41 202 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
nuclear@41 203
nuclear@41 204 glGenTextures(MRT_COUNT, mrt_tex);
nuclear@41 205 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 206 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
nuclear@41 207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
nuclear@41 208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
nuclear@41 209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@41 210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@41 211 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
nuclear@41 212
nuclear@41 213 // attach to fbo
nuclear@41 214 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
nuclear@41 215 GL_TEXTURE_2D, mrt_tex[i], 0);
nuclear@41 216 CHECKGLERR;
nuclear@41 217 }
nuclear@41 218
nuclear@41 219 static GLenum draw_bufs[] = {
nuclear@41 220 GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT,
nuclear@41 221 GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT,
nuclear@41 222 GL_COLOR_ATTACHMENT4_EXT, GL_COLOR_ATTACHMENT5_EXT,
nuclear@41 223 GL_COLOR_ATTACHMENT6_EXT, GL_COLOR_ATTACHMENT7_EXT
nuclear@41 224 };
nuclear@41 225 glDrawBuffersARB(MRT_COUNT, draw_bufs);
nuclear@41 226
nuclear@41 227 glGenRenderbuffersEXT(1, &rbuf_depth);
nuclear@41 228 glBindRenderbufferEXT(GL_RENDERBUFFER, rbuf_depth);
nuclear@41 229 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz);
nuclear@41 230 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_depth);
nuclear@41 231
nuclear@41 232 int fbst = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
nuclear@41 233 if(fbst != GL_FRAMEBUFFER_COMPLETE) {
nuclear@41 234 fprintf(stderr, "incomplete fbo: %u (%s)\n", fbo, fbstname[fbst - GL_FRAMEBUFFER_COMPLETE]);
nuclear@41 235 return false;
nuclear@41 236 }
nuclear@41 237 CHECKGLERR;
nuclear@41 238
nuclear@41 239 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
nuclear@41 240 return true;
nuclear@41 241 }
nuclear@41 242
nuclear@41 243 static unsigned int load_sdr(const char *vfname, const char *pfname)
nuclear@41 244 {
nuclear@41 245 char vsfile[PATH_MAX], psfile[PATH_MAX];
nuclear@41 246 const char *fname;
nuclear@41 247 unsigned int prog;
nuclear@41 248
nuclear@41 249 if((fname = datafile_path(vfname))) {
nuclear@41 250 strcpy(vsfile, fname);
nuclear@41 251 } else {
nuclear@41 252 vsfile[0] = 0;
nuclear@41 253 }
nuclear@41 254 if((fname = datafile_path(pfname))) {
nuclear@41 255 strcpy(psfile, fname);
nuclear@41 256 } else {
nuclear@41 257 psfile[0] = 0;
nuclear@41 258 }
nuclear@41 259 if(!(prog = create_program_load(vsfile, psfile))) {
nuclear@41 260 fprintf(stderr, "failed to load shader program (%s, %s)\n", vsfile, psfile);
nuclear@41 261 return 0;
nuclear@41 262 }
nuclear@41 263 return prog;
nuclear@41 264 }
nuclear@41 265
nuclear@41 266 static int round_pow2(int x)
nuclear@41 267 {
nuclear@41 268 x--;
nuclear@41 269 x = (x >> 1) | x;
nuclear@41 270 x = (x >> 2) | x;
nuclear@41 271 x = (x >> 4) | x;
nuclear@41 272 x = (x >> 8) | x;
nuclear@41 273 x = (x >> 16) | x;
nuclear@41 274 return x + 1;
nuclear@41 275 }
nuclear@41 276
nuclear@41 277 #ifdef DBG_VIS_MRT
nuclear@41 278 // visualize the MRT buffers
nuclear@41 279 static void draw_deferred_debug()
nuclear@41 280 {
nuclear@41 281 glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
nuclear@41 282 glUseProgram(deferred_debug);
nuclear@41 283 glDisable(GL_DEPTH_TEST);
nuclear@41 284
nuclear@41 285 glMatrixMode(GL_PROJECTION);
nuclear@41 286 glPushMatrix();
nuclear@41 287 glLoadIdentity();
nuclear@41 288 glMatrixMode(GL_MODELVIEW);
nuclear@41 289 glPushMatrix();
nuclear@41 290 glLoadIdentity();
nuclear@41 291
nuclear@41 292 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 293 glActiveTexture(GL_TEXTURE0 + i);
nuclear@41 294 glBindTexture(GL_TEXTURE_2D, mrt_tex[i]);
nuclear@41 295 glEnable(GL_TEXTURE_2D);
nuclear@41 296 }
nuclear@41 297
nuclear@41 298 glBegin(GL_QUADS);
nuclear@41 299 glTexCoord2f(0, 0);
nuclear@41 300 glVertex2f(-1, -1);
nuclear@41 301 glTexCoord2f(1, 0);
nuclear@41 302 glVertex2f(1, -1);
nuclear@41 303 glTexCoord2f(1, 1);
nuclear@41 304 glVertex2f(1, 1);
nuclear@41 305 glTexCoord2f(0, 1);
nuclear@41 306 glVertex2f(-1, 1);
nuclear@41 307 glEnd();
nuclear@41 308
nuclear@41 309 for(int i=0; i<MRT_COUNT; i++) {
nuclear@41 310 glActiveTexture(GL_TEXTURE0 + MRT_COUNT - i - 1);
nuclear@41 311 glDisable(GL_TEXTURE_2D);
nuclear@41 312 }
nuclear@41 313
nuclear@41 314 glMatrixMode(GL_PROJECTION);
nuclear@41 315 glPopMatrix();
nuclear@41 316 glMatrixMode(GL_MODELVIEW);
nuclear@41 317 glPopMatrix();
nuclear@41 318
nuclear@41 319 glUseProgram(0);
nuclear@41 320 glPopAttrib();
nuclear@41 321 }
nuclear@41 322 #endif