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