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