dungeon_crawler

annotate prototype/src/renderer.cc @ 78:12a1dcfe91fa

gamma correct rendering
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 26 Oct 2012 21:22:14 +0300
parents 5981917093ff
children
rev   line source
nuclear@44 1 #include <limits.h>
nuclear@78 2 #include <assert.h>
nuclear@15 3 #include "opengl.h"
nuclear@15 4 #include "renderer.h"
nuclear@23 5 #include "level.h"
nuclear@15 6 #include "sdr.h"
nuclear@15 7 #include "datapath.h"
nuclear@15 8
nuclear@41 9 static unsigned int load_sdr(const char *vfname, const char *pfname);
nuclear@72 10 static int round_pow2(int x);
nuclear@35 11
nuclear@41 12 Renderer *rend;
nuclear@18 13
nuclear@15 14
nuclear@41 15 Renderer::Renderer()
nuclear@41 16 {
nuclear@72 17 fbo = 0;
nuclear@72 18 rend_tex = rend_depth = 0;
nuclear@41 19 width = height = 0;
nuclear@72 20 tex_xsz = tex_ysz = 0;
nuclear@72 21 post_sdr = 0;
nuclear@41 22 }
nuclear@17 23
nuclear@41 24 Renderer::~Renderer()
nuclear@41 25 {
nuclear@72 26 if(post_sdr) {
nuclear@72 27 free_program(post_sdr);
nuclear@72 28 }
nuclear@72 29 if(rend_tex) {
nuclear@72 30 glDeleteTextures(1, &rend_tex);
nuclear@72 31 }
nuclear@72 32 if(rend_depth) {
nuclear@72 33 glDeleteRenderbuffersEXT(1, &rend_depth);
nuclear@72 34 }
nuclear@72 35 if(fbo) {
nuclear@72 36 glDeleteFramebuffersEXT(1, &fbo);
nuclear@72 37 }
nuclear@41 38 }
nuclear@17 39
nuclear@41 40 bool Renderer::init(int xsz, int ysz)
nuclear@41 41 {
nuclear@41 42 width = xsz;
nuclear@41 43 height = ysz;
nuclear@17 44
nuclear@72 45 if(!create_rtarg()) {
nuclear@72 46 return false;
nuclear@72 47 }
nuclear@72 48
nuclear@72 49 if(!(post_sdr = load_sdr("post.v.glsl", "post.p.glsl"))) {
nuclear@72 50 return false;
nuclear@72 51 }
nuclear@72 52
nuclear@72 53 if(!gradepal.create()) {
nuclear@72 54 return false;
nuclear@72 55 }
nuclear@72 56
nuclear@78 57 if(GLEW_ARB_framebuffer_sRGB) {
nuclear@78 58 glEnable(GL_FRAMEBUFFER_SRGB);
nuclear@78 59 }
nuclear@78 60
nuclear@41 61 rend = this;
nuclear@41 62 return true;
nuclear@41 63 }
nuclear@15 64
nuclear@41 65 int Renderer::get_tangent_location() const
nuclear@41 66 {
nuclear@41 67 return -1;
nuclear@41 68 }
nuclear@15 69
nuclear@41 70 unsigned int Renderer::get_current_program() const
nuclear@41 71 {
nuclear@41 72 return 0;
nuclear@41 73 }
nuclear@21 74
nuclear@41 75 void Renderer::resize(int xsz, int ysz)
nuclear@41 76 {
nuclear@41 77 width = xsz;
nuclear@41 78 height = ysz;
nuclear@72 79
nuclear@72 80 // if we need a bigger rendertarget ...
nuclear@72 81 if(xsz > tex_xsz || ysz > tex_ysz) {
nuclear@72 82 tex_xsz = round_pow2(xsz);
nuclear@72 83 tex_ysz = round_pow2(ysz);
nuclear@72 84
nuclear@72 85 // ... resize the render target
nuclear@72 86 glBindTexture(GL_TEXTURE_2D, rend_tex);
nuclear@78 87 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@72 88
nuclear@72 89 // ... resize the depth buffer
nuclear@72 90 glBindRenderbufferEXT(GL_RENDERBUFFER, rend_depth);
nuclear@72 91 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz);
nuclear@72 92 }
nuclear@41 93 }
nuclear@21 94
nuclear@62 95 void Renderer::render_pre(const Level *level) const
nuclear@62 96 {
nuclear@62 97 glEnable(GL_FOG);
nuclear@62 98 glFogi(GL_FOG_MODE, GL_LINEAR);
nuclear@62 99 glFogf(GL_FOG_START, 3.0f);
nuclear@62 100 glFogf(GL_FOG_END, 6.0f);
nuclear@62 101 // TODO level->draw_pre();
nuclear@72 102
nuclear@72 103 // bind the render target
nuclear@72 104 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
nuclear@72 105 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rend_tex, 0);
nuclear@72 106 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@72 107
nuclear@72 108 CHECKGLERR;
nuclear@62 109 }
nuclear@62 110
nuclear@62 111 void Renderer::render_post(const Level *level) const
nuclear@62 112 {
nuclear@62 113 level->draw_post();
nuclear@72 114 CHECKGLERR;
nuclear@72 115
nuclear@72 116 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
nuclear@72 117
nuclear@72 118 // draw the rendered output
nuclear@72 119 glActiveTextureARB(GL_TEXTURE0);
nuclear@72 120 glBindTexture(GL_TEXTURE_2D, rend_tex);
nuclear@72 121 glEnable(GL_TEXTURE_2D);
nuclear@72 122
nuclear@72 123 // use the color-grading palette
nuclear@72 124 glActiveTextureARB(GL_TEXTURE1);
nuclear@72 125 glBindTexture(GL_TEXTURE_3D, gradepal.get_texture());
nuclear@72 126 glEnable(GL_TEXTURE_3D);
nuclear@72 127
nuclear@72 128 glUseProgram(post_sdr);
nuclear@72 129 set_uniform_int(post_sdr, "fbtex", 0);
nuclear@72 130 set_uniform_int(post_sdr, "paltex", 1);
nuclear@72 131
nuclear@72 132 glBegin(GL_QUADS);
nuclear@72 133 glTexCoord2f(0, 0);
nuclear@72 134 glVertex2f(-1, -1);
nuclear@72 135 glTexCoord2f((float)width / tex_xsz, 0);
nuclear@72 136 glVertex2f(1, -1);
nuclear@72 137 glTexCoord2f((float)width / tex_xsz, (float)height / tex_ysz);
nuclear@72 138 glVertex2f(1, 1);
nuclear@72 139 glTexCoord2f(0, (float)height / tex_ysz);
nuclear@72 140 glVertex2f(-1, 1);
nuclear@72 141 glEnd();
nuclear@72 142 glUseProgram(0);
nuclear@72 143
nuclear@73 144 glActiveTextureARB(GL_TEXTURE1);
nuclear@73 145 glDisable(GL_TEXTURE_3D);
nuclear@72 146 glActiveTextureARB(GL_TEXTURE0);
nuclear@73 147 glDisable(GL_TEXTURE_2D);
nuclear@72 148
nuclear@72 149 CHECKGLERR;
nuclear@72 150 }
nuclear@72 151
nuclear@72 152 static const char *fbstname[] = {
nuclear@72 153 "GL_FRAMEBUFFER_COMPLETE",
nuclear@72 154 "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
nuclear@72 155 "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
nuclear@72 156 "no such fbo error",
nuclear@72 157 "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
nuclear@72 158 "GL_FRAMEBUFFER_INCOMPLETE_FORMATS",
nuclear@72 159 "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
nuclear@72 160 "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
nuclear@72 161 "GL_FRAMEBUFFER_UNSUPPORTED"
nuclear@72 162 };
nuclear@72 163
nuclear@72 164 bool Renderer::create_rtarg()
nuclear@72 165 {
nuclear@72 166 unsigned int clamp = GLEW_ARB_texture_border_clamp ? GL_CLAMP_TO_EDGE : GL_CLAMP;
nuclear@72 167
nuclear@72 168 tex_xsz = round_pow2(width);
nuclear@72 169 tex_ysz = round_pow2(height);
nuclear@72 170
nuclear@72 171 if(!glGenFramebuffersEXT) {
nuclear@72 172 fprintf(stderr, "FBO support missing!\n");
nuclear@72 173 return false;
nuclear@72 174 }
nuclear@72 175 glGenFramebuffersEXT(1, &fbo);
nuclear@72 176 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
nuclear@72 177
nuclear@72 178 // create the render target
nuclear@72 179 glGenTextures(1, &rend_tex);
nuclear@72 180 glBindTexture(GL_TEXTURE_2D, rend_tex);
nuclear@72 181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
nuclear@72 182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
nuclear@72 183 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@72 184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@78 185 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@72 186
nuclear@72 187 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rend_tex, 0);
nuclear@72 188
nuclear@72 189 // create depth buffer
nuclear@72 190 glGenRenderbuffersEXT(1, &rend_depth);
nuclear@72 191 glBindRenderbufferEXT(GL_RENDERBUFFER, rend_depth);
nuclear@72 192 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_xsz, tex_ysz);
nuclear@72 193
nuclear@72 194 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rend_depth);
nuclear@72 195
nuclear@72 196 int fbst = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
nuclear@72 197 if(fbst != GL_FRAMEBUFFER_COMPLETE) {
nuclear@72 198 fprintf(stderr, "incomplete fbo: %u (%s)\n", fbo, fbstname[fbst - GL_FRAMEBUFFER_COMPLETE]);
nuclear@72 199 return false;
nuclear@72 200 }
nuclear@72 201 CHECKGLERR;
nuclear@72 202
nuclear@72 203 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
nuclear@72 204 return true;
nuclear@62 205 }
nuclear@62 206
nuclear@74 207 GradePalette *Renderer::get_grade_palette()
nuclear@74 208 {
nuclear@74 209 return &gradepal;
nuclear@74 210 }
nuclear@74 211
nuclear@74 212 const GradePalette *Renderer::get_grade_palette() const
nuclear@74 213 {
nuclear@74 214 return &gradepal;
nuclear@74 215 }
nuclear@74 216
nuclear@41 217
nuclear@41 218 // ---- fallback forward renderer ----
nuclear@41 219 FwdRenderer::FwdRenderer()
nuclear@17 220 {
nuclear@41 221 sdrprog = 0;
nuclear@41 222 tang_attr = -1;
nuclear@41 223 }
nuclear@41 224
nuclear@41 225 FwdRenderer::~FwdRenderer()
nuclear@41 226 {
nuclear@41 227 if(sdrprog) {
nuclear@41 228 free_program(sdrprog);
nuclear@32 229 }
nuclear@41 230 }
nuclear@21 231
nuclear@41 232 bool FwdRenderer::init(int xsz, int ysz)
nuclear@41 233 {
nuclear@72 234 if(!Renderer::init(xsz, ysz)) {
nuclear@72 235 return false;
nuclear@72 236 }
nuclear@19 237
nuclear@41 238 if(glUseProgram && (sdrprog = load_sdr("fallback.v.glsl", "fallback.p.glsl"))) {
nuclear@41 239 tang_attr = get_attrib_loc(sdrprog, "attr_tangent");
nuclear@41 240 set_uniform_int(sdrprog, "tex_dif", 0);
nuclear@41 241 set_uniform_int(sdrprog, "tex_norm", 1);
nuclear@23 242 }
nuclear@17 243 return true;
nuclear@17 244 }
nuclear@17 245
nuclear@41 246 int FwdRenderer::get_tangent_location() const
nuclear@17 247 {
nuclear@41 248 return tang_attr;
nuclear@17 249 }
nuclear@17 250
nuclear@41 251 unsigned int FwdRenderer::get_current_program() const
nuclear@33 252 {
nuclear@41 253 return sdrprog;
nuclear@33 254 }
nuclear@33 255
nuclear@41 256 void FwdRenderer::render(const Level *level) const
nuclear@35 257 {
nuclear@41 258 glPushAttrib(GL_ENABLE_BIT);
nuclear@51 259 glEnable(GL_LIGHTING);
nuclear@62 260
nuclear@62 261 render_pre(level);
nuclear@51 262
nuclear@41 263 glUseProgram(sdrprog);
nuclear@62 264 level->draw();
nuclear@62 265 glUseProgram(0);
nuclear@35 266
nuclear@62 267 render_post(level);
nuclear@46 268
nuclear@41 269 glPopAttrib();
nuclear@17 270 }
nuclear@17 271
nuclear@18 272 static unsigned int load_sdr(const char *vfname, const char *pfname)
nuclear@15 273 {
nuclear@18 274 unsigned int prog;
nuclear@15 275
nuclear@63 276 std::string vsfile = datafile_path(vfname);
nuclear@63 277 std::string psfile = datafile_path(pfname);
nuclear@63 278
nuclear@63 279 const char *vs = vsfile.empty() ? 0 : vsfile.c_str();
nuclear@63 280 const char *ps = psfile.empty() ? 0 : psfile.c_str();
nuclear@63 281
nuclear@63 282 if(!(prog = create_program_load(vs, ps))) {
nuclear@63 283 fprintf(stderr, "failed to load shader program (%s, %s)\n", vs, ps);
nuclear@18 284 return 0;
nuclear@15 285 }
nuclear@18 286 return prog;
nuclear@15 287 }
nuclear@72 288
nuclear@72 289 static int round_pow2(int x)
nuclear@72 290 {
nuclear@72 291 x--;
nuclear@72 292 x = (x >> 1) | x;
nuclear@72 293 x = (x >> 2) | x;
nuclear@72 294 x = (x >> 4) | x;
nuclear@72 295 x = (x >> 8) | x;
nuclear@72 296 x = (x >> 16) | x;
nuclear@72 297 return x + 1;
nuclear@72 298 }
nuclear@72 299