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
|