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