variable scale menu
[carveJwlIkooP6JGAAIwe30JlM.git] / skaterift.c
1 /*
2 * =============================================================================
3 *
4 * Copyright . . . -----, ,----- ,---. .---.
5 * 2021-2023 |\ /| | / | | | | /|
6 * | \ / | +-- / +----- +---' | / |
7 * | \ / | | / | | \ | / |
8 * | \/ | | / | | \ | / |
9 * ' ' '--' [] '----- '----- ' ' '---' SOFTWARE
10 *
11 * =============================================================================
12 */
13
14 #define SR_NETWORKED
15 #include "common.h"
16 #include "conf.h"
17 #include "steam.h"
18 #include "render.h"
19 #include "audio.h"
20 #include "world.h"
21
22
23
24 #include "player.h"
25 static player_instance localplayer;
26 VG_STATIC struct player_avatar localplayer_avatar;
27 VG_STATIC glmesh localplayer_meshes[3];
28 vg_tex2d localplayer_texture = { .path = "textures/ch_gradient.qoi" };
29
30 player_instance *tmp_localplayer(void)
31 {
32 return &localplayer;
33 }
34
35 #include "network.h"
36 #include "menu.h"
37 #include "vehicle.h"
38
39 static int cl_ui = 1,
40 cl_light_edit = 0;
41
42 int main( int argc, char *argv[] )
43 {
44 vg_mem.use_libc_malloc = 0;
45 vg_set_mem_quota( 160*1024*1024 );
46 vg_enter( argc, argv, "Voyager Game Engine" );
47
48 return 0;
49 }
50
51 VG_STATIC void highscores_save_at_exit(void)
52 {
53 highscores_serialize_all();
54 }
55
56 VG_STATIC void vg_launch_opt(void)
57 {
58
59 }
60
61 VG_STATIC int __kill( int argc, const char *argv[] )
62 {
63 #if 0
64 player_use_device( &localplayer, &player_device_dead, &localplayer_dead );
65 #endif
66 return 0;
67 }
68
69 VG_STATIC int __respawn( int argc, const char *argv[] )
70 {
71 ent_spawn *rp = NULL, *r;
72 world_instance *world = get_active_world();
73
74 if( argc == 1 ){
75 for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
76 r = mdl_arritm( &world->ent_spawn, i );
77 if( !strcmp( mdl_pstr(&world->meta, r->pstr_name),argv[0] ) ){
78 rp = r;
79 break;
80 }
81 }
82
83 if( !rp )
84 vg_warn( "No spawn named '%s'\n", argv[0] );
85 }
86
87 if( !rp ){
88 float min_dist = INFINITY;
89
90 for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
91 r = mdl_arritm( &world->ent_spawn, i );
92 float d = v3_dist2( r->transform.co, localplayer.rb.co );
93
94 if( d < min_dist ){
95 min_dist = d;
96 rp = r;
97 }
98 }
99 }
100
101 if( !rp ){
102 vg_error( "No spawn found\n" );
103
104 if( !mdl_arrcount(&world->ent_spawn) )
105 return 0;
106
107 rp = mdl_arritm( &world->ent_spawn, 0 );
108 }
109
110 player__spawn( &localplayer, rp );
111 return 1;
112 }
113
114 VG_STATIC void vg_preload(void)
115 {
116 g_conf_init();
117
118 common_var_temp();
119
120 vg_var_push( (struct vg_var){
121 .name = "cl_ui",
122 .data = &cl_ui,
123 .data_type = k_var_dtype_i32,
124 .opt_i32 = { .min=0, .max=1, .clamp=1 },
125 .persistent = 0
126 });
127
128 vg_var_push( (struct vg_var){
129 .name = "ledit",
130 .data = &cl_light_edit,
131 .data_type = k_var_dtype_i32,
132 .opt_i32 = { .min=0, .max=1, .clamp=1 },
133 .persistent = 0
134 });
135
136 vg_function_push( (struct vg_cmd) {
137 .name = "respawn",
138 .function = __respawn,
139 //.poll_suggest = reset_player_poll
140 });
141
142 vg_function_push( (struct vg_cmd) {
143 .name = "ded",
144 .function = __kill,
145 //.poll_suggest = reset_player_poll
146 });
147
148 vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" );
149 vg_info(" 2021-2022 |\\ /| | / | | | | /| \n" );
150 vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
151 vg_info(" | \\ / | | / | | \\ | / | \n" );
152 vg_info(" | \\/ | | / | | \\ | / | \n" );
153 vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
154 "SOFTWARE\n" );
155
156 highscores_init( 2000, 50 );
157 if( !highscores_read() )
158 highscores_create_db();
159
160 vg_loader_step( NULL, highscores_save_at_exit );
161
162 steam_init();
163 vg_loader_step( NULL, steam_end );
164 vg_loader_step( network_init, network_end );
165 }
166
167 VG_STATIC void load_playermodels(void)
168 {
169 vg_linear_clear( vg_mem.scratch );
170
171 /*
172 * load in other player models. This may need to be more sophisticated in
173 * the futre if we have more of these guys
174 */
175 mdl_context ctx_default,
176 ctx_outlaw,
177 ctx_jordan;
178
179 mdl_open( &ctx_default, "models/ch_new.mdl", vg_mem.scratch );
180 mdl_load_metadata_block( &ctx_default, vg_mem.scratch );
181 mdl_load_mesh_block( &ctx_default, vg_mem.scratch );
182 mdl_close( &ctx_default );
183
184 mdl_open( &ctx_outlaw, "models/ch_outlaw.mdl", vg_mem.scratch );
185 mdl_load_metadata_block( &ctx_outlaw, vg_mem.scratch );
186 mdl_load_mesh_block( &ctx_outlaw, vg_mem.scratch );
187 mdl_close( &ctx_outlaw );
188
189 mdl_open( &ctx_jordan, "models/ch_jordan.mdl", vg_mem.scratch );
190 mdl_load_metadata_block( &ctx_jordan, vg_mem.scratch );
191 mdl_load_mesh_block( &ctx_jordan, vg_mem.scratch );
192 mdl_close( &ctx_jordan );
193
194 vg_acquire_thread_sync();
195 {
196 mdl_unpack_glmesh( &ctx_default, &localplayer_meshes[0] );
197 mdl_unpack_glmesh( &ctx_outlaw, &localplayer_meshes[1] );
198 mdl_unpack_glmesh( &ctx_jordan, &localplayer_meshes[2] );
199 }
200 vg_release_thread_sync();
201
202 /* FIXME: hack */
203 shader_model_character_view_register();
204 vg_acquire_thread_sync();
205 {
206 vg_tex2d_init( (vg_tex2d *[]){ &localplayer_texture }, 1 );
207 }
208 vg_release_thread_sync();
209 }
210
211 void temp_update_playermodel(void){
212 player__use_mesh( &localplayer, &localplayer_meshes[cl_playermdl_id] );
213 }
214
215 VG_STATIC void vg_load(void)
216 {
217 vg_loader_step( render_init, NULL );
218 vg_loader_step( menu_init, NULL );
219 vg_loader_step( world_init, NULL );
220 //vg_loader_step( player_init, NULL );
221 //vg_loader_step( vehicle_init, NULL );
222 //
223 //vg_loader_step( player_model_init, NULL );
224
225 /* ----------------- */
226 vg_loader_step( load_playermodels, NULL );
227
228 /* player setup */
229 player__create( &localplayer );
230 player_avatar_load( &localplayer_avatar, "models/ch_new.mdl" );
231 player__use_avatar( &localplayer, &localplayer_avatar );
232 player__use_mesh( &localplayer, &localplayer_meshes[cl_playermdl_id] );
233 player__use_texture( &localplayer, &localplayer_texture );
234 player__bind( &localplayer );
235
236 /* --------------------- */
237
238 vg_bake_shaders();
239 vg_loader_step( audio_init, audio_free );
240
241 /* 'systems' are completely loaded now */
242
243 /* load home world */
244 //world_load( &world_global.worlds[0], "maps/mp_gridmap.mdl" );
245 world_load( &world_global.worlds[0], "maps/mp_mtzero.mdl" );
246
247 #if 0
248 world_load( &world_global.worlds[1], "maps/mp_gridmap.mdl" );
249 world_link_nonlocal_gates( 0, 1 );
250 world_load( &world_global.worlds[2], "maps/mp_mtzero.mdl" );
251 world_link_nonlocal_gates( 0, 2 );
252 #endif
253
254 vg_console_load_autos();
255 }
256
257 VG_STATIC void vg_start(void)
258 {
259 __respawn( 1, (const char *[]){ "start" } );
260 }
261
262 VG_STATIC void draw_origin_axis(void)
263 {
264 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
265 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
266 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
267 }
268
269 VG_STATIC void vg_update(void)
270 {
271 steam_update();
272
273 if( vg.is_loaded )
274 {
275 draw_origin_axis();
276 network_update();
277
278 #if 0
279 if( !gzoomer.inside )
280 player_update_pre();
281 #endif
282
283 player__pre_update( &localplayer );
284 world_update( get_active_world(), localplayer.rb.co );
285
286 audio_update();
287 }
288 }
289
290 VG_STATIC void vg_update_fixed(void)
291 {
292 if( vg.is_loaded )
293 {
294 #if 0
295 if( !gzoomer.inside )
296 player_update_fixed();
297
298 vehicle_update_fixed();
299 #endif
300
301 player__update( &localplayer );
302 }
303 }
304
305 VG_STATIC void vg_update_post(void)
306 {
307 if( vg.is_loaded )
308 {
309 #if 0
310 if( gzoomer.inside )
311 {
312 vehicle_camera();
313 }
314 else
315 {
316 player_update_post();
317 }
318 #endif
319
320 player__post_update( &localplayer );
321
322
323 float inr3 = 0.57735027,
324 inr2 = 0.70710678118;
325
326 v3f sample_directions[] = {
327 { -1.0f, 0.0f, 0.0f },
328 { 1.0f, 0.0f, 0.0f },
329 { 0.0f, 0.0f, 1.0f },
330 { 0.0f, 0.0f, -1.0f },
331 { 0.0f, 1.0f, 0.0f },
332 { 0.0f, -1.0f, 0.0f },
333 { -inr3, inr3, inr3 },
334 { inr3, inr3, inr3 },
335 { -inr3, inr3, -inr3 },
336 { inr3, inr3, -inr3 },
337 { -inr2, 0.0f, inr2 },
338 { inr2, 0.0f, inr2 },
339 { -inr2, 0.0f, -inr2 },
340 { inr2, 0.0f, -inr2 },
341 };
342
343 static int si = 0;
344 static float distances[16];
345
346 ray_hit ray;
347 ray.dist = 5.0f;
348
349 v3f rc, rd, ro;
350 v3_copy( sample_directions[ si ], rd );
351 v3_add( localplayer.rb.co, (v3f){0.0f,1.5f,0.0f}, ro );
352 v3_copy( ro, rc );
353
354 float dist = 200.0f;
355
356 for( int i=0; i<10; i++ ){
357 if( ray_world( get_active_world(), rc, rd, &ray ) ){
358 dist = (float)i*5.0f + ray.dist;
359 break;
360 }
361 else{
362 v3_muladds( rc, rd, ray.dist, rc );
363 }
364 }
365
366 distances[si] = dist;
367
368
369 for( int i=0; i<14; i++ ){
370 if( distances[i] != 200.0f ){
371 u32 colours[] = { VG__RED, VG__BLUE, VG__GREEN,
372 VG__CYAN, VG__YELOW, VG__PINK,
373 VG__WHITE };
374
375 u32 colour = colours[i%7];
376
377 v3f p1;
378 v3_muladds( ro, sample_directions[i], distances[i], p1 );
379 vg_line( ro, p1, colour );
380 vg_line_pt3( p1, 0.1f, colour );
381 }
382 }
383
384 si ++;
385 if( si >= 14 )
386 si = 0;
387
388
389 /* FIXME: TEMP */
390 audio_lock();
391 vg_dsp.echo_distances[si] = dist;
392
393 v3f ears = { 1.0f,0.0f,0.0f };
394 m3x3_mulv( main_camera.transform, ears, ears );
395 v3_copy( ears, vg_audio.external_listener_ears );
396 v3_copy( main_camera.transform[3], vg_audio.external_listener_pos );
397
398 /* TODO: this is transformed back and fourth twice. */
399 if( localplayer.gate_waiting ){
400 m4x3_mulv( localplayer.gate_waiting->transport,
401 vg_audio.external_listener_pos,
402 vg_audio.external_listener_pos );
403 }
404
405 v3_copy( localplayer.rb.v, vg_audio.external_lister_velocity );
406 audio_unlock();
407
408 menu_update();
409 #if 0
410 vehicle_update_post();
411 #endif
412 }
413 }
414
415 VG_STATIC void vg_framebuffer_resize( int w, int h )
416 {
417 render_fb_resize();
418 }
419
420 VG_STATIC void present_view_with_post_processing(void)
421 {
422 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
423 glViewport( 0,0, vg.window_x, vg.window_y );
424
425 glEnable(GL_BLEND);
426 glDisable(GL_DEPTH_TEST);
427 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
428 glBlendEquation(GL_FUNC_ADD);
429
430 v2f inverse;
431 render_fb_inverse_ratio( gpipeline.fb_main, inverse );
432
433 if( cl_blur ){
434 shader_blitblur_use();
435 shader_blitblur_uTexMain( 0 );
436 shader_blitblur_uTexMotion( 1 );
437 shader_blitblur_uBlurStrength(cl_blur_strength / (vg.frame_delta*60.0f));
438 shader_blitblur_uInverseRatio( inverse );
439
440 v2f menu_blurring;
441 v2_muls( (v2f){ 0.04f, 0.001f }, menu_opacity, menu_blurring );
442 shader_blitblur_uOverrideDir( menu_blurring );
443
444 render_fb_bind_texture( gpipeline.fb_main, 0, 0 );
445 render_fb_bind_texture( gpipeline.fb_main, 1, 1 );
446 }
447 else{
448 shader_blit_use();
449 shader_blit_uTexMain( 0 );
450 shader_blit_uInverseRatio( inverse );
451 render_fb_bind_texture( gpipeline.fb_main, 0, 0 );
452 }
453
454 render_fsquad();
455 }
456
457 VG_STATIC void render_player_transparent(void)
458 {
459 static camera small_cam; /* DOES NOT NEED TO BE STATIC BUT MINGW
460 SAIS OTHERWISE */
461
462 m4x3_copy( main_camera.transform, small_cam.transform );
463
464 small_cam.fov = main_camera.fov;
465 small_cam.nearz = 0.05f;
466 small_cam.farz = 60.0f;
467
468 camera_update_view( &small_cam );
469 camera_update_projection( &small_cam );
470 camera_finalize( &small_cam );
471
472 /* Draw player to window buffer and blend background ontop */
473 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
474 glViewport( 0,0, vg.window_x, vg.window_y );
475 player__render( &small_cam, &localplayer );
476 }
477
478 VG_STATIC void render_scene(void)
479 {
480 render_fb_bind( gpipeline.fb_main, 1 );
481 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
482 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT );
483
484 /* Draw world */
485 glEnable( GL_DEPTH_TEST );
486
487 world_instance *view_world = localplayer.viewable_world;
488
489 if( view_world == NULL ){
490 glClearColor( 0.25f, 0.25f, 0.0f, 1.0f );
491 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT );
492 return;
493 }
494
495 render_world( view_world, &main_camera, 0 );
496
497 render_water_texture( view_world, &main_camera, 0 );
498 render_fb_bind( gpipeline.fb_main, 1 );
499 render_water_surface( view_world, &main_camera );
500
501 int depth = 1;
502 if( localplayer.gate_waiting ) depth = 0;
503 render_world_gates( view_world, &main_camera, depth );
504
505 if( !cl_menu )
506 render_player_transparent();
507 }
508
509 VG_STATIC void render_main_game(void)
510 {
511 #if 0
512 static float fov = 60.0f;
513 float fov_target = vg_lerpf( 90.0f, 110.0f, cl_fov );
514
515 if( player.controller == k_player_controller_skate )
516 fov_target = vg_lerpf( 97.0f, 135.0f, cl_fov );
517
518 if( cl_menu )
519 fov_target = menu_fov_target;
520 fov = vg_lerpf( fov, fov_target, vg.frame_delta * 2.0f );
521 fov = freecam? 60.0f: fov;
522
523 main_camera.fov = fov;
524 #endif
525
526 player__pre_render( &localplayer );
527
528 v3_lerp( localplayer.cam.pos, menu_camera_pos, menu_opacity,
529 main_camera.pos );
530 main_camera.angles[0] =
531 vg_alerpf( localplayer.cam.angles[0], menu_camera_angles[0],
532 menu_opacity );
533 main_camera.angles[1] =
534 vg_lerpf ( localplayer.cam.angles[1], menu_camera_angles[1],
535 menu_opacity );
536
537 main_camera.fov = vg_lerpf( localplayer.cam.fov, menu_smooth_fov,
538 menu_opacity );
539 main_camera.nearz = 0.1f;
540 main_camera.farz = 2100.0f;
541
542 camera_update_transform( &main_camera );
543
544 if( localplayer.gate_waiting ){
545 m3x3_mul( localplayer.basis_gate, main_camera.transform,
546 main_camera.transform );
547 }
548 else{
549 m3x3_mul( localplayer.basis, main_camera.transform,
550 main_camera.transform );
551 }
552
553 camera_update_view( &main_camera );
554 camera_update_projection( &main_camera );
555 camera_finalize( &main_camera );
556
557 /* ========== Begin Frame ========== */
558
559 render_scene();
560
561 if( cl_menu ) {
562 glClear( GL_DEPTH_BUFFER_BIT );
563 menu_render_bg();
564 glEnable( GL_DEPTH_TEST );
565 render_player_transparent();
566 }
567
568 present_view_with_post_processing();
569
570 if( cl_menu )
571 menu_render_fg( &main_camera );
572
573 /* =========== End Frame =========== */
574 }
575
576 VG_STATIC void vg_render(void)
577 {
578 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
579
580 glViewport( 0,0, vg.window_x, vg.window_y );
581 glDisable( GL_DEPTH_TEST );
582
583 glClearColor( 1.0f, 0.0f, 0.0f, 0.0f );
584 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
585
586 render_main_game();
587
588 m4x4_copy( main_camera.mtx.pv, vg.pv );
589
590 /* Other shite */
591 glDisable(GL_BLEND);
592 glDisable(GL_DEPTH_TEST);
593 vg_lines_drawall();
594 glViewport( 0,0, vg.window_x, vg.window_y );
595 }
596
597 VG_STATIC void vg_ui(void)
598 {
599 #if 0
600 player__im_gui( &localplayer );
601 #endif
602 world_instance *world = get_active_world();
603 menu_crap_ui();
604
605 audio_debug_soundscapes();
606 render_view_framebuffer_ui();
607
608 #if 0
609 player_physics_gui();
610 #endif
611 }
612
613 VG_STATIC void run_debug_info(void)
614 {
615 #if 0
616 char buf[40];
617
618 snprintf( buf, 40, "%.2fm/s", v3_length( player.rb.v ) );
619 ui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
620
621 snprintf( buf, 40, "%.2f %.2f %.2f m/s",
622 player.phys.a[0], player.phys.a[1], player.phys.a[2] );
623 ui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
624
625 snprintf( buf, 40, "pos %.2f %.2f %.2f",
626 player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
627 ui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
628
629 if( vg_input.controller_handle )
630 {
631 for( int i=0; i<vg_list_size(vg_input.controller_axises); i++ )
632 {
633 snprintf( buf, 40, "%.2f", vg_input.controller_axises[i] );
634 ui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
635 }
636 }
637 else
638 {
639 ui_text( (ui_px [2]){ 0, 60 },
640 "Gamepad not ready", 1, k_text_align_left );
641 }
642 #endif
643 }