dungeon_crawler
diff prototype/src/renderer_deferred.cc @ 41:acfe0c0110fc
- cleaned up the renderer
- implemented fallback (non-deferred renderer)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 30 Aug 2012 05:35:00 +0300 |
parents | |
children | aa86119e3295 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/prototype/src/renderer_deferred.cc Thu Aug 30 05:35:00 2012 +0300 1.3 @@ -0,0 +1,322 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <limits.h> 1.8 +#include "opengl.h" 1.9 +#include "renderer_deferred.h" 1.10 +#include "level.h" 1.11 +#include "sdr.h" 1.12 +#include "datapath.h" 1.13 + 1.14 +static unsigned int load_sdr(const char *vfname, const char *pfname); 1.15 +static int round_pow2(int x); 1.16 + 1.17 +DeferredRenderer::DeferredRenderer() 1.18 +{ 1.19 + fbo = rbuf_depth = 0; 1.20 + for(int i=0; i<MRT_COUNT; i++) { 1.21 + mrt_tex[i] = 0; 1.22 + } 1.23 + tex_xsz = tex_ysz = 0; 1.24 + 1.25 + mrt_prog = deferred_debug = deferred_omni = 0; 1.26 + 1.27 + curr_prog = 0; 1.28 +} 1.29 + 1.30 +DeferredRenderer::~DeferredRenderer() 1.31 +{ 1.32 + if(mrt_prog) { 1.33 + free_program(mrt_prog); 1.34 + } 1.35 + if(deferred_omni) { 1.36 + free_program(deferred_omni); 1.37 + } 1.38 + if(deferred_debug) { 1.39 + free_program(deferred_debug); 1.40 + } 1.41 + 1.42 + if(mrt_tex[0]) { 1.43 + glDeleteTextures(MRT_COUNT, mrt_tex); 1.44 + } 1.45 + if(fbo) { 1.46 + glDeleteFramebuffersEXT(1, &fbo); 1.47 + } 1.48 +} 1.49 + 1.50 +bool DeferredRenderer::init(int xsz, int ysz) 1.51 +{ 1.52 + width = xsz; 1.53 + height = ysz; 1.54 + 1.55 + if(!GLEW_ARB_texture_float) { 1.56 + fprintf(stderr, "%s: error: no floating point texture support\n", __func__); 1.57 + return false; 1.58 + } 1.59 + if(!GLEW_ARB_draw_buffers) { 1.60 + fprintf(stderr, "%s: error: no multiple render target support\n", __func__); 1.61 + return false; 1.62 + } 1.63 + 1.64 + int max_draw_buf; 1.65 + glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buf); 1.66 + printf("max draw buffers: %d\n", max_draw_buf); 1.67 + if(max_draw_buf < MRT_COUNT) { 1.68 + fprintf(stderr, "%s: error: not enough draw buffers (%d), %d required\n", __func__, max_draw_buf, MRT_COUNT); 1.69 + return false; 1.70 + } 1.71 + 1.72 + if(!create_fbo()) { 1.73 + return false; 1.74 + } 1.75 + 1.76 + if(!(mrt_prog = load_sdr("mrt.v.glsl", "mrt.p.glsl"))) { 1.77 + return false; 1.78 + } 1.79 + set_uniform_int(mrt_prog, "tex_dif", 0); 1.80 + set_uniform_int(mrt_prog, "tex_norm", 1); 1.81 + 1.82 + if(!(deferred_omni = load_sdr("deferred_omni.v.glsl", "deferred_omni.p.glsl"))) { 1.83 + return false; 1.84 + } 1.85 + for(int i=0; i<MRT_COUNT; i++) { 1.86 + char uname[32]; 1.87 + sprintf(uname, "mrt%d", i); 1.88 + set_uniform_int(deferred_omni, uname, i); 1.89 + } 1.90 + 1.91 + rend = this; 1.92 + return true; 1.93 +} 1.94 + 1.95 +int DeferredRenderer::get_tangent_location() const 1.96 +{ 1.97 + return get_attrib_loc(mrt_prog, "attr_tangent"); 1.98 +} 1.99 + 1.100 +unsigned int DeferredRenderer::get_current_program() const 1.101 +{ 1.102 + return curr_prog; 1.103 +} 1.104 + 1.105 +void DeferredRenderer::resize(int xsz, int ysz) 1.106 +{ 1.107 + width = xsz; 1.108 + height = ysz; 1.109 + 1.110 + // if we need a bigger rendertarget ... 1.111 + if(xsz > tex_xsz || ysz > tex_ysz) { 1.112 + tex_xsz = round_pow2(xsz); 1.113 + tex_ysz = round_pow2(ysz); 1.114 + 1.115 + // ... resize all the color buffers 1.116 + for(int i=0; i<MRT_COUNT; i++) { 1.117 + glBindTexture(GL_TEXTURE_2D, mrt_tex[i]); 1.118 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0); 1.119 + } 1.120 + 1.121 + // ... resize the depth buffer 1.122 + glBindRenderbufferEXT(GL_RENDERBUFFER, rbuf_depth); 1.123 + glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz); 1.124 + } 1.125 + 1.126 + // update the texture coordinate scaling factors 1.127 + float tex_scale_x = (float)width / tex_xsz; 1.128 + float tex_scale_y = (float)height / tex_ysz; 1.129 + 1.130 + set_uniform_float2(deferred_omni, "tex_scale", tex_scale_x, tex_scale_y); 1.131 + set_uniform_float2(deferred_omni, "fb_size", width, height); 1.132 +} 1.133 + 1.134 +void DeferredRenderer::render(const Level *level) const 1.135 +{ 1.136 + // render into the MRT buffers 1.137 + glUseProgram(mrt_prog); 1.138 + curr_prog = mrt_prog; 1.139 + 1.140 + glBindFramebufferEXT(GL_FRAMEBUFFER, fbo); 1.141 + 1.142 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.143 + level->draw(); 1.144 + 1.145 + glBindFramebufferEXT(GL_FRAMEBUFFER, 0); 1.146 + 1.147 + // post-process lighting 1.148 + glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT); 1.149 + 1.150 + glEnable(GL_BLEND); 1.151 + glBlendFunc(GL_ONE, GL_ONE); 1.152 + 1.153 + glDisable(GL_LIGHTING); 1.154 + glDisable(GL_DEPTH_TEST); 1.155 + glCullFace(GL_FRONT); 1.156 + 1.157 + glUseProgram(deferred_omni); 1.158 + curr_prog = deferred_omni; 1.159 + 1.160 + for(int i=0; i<MRT_COUNT; i++) { 1.161 + glActiveTexture(GL_TEXTURE0 + i); 1.162 + glBindTexture(GL_TEXTURE_2D, mrt_tex[i]); 1.163 + glEnable(GL_TEXTURE_2D); 1.164 + } 1.165 + 1.166 + glDepthMask(0); 1.167 + level->draw_lights(); 1.168 + glDepthMask(1); 1.169 + 1.170 + for(int i=0; i<MRT_COUNT; i++) { 1.171 + glActiveTexture(GL_TEXTURE0 + MRT_COUNT - i - 1); 1.172 + glDisable(GL_TEXTURE_2D); 1.173 + } 1.174 + 1.175 + glUseProgram(0); 1.176 + curr_prog = 0; 1.177 + glPopAttrib(); 1.178 +} 1.179 + 1.180 +static const char *fbstname[] = { 1.181 + "GL_FRAMEBUFFER_COMPLETE", 1.182 + "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", 1.183 + "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", 1.184 + "no such fbo error", 1.185 + "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS", 1.186 + "GL_FRAMEBUFFER_INCOMPLETE_FORMATS", 1.187 + "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER", 1.188 + "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER", 1.189 + "GL_FRAMEBUFFER_UNSUPPORTED" 1.190 +}; 1.191 + 1.192 +bool DeferredRenderer::create_fbo() 1.193 +{ 1.194 + unsigned int clamp = GLEW_ARB_texture_border_clamp ? GL_CLAMP_TO_EDGE : GL_CLAMP; 1.195 + 1.196 + // round the texture size up to the next power of 2 1.197 + tex_xsz = round_pow2(width); 1.198 + tex_ysz = round_pow2(height); 1.199 + 1.200 + if(!glGenFramebuffersEXT) { 1.201 + fprintf(stderr, "FBO support missing\n"); 1.202 + return false; 1.203 + } 1.204 + glGenFramebuffersEXT(1, &fbo); 1.205 + glBindFramebufferEXT(GL_FRAMEBUFFER, fbo); 1.206 + 1.207 + glGenTextures(MRT_COUNT, mrt_tex); 1.208 + for(int i=0; i<MRT_COUNT; i++) { 1.209 + glBindTexture(GL_TEXTURE_2D, mrt_tex[i]); 1.210 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp); 1.211 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp); 1.212 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1.213 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.214 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0); 1.215 + 1.216 + // attach to fbo 1.217 + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, 1.218 + GL_TEXTURE_2D, mrt_tex[i], 0); 1.219 + CHECKGLERR; 1.220 + } 1.221 + 1.222 + static GLenum draw_bufs[] = { 1.223 + GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, 1.224 + GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT, 1.225 + GL_COLOR_ATTACHMENT4_EXT, GL_COLOR_ATTACHMENT5_EXT, 1.226 + GL_COLOR_ATTACHMENT6_EXT, GL_COLOR_ATTACHMENT7_EXT 1.227 + }; 1.228 + glDrawBuffersARB(MRT_COUNT, draw_bufs); 1.229 + 1.230 + glGenRenderbuffersEXT(1, &rbuf_depth); 1.231 + glBindRenderbufferEXT(GL_RENDERBUFFER, rbuf_depth); 1.232 + glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz); 1.233 + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_depth); 1.234 + 1.235 + int fbst = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); 1.236 + if(fbst != GL_FRAMEBUFFER_COMPLETE) { 1.237 + fprintf(stderr, "incomplete fbo: %u (%s)\n", fbo, fbstname[fbst - GL_FRAMEBUFFER_COMPLETE]); 1.238 + return false; 1.239 + } 1.240 + CHECKGLERR; 1.241 + 1.242 + glBindFramebufferEXT(GL_FRAMEBUFFER, 0); 1.243 + return true; 1.244 +} 1.245 + 1.246 +static unsigned int load_sdr(const char *vfname, const char *pfname) 1.247 +{ 1.248 + char vsfile[PATH_MAX], psfile[PATH_MAX]; 1.249 + const char *fname; 1.250 + unsigned int prog; 1.251 + 1.252 + if((fname = datafile_path(vfname))) { 1.253 + strcpy(vsfile, fname); 1.254 + } else { 1.255 + vsfile[0] = 0; 1.256 + } 1.257 + if((fname = datafile_path(pfname))) { 1.258 + strcpy(psfile, fname); 1.259 + } else { 1.260 + psfile[0] = 0; 1.261 + } 1.262 + if(!(prog = create_program_load(vsfile, psfile))) { 1.263 + fprintf(stderr, "failed to load shader program (%s, %s)\n", vsfile, psfile); 1.264 + return 0; 1.265 + } 1.266 + return prog; 1.267 +} 1.268 + 1.269 +static int round_pow2(int x) 1.270 +{ 1.271 + x--; 1.272 + x = (x >> 1) | x; 1.273 + x = (x >> 2) | x; 1.274 + x = (x >> 4) | x; 1.275 + x = (x >> 8) | x; 1.276 + x = (x >> 16) | x; 1.277 + return x + 1; 1.278 +} 1.279 + 1.280 +#ifdef DBG_VIS_MRT 1.281 +// visualize the MRT buffers 1.282 +static void draw_deferred_debug() 1.283 +{ 1.284 + glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT); 1.285 + glUseProgram(deferred_debug); 1.286 + glDisable(GL_DEPTH_TEST); 1.287 + 1.288 + glMatrixMode(GL_PROJECTION); 1.289 + glPushMatrix(); 1.290 + glLoadIdentity(); 1.291 + glMatrixMode(GL_MODELVIEW); 1.292 + glPushMatrix(); 1.293 + glLoadIdentity(); 1.294 + 1.295 + for(int i=0; i<MRT_COUNT; i++) { 1.296 + glActiveTexture(GL_TEXTURE0 + i); 1.297 + glBindTexture(GL_TEXTURE_2D, mrt_tex[i]); 1.298 + glEnable(GL_TEXTURE_2D); 1.299 + } 1.300 + 1.301 + glBegin(GL_QUADS); 1.302 + glTexCoord2f(0, 0); 1.303 + glVertex2f(-1, -1); 1.304 + glTexCoord2f(1, 0); 1.305 + glVertex2f(1, -1); 1.306 + glTexCoord2f(1, 1); 1.307 + glVertex2f(1, 1); 1.308 + glTexCoord2f(0, 1); 1.309 + glVertex2f(-1, 1); 1.310 + glEnd(); 1.311 + 1.312 + for(int i=0; i<MRT_COUNT; i++) { 1.313 + glActiveTexture(GL_TEXTURE0 + MRT_COUNT - i - 1); 1.314 + glDisable(GL_TEXTURE_2D); 1.315 + } 1.316 + 1.317 + glMatrixMode(GL_PROJECTION); 1.318 + glPopMatrix(); 1.319 + glMatrixMode(GL_MODELVIEW); 1.320 + glPopMatrix(); 1.321 + 1.322 + glUseProgram(0); 1.323 + glPopAttrib(); 1.324 +} 1.325 +#endif