6a5b56d5beffc50b0aec45fbd7b56dfc9f13058d
[carveJwlIkooP6JGAAIwe30JlM.git] / render.h
1 #include "common.h"
2 #include "model.h"
3
4 #include "shaders/blit.h"
5 #include "shaders/standard.h"
6 #include "shaders/vblend.h"
7 #include "shaders/unlit.h"
8
9 static void render_water_texture( m4x3f camera );
10 static void render_water_surface( m4x4f pv, m4x3f camera );
11 static void render_world( m4x4f projection, m4x3f camera );
12 static void shader_link_standard_ub( GLuint shader, int texture_id );
13 static void render_world_depth( m4x4f projection, m4x3f camera );
14
15 #ifndef RENDER_H
16 #define RENDER_H
17
18 struct framebuffer
19 {
20 GLuint fb, colour, rb;
21 int div;
22 GLuint format;
23
24 int allocated;
25 };
26
27 static struct pipeline
28 {
29 float fov;
30 glmesh fsquad;
31
32 GLuint fb_background,
33 rgb_background;
34
35 /* STD140 */
36 struct ub_world_lighting
37 {
38 /* v3f (padded) */
39 v4f g_light_colours[3],
40 g_light_directions[3],
41 g_ambient_colour;
42
43 v4f g_water_plane,
44 g_depth_bounds;
45
46 float g_water_fog;
47 int g_light_count;
48 int g_light_preview;
49 }
50 ub_world_lighting;
51
52 struct light_widget
53 {
54 int enabled;
55 v2f dir;
56 v3f colour;
57 }
58 widgets[3];
59
60 float shadow_spread, shadow_length;
61
62 GLuint fb_depthmap, rgb_depthmap;
63 GLuint ubo_world_lighting,
64 ubo_world;
65
66 int ready;
67 }
68 gpipeline =
69 {
70 .widgets =
71 {
72 {
73 .enabled = 1,
74 .colour = { 1.36f, 1.35f, 1.01f },
75 .dir = { 0.63f, -0.08f }
76 },
77 {
78 .enabled = 1,
79 .colour = { 0.33f, 0.56f, 0.64f },
80 .dir = { -2.60f, -0.13f }
81 },
82 {
83 .enabled = 1,
84 .colour = { 0.05f, 0.05f, 0.23f },
85 .dir = { 2.60f, -0.84f }
86 }
87 },
88 .shadow_spread = 0.65f,
89 .shadow_length = 9.50f,
90
91 .ub_world_lighting =
92 {
93 .g_ambient_colour = { 0.09f, 0.03f, 0.07f }
94 }
95 };
96
97 /*
98 * Matrix Projections
99 */
100 /*
101 * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
102 */
103 static void plane_clip_projection( m4x4f mat, v4f plane )
104 {
105 v4f c =
106 {
107 (vg_signf(plane[0]) + mat[2][0]) / mat[0][0],
108 (vg_signf(plane[1]) + mat[2][1]) / mat[1][1],
109 -1.0f,
110 (1.0f + mat[2][2]) / mat[3][2]
111 };
112
113 v4_muls( plane, 2.0f / v4_dot(plane,c), c );
114
115 mat[0][2] = c[0];
116 mat[1][2] = c[1];
117 mat[2][2] = c[2] + 1.0f;
118 mat[3][2] = c[3];
119 }
120
121 static void pipeline_projection( m4x4f mat, float nearz, float farz )
122 {
123 m4x4_projection( mat,
124 gpipeline.fov,
125 (float)vg_window_x / (float)vg_window_y,
126 nearz, farz );
127 }
128
129 /*
130 * Shaders
131 */
132 static void shader_link_standard_ub( GLuint shader, int texture_id )
133 {
134 GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
135 glUniformBlockBinding( shader, idx, 0 );
136
137 glActiveTexture( GL_TEXTURE0 + texture_id );
138 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap );
139 glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
140 }
141
142 static void render_update_lighting_ub(void)
143 {
144 struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
145 int c = 0;
146
147 for( int i=0; i<3; i++ )
148 {
149 struct light_widget *lw = &gpipeline.widgets[i];
150
151 if( lw->enabled )
152 {
153 float pitch = lw->dir[0],
154 yaw = lw->dir[1],
155 xz = cosf( pitch );
156
157 v3_copy( (v3f){ xz*cosf(yaw), sinf(pitch), xz*sinf(yaw) },
158 winf->g_light_directions[c] );
159 v3_copy( lw->colour, winf->g_light_colours[c] );
160
161 c ++;
162 }
163 }
164
165 winf->g_light_count = c;
166 winf->g_light_directions[0][3] = gpipeline.shadow_length;
167 winf->g_light_colours[0][3] = gpipeline.shadow_spread;
168
169 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
170 glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
171 &gpipeline.ub_world_lighting );
172 }
173
174 /*
175 * Framebuffers
176 */
177
178 static void fb_use( struct framebuffer *fb )
179 {
180 if( !fb )
181 {
182 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
183 glViewport( 0, 0, vg_window_x, vg_window_y );
184 }
185 else
186 {
187 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
188 glViewport( 0, 0, vg_window_x / fb->div, vg_window_y / fb->div );
189 }
190 }
191
192 __attribute__((warn_unused_result))
193 static int fb_init( struct framebuffer *fb )
194 {
195 i32 ix = vg_window_x / fb->div,
196 iy = vg_window_y / fb->div;
197
198 glGenFramebuffers( 1, &fb->fb );
199 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
200
201 glGenTextures( 1, &fb->colour );
202 glBindTexture( GL_TEXTURE_2D, fb->colour );
203 glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy,
204 0, fb->format, GL_UNSIGNED_BYTE, NULL);
205
206 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
207 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
208 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
209 GL_TEXTURE_2D, fb->colour, 0);
210
211 glGenRenderbuffers( 1, &fb->rb );
212 glBindRenderbuffer( GL_RENDERBUFFER, fb->rb );
213 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
214
215 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
216 GL_RENDERBUFFER, fb->rb );
217 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
218
219 if( VG_CHECK_GL_ERR() )
220 {
221 fb->allocated = 0;
222 vg_error( "Error while creating standard framebuffer\n" );
223 return 0;
224 }
225
226 fb->allocated = 1;
227 return 1;
228 }
229
230 static void fb_free( struct framebuffer *fb )
231 {
232 glDeleteTextures( 1, &fb->colour );
233 glDeleteFramebuffers( 1, &fb->fb );
234 }
235
236 static void fb_bindtex( struct framebuffer *fb, int texture )
237 {
238 glActiveTexture( GL_TEXTURE0 + texture );
239 glBindTexture( GL_TEXTURE_2D, fb->colour );
240 }
241
242 static void fb_resize( struct framebuffer *fb )
243 {
244 if( !fb->allocated )
245 return;
246
247 i32 ix = vg_window_x / fb->div,
248 iy = vg_window_y / fb->div;
249
250 glBindTexture( GL_TEXTURE_2D, fb->colour );
251 glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy, 0,
252 fb->format, GL_UNSIGNED_BYTE, NULL );
253
254 glBindRenderbuffer( GL_RENDERBUFFER, fb->rb );
255 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
256 }
257
258 static void render_fb_resize(void)
259 {
260 if( gpipeline.ready )
261 {
262 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
263 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, 0,
264 GL_RGB, GL_UNSIGNED_BYTE, NULL );
265 }
266 }
267
268 /*
269 * Vg
270 */
271 static int render_init(void)
272 {
273 shader_blit_register();
274 shader_standard_register();
275 shader_vblend_register();
276 shader_unlit_register();
277
278 if( vg_acquire_thread_sync(1) )
279 {
280 vg_info( "Allocating framebuffers\n" );
281
282 glGenFramebuffers( 1, &gpipeline.fb_background );
283 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background );
284
285 glGenTextures( 1, &gpipeline.rgb_background );
286 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
287 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y,
288 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
289
290 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
291 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
292 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
293 GL_TEXTURE_2D,
294 gpipeline.rgb_background, 0);
295
296 if( VG_CHECK_GL_ERR() )
297 {
298 vg_error( "Error while creating back buffer\n" );
299 vg_release_thread_sync(1);
300 return 0;
301 }
302
303 /*
304 * World depth map, maybe this should be moved to world.h
305 * TODO: review
306 */
307 glGenFramebuffers( 1, &gpipeline.fb_depthmap );
308 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
309
310 glGenTextures( 1, &gpipeline.rgb_depthmap );
311 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap );
312 glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0,
313 GL_RED, GL_FLOAT, NULL );
314 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
315 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
316 vg_tex2d_clamp();
317
318 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
319 GL_TEXTURE_2D,
320 gpipeline.rgb_depthmap, 0);
321
322 if( VG_CHECK_GL_ERR() )
323 {
324 vg_error( "Error while creating world depth buffer\n" );
325 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
326 vg_release_thread_sync(1);
327 return 0;
328 }
329
330 float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
331 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f };
332
333 glGenVertexArrays( 1, &gpipeline.fsquad.vao );
334 glGenBuffers( 1, &gpipeline.fsquad.vbo );
335 glBindVertexArray( gpipeline.fsquad.vao );
336 glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo );
337 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
338 glBindVertexArray( gpipeline.fsquad.vao );
339 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
340 sizeof(float)*2, (void*)0 );
341 glEnableVertexAttribArray( 0 );
342
343 if( VG_CHECK_GL_ERR() )
344 {
345 vg_error( "Error while creating fsquad\n" );
346 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
347 vg_release_thread_sync(1);
348 return 0;
349 }
350
351 glGenBuffers( 1, &gpipeline.ubo_world_lighting );
352 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
353 glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
354 NULL, GL_DYNAMIC_DRAW );
355
356 render_update_lighting_ub();
357 glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
358
359 if( VG_CHECK_GL_ERR() )
360 {
361 vg_error( "Error while creating world uniform buffers\n" );
362 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
363 vg_release_thread_sync(1);
364 return 0;
365 }
366
367 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
368 vg_success( "Done\n" );
369
370 gpipeline.ready = 1;
371 vg_release_thread_sync(1);
372 return 1;
373 }
374 else
375 return 0;
376 }
377
378 static void render_free(void *_)
379 {
380 glDeleteVertexArrays( 1, &gpipeline.fsquad.vao );
381 glDeleteBuffers( 1, &gpipeline.fsquad.vbo );
382
383 glDeleteFramebuffers( 1, &gpipeline.fb_background );
384 glDeleteFramebuffers( 1, &gpipeline.fb_depthmap );
385
386 glDeleteTextures( 1, &gpipeline.rgb_background );
387 glDeleteTextures( 1, &gpipeline.rgb_depthmap );
388 }
389
390 /*
391 * Utility
392 */
393 static void render_fsquad(void)
394 {
395 glBindVertexArray( gpipeline.fsquad.vao );
396 glDrawArrays( GL_TRIANGLES, 0, 6 );
397 }
398
399 #endif /* RENDER_H */