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