model fmt & heisenbug
[carveJwlIkooP6JGAAIwe30JlM.git] / main.c
1 /*
2 * =============================================================================
3 *
4 * Copyright . . . -----, ,----- ,---. .---.
5 * 2021-2022 |\ /| | / | | | | /|
6 * | \ / | +-- / +----- +---' | / |
7 * | \ / | | / | | \ | / |
8 * | \/ | | / | | \ | / |
9 * ' ' '--' [] '----- '----- ' ' '---' SOFTWARE
10 *
11 * =============================================================================
12 *
13 * register: shader register & init scheduling
14 * init: initialization
15 * update: logic
16 * render: graphics
17 * free: resource free
18 *
19 */
20
21 #define VG_3D
22 //#define VG_STATIC static
23 #define VG_STATIC
24
25 //#define VG_MINIMAL_TEST
26 #ifndef VG_MINIMAL_TEST
27
28 #define SR_NETWORKED
29
30 #include "common.h"
31 #include "steam.h"
32 #include "render.h"
33 #include "audio.h"
34 #include "world.h"
35 #include "player.h"
36 #include "network.h"
37 #include "menu.h"
38
39 static int cl_ui = 1;
40
41 int main( int argc, char *argv[] )
42 {
43 vg_mem.use_libc_malloc = 1;
44 #if 0
45 vg_prealloc_quota( 128*1024*1024 );
46 void *test_allocator = vg_create_linear_allocator( NULL, 2048 );
47
48 for( int i=0; i<8; i++ )
49 {
50 u64 *items = vg_linear_alloc( test_allocator, sizeof(u64) );
51 items = vg_linear_extend( test_allocator, items, sizeof(u64));
52 items[0] = 43;
53 items[1] = 12445;
54
55 vg_info( "%lu %lu\n", items[0], items[1] );
56 }
57
58 vg_linear_clear( test_allocator );
59 return 0;
60 #endif
61
62 vg_prealloc_quota( 128*1024*1024 );
63 vg_enter( argc, argv, "Voyager Game Engine" );
64 }
65
66 VG_STATIC void highscores_save_at_exit(void*_)
67 {
68 highscores_serialize_all();
69 }
70
71 VG_STATIC void vg_preload(void)
72 {
73
74 vg_convar_push( (struct vg_convar){
75 .name = "cl_ui",
76 .data = &cl_ui,
77 .data_type = k_convar_dtype_i32,
78 .opt_i32 = { .min=0, .max=1, .clamp=1 },
79 .persistent = 1
80 });
81
82 vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" );
83 vg_info(" 2021-2022 |\\ /| | / | | | | /| \n" );
84 vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
85 vg_info(" | \\ / | | / | | \\ | / | \n" );
86 vg_info(" | \\/ | | / | | \\ | / | \n" );
87 vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
88 "SOFTWARE\n" );
89
90 highscores_init( 2000, 50 );
91 if( !highscores_read() )
92 highscores_create_db();
93
94 vg_loader_highwater( NULL, highscores_save_at_exit, NULL );
95
96 //vg_sleep_ms(200);
97
98 steam_init();
99 vg_loader_highwater( NULL, steam_end, NULL );
100 vg_loader_highwater( network_init, network_end, NULL );
101 }
102
103 VG_STATIC void vg_load(void)
104 {
105 vg_loader_highwater( render_init, NULL, NULL );
106 vg_loader_highwater( menu_init, NULL, NULL );
107 vg_loader_highwater( world_init, NULL, NULL );
108 vg_loader_highwater( player_init, NULL, NULL );
109
110 vg_bake_shaders();
111 vg_loader_highwater( audio_init, audio_free, NULL );
112
113 /* 'systems' are completely loaded now */
114 strcpy( world.world_name, "models/mp_test.mdl" );
115 world_load();
116 vg_console_load_autos();
117 }
118
119 VG_STATIC void vg_start(void)
120 {
121 reset_player( 1, (const char *[]){ "start" } );
122 }
123
124 VG_STATIC void draw_origin_axis(void)
125 {
126 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
127 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
128 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
129 }
130
131 VG_STATIC void vg_update( int loaded )
132 {
133 steam_update();
134
135 if( loaded )
136 {
137 draw_origin_axis();
138 network_update();
139
140 player_update_pre();
141 world_update( player.phys.rb.co );
142 }
143 }
144
145 VG_STATIC void vg_update_fixed( int loaded )
146 {
147 if( loaded )
148 {
149 player_update_fixed();
150 }
151 }
152
153 VG_STATIC void vg_update_post( int loaded )
154 {
155 if( loaded )
156 {
157 player_update_post();
158 menu_update();
159 }
160 }
161
162 VG_STATIC void vg_framebuffer_resize( int w, int h )
163 {
164 render_fb_resize();
165 water_fb_resize();
166 }
167
168 VG_STATIC void render_main_game(void)
169 {
170 m4x4f world_4x4;
171 m4x3_expand( camera_mtx_inverse, world_4x4 );
172
173 static float fov = 97.0f;
174
175 float fov_target = 108.0f;
176 if( player.phys.on_board )
177 fov_target = 125.0f;
178
179 if( cl_menu )
180 fov_target = menu_fov_target;
181
182 fov = vg_lerpf( fov, fov_target, vg.frame_delta * 2.0f );
183
184 gpipeline.fov = freecam? 60.0f: fov; /* 120 */
185 m4x4_projection( vg.pv, gpipeline.fov,
186 (float)vg.window_x / (float)vg.window_y,
187 0.1f, 2100.0f );
188
189 m4x4_mul( vg.pv, world_4x4, vg.pv );
190 glEnable( GL_DEPTH_TEST );
191
192 /*
193 * Draw world
194 */
195
196 int draw_solid = player.is_dead | freecam;
197
198 render_world( vg.pv, camera_mtx );
199 if( draw_solid )
200 draw_player( camera_mtx );
201
202 render_water_texture( camera_mtx );
203
204 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
205 render_water_surface( vg.pv, camera_mtx );
206 render_world_gates( vg.pv, player.phys.rb.co, camera_mtx );
207
208 if( cl_menu )
209 {
210 glClear( GL_DEPTH_BUFFER_BIT );
211 menu_render( vg.pv );
212 }
213
214 /* Copy the RGB of what we have into the background buffer */
215 glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
216 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, gpipeline.fb_background );
217 glBlitFramebuffer( 0,0, vg.window_x, vg.window_y,
218 0,0, vg.window_x, vg.window_y,
219 GL_COLOR_BUFFER_BIT,
220 GL_LINEAR );
221
222 /* Clear out the colour buffer, but keep depth */
223 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
224 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
225
226 if( !player.is_dead )
227 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
228 else
229 glClear( GL_COLOR_BUFFER_BIT );
230
231 if( !draw_solid )
232 {
233 m4x4_projection( vg.pv, gpipeline.fov,
234 (float)vg.window_x / (float)vg.window_y,
235 0.05f, 60.0f );
236 m4x4_mul( vg.pv, world_4x4, vg.pv );
237 draw_player( camera_mtx );
238 }
239
240 /* Draw back in the background
241 *
242 * TODO: need to disable alpha write in the terrain shader so this works
243 * again.
244 */
245 glEnable(GL_BLEND);
246 glDisable(GL_DEPTH_TEST);
247 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
248 glBlendEquation(GL_FUNC_ADD);
249
250 shader_blit_use();
251 shader_blit_uTexMain( 0 );
252 glActiveTexture(GL_TEXTURE0);
253 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
254
255 render_fsquad();
256 }
257
258 VG_STATIC void vg_render(void)
259 {
260 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
261 glViewport( 0,0, vg.window_x, vg.window_y );
262 glDisable( GL_DEPTH_TEST );
263
264 glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
265 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
266
267 render_main_game();
268
269
270 /* Other shite */
271 glDisable(GL_BLEND);
272 glDisable( GL_DEPTH_TEST );
273 vg_lines_drawall( (float *)vg.pv );
274 glViewport( 0,0, vg.window_x, vg.window_y );
275 }
276
277 VG_STATIC void vg_ui(void)
278 {
279 #if 0
280 if( cl_menu )
281 {
282 ui_rect menu =
283 {
284 vg.window_x / 2 - 150,
285 vg.window_y / 2 - 50,
286 300,
287 130
288 };
289
290 ui_fill_rect( &ui_global_ctx, menu, 0xa0000000 );
291
292 ui_text( &ui_global_ctx, (ui_rect){ menu[0]+menu[2]/2,menu[1]+6, 0, 0 },
293 steam_username_at_startup,
294 1, k_text_align_center );
295 menu[1] += 24;
296 menu[3] -= 30;
297
298 ui_rect_pad( menu, 8 );
299 ui_fill_rect( &ui_global_ctx, menu, 0x90ffffff );
300 ui_rect_pad( menu, 2 );
301 ui_fill_rect( &ui_global_ctx, menu, 0xa0000000 );
302
303 menu[1] += 32;
304 ui_text( &ui_global_ctx, (ui_rect){ menu[0]+menu[2]/2,menu[1], 0, 0 },
305 "Exit", 2, k_text_align_center );
306
307 if( vg_get_button_down( "jump" ) )
308 {
309 glfwSetWindowShouldClose( vg.window, 1 );
310 }
311 }
312
313 if( lightedit )
314 {
315 ui_global_ctx.cursor[0] = 10;
316 ui_global_ctx.cursor[1] = 10;
317 ui_global_ctx.cursor[2] = 200;
318 ui_global_ctx.cursor[3] = 20;
319
320 struct ub_world_lighting *wl = &gpipeline.ub_world_lighting;
321 struct ui_slider_vector
322 s5 = { .min=0.0f, .max=2.0f, .len=3, .data=wl->g_ambient_colour };
323
324 struct ui_slider
325 s8 = { .min=0.0f, .max=2.0f, .data = &gpipeline.shadow_spread },
326 s9 = { .min=0.0f, .max=25.0f, .data = &gpipeline.shadow_length };
327
328 for( int i=0; i<3; i++ )
329 run_light_widget( &gpipeline.widgets[i] );
330
331 gui_text( ui_global_ctx.cursor, "Ambient", 1, 0 );
332 ui_global_ctx.cursor[1] += 16;
333 ui_slider_vector( &ui_global_ctx, &s5 );
334
335 gui_text( ui_global_ctx.cursor, "Shadows", 1, 0 );
336 ui_global_ctx.cursor[1] += 16;
337 ui_slider( &ui_global_ctx, &s8 );
338 ui_slider( &ui_global_ctx, &s9 );
339
340 gui_text( ui_global_ctx.cursor, "Misc", 1, 0 );
341 ui_global_ctx.cursor[1] += 16;
342 struct ui_checkbox c1 = {.data = &wl->g_light_preview};
343 ui_checkbox( &ui_global_ctx, &c1 );
344
345 render_update_lighting_ub();
346 }
347 #endif
348
349 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
350 if( cl_ui )
351 {
352 render_world_routes_ui();
353 }
354 //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
355
356 audio_debug_soundscapes();
357 }
358
359 #if 0
360 VG_STATIC void run_light_widget( struct light_widget *lw )
361 {
362 struct ui_checkbox c1 = { .data=&lw->enabled };
363
364 ui_checkbox( &ui_global_ctx, &c1 );
365
366 if( lw->enabled )
367 {
368 struct ui_slider_vector
369 colour = { .min=0.0f, .max=2.0f, .len=3, .data=lw->colour },
370 dir = { .min=-VG_PIf, .max=VG_PIf, .len=2, .data=lw->dir };
371
372 ui_slider_vector( &ui_global_ctx, &colour );
373 ui_global_ctx.cursor[1] += 4;
374 ui_slider_vector( &ui_global_ctx, &dir );
375 }
376 }
377 #endif
378
379 VG_STATIC void run_debug_info(void)
380 {
381 char buf[40];
382
383 snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) );
384 ui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
385
386 snprintf( buf, 40, "%.2f %.2f %.2f m/s",
387 player.phys.a[0], player.phys.a[1], player.phys.a[2] );
388 ui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
389
390 snprintf( buf, 40, "pos %.2f %.2f %.2f",
391 player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
392 ui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
393
394 if( vg.gamepad_ready )
395 {
396 for( int i=0; i<6; i++ )
397 {
398 snprintf( buf, 40, "%.2f", vg.gamepad.axes[i] );
399 ui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
400 }
401 }
402 else
403 {
404 ui_text( (ui_px [2]){ 0, 60 },
405 "Gamepad not ready", 1, k_text_align_left );
406 }
407 }
408
409 #else
410
411 #define VG_TIMESTEP_FIXED (1.0/60.0)
412 #define VG_3D
413 #define VG_FRAMEBUFFER_RESIZE 1
414 #include "vg/vg.h"
415
416 int main( int argc, char *argv[] )
417 {
418 vg_prealloc_quota( 512*1024*1024 );
419 vg_enter( argc, argv, "Voyager Game Engine" );
420 }
421
422 VG_STATIC void vg_preload(void)
423 {
424 vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" );
425 vg_info(" 2021-2022 |\\ /| | / | | | | /| \n" );
426 vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
427 vg_info(" | \\ / | | / | | \\ | / | \n" );
428 vg_info(" | \\/ | | / | | \\ | / | \n" );
429 vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
430 "SOFTWARE\n" );
431 }
432
433 VG_STATIC void vg_load(void)
434 {
435 vg_bake_shaders();
436 vg_console_load_autos();
437 }
438
439 VG_STATIC void vg_start(void)
440 {
441 }
442
443 VG_STATIC void vg_update( int loaded )
444 {
445 }
446
447 VG_STATIC void vg_update_fixed( int loaded )
448 {
449 }
450
451 VG_STATIC void vg_update_post( int loaded )
452 {
453 }
454
455 VG_STATIC void vg_framebuffer_resize( int w, int h )
456 {
457 }
458
459 VG_STATIC void vg_render(void)
460 {
461 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
462 glViewport( 0,0, vg.window_x, vg.window_y );
463 glDisable( GL_DEPTH_TEST );
464
465 glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
466 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
467
468 /* Other shite */
469 glDisable(GL_BLEND);
470 glDisable( GL_DEPTH_TEST );
471 vg_lines_drawall( (float *)vg.pv );
472 glViewport( 0,0, vg.window_x, vg.window_y );
473 }
474
475 VG_STATIC void vg_ui(void)
476 {
477 }
478
479 #endif