dungeon_crawler

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