3 static int ray_world( v3f pos
, v3f dir
, ray_hit
*hit
);
12 #include "rigidbody.h"
18 #include "traffic.h" /*TODO: -> world_traffic.h */
19 #include "world_routes.h"
20 #include "world_sfd.h"
21 #include "world_audio.h"
23 #include "network_msg.h"
25 #include "shaders/terrain.h"
26 #include "shaders/sky.h"
27 #include "shaders/planeinf.h"
28 #include "shaders/standard.h"
29 #include "shaders/vblend.h"
30 #include "shaders/gpos.h"
31 #include "shaders/fscolour.h"
32 #include "shaders/alphatest.h"
46 struct subworld_routes routes
;
47 struct subworld_sfd sfd
;
50 traffic_node traffic
[128];
54 traffic_driver van_man
[6];
59 /* Rendering & geometry */
63 /* TODO Maybe make this less hardcoded */
64 mdl_submesh sm_geo_std_oob
, sm_geo_std
, sm_geo_vb
,
65 sm_foliage_main
, sm_foliage_alphatest
,
66 sm_graffiti
, sm_subworld
, sm_terrain
;
68 glmesh skybox
, skydome
;
69 mdl_submesh dome_upper
, dome_lower
;
72 mdl_submesh car_holden
;
84 u32 instance_cache_count
,
88 int active_route_board
;
92 static struct subworld_routes
*subworld_routes(void) { return &world
.routes
; }
93 static struct subworld_sfd
*subworld_sfd(void) { return &world
.sfd
; }
96 vg_tex2d tex_terrain_colours
= { .path
= "textures/gradients.qoi",
97 .flags
= VG_TEXTURE_CLAMP
|VG_TEXTURE_NEAREST
};
99 vg_tex2d tex_terrain_noise
= { .path
= "textures/garbage.qoi",
100 .flags
= VG_TEXTURE_NEAREST
};
102 vg_tex2d tex_alphatest
= { .path
= "textures/alphatest.qoi",
103 .flags
= VG_TEXTURE_NEAREST
};
105 vg_tex2d tex_graffiti
= { .path
= "textures/graffitibox.qoi",
106 .flags
= VG_TEXTURE_NEAREST
};
108 static void ray_world_get_tri( ray_hit
*hit
, v3f tri
[3] )
110 for( int i
=0; i
<3; i
++ )
111 v3_copy( world
.geo
.verts
[ hit
->tri
[i
] ].co
, tri
[i
] );
114 static int ray_world( v3f pos
, v3f dir
, ray_hit
*hit
)
116 return scene_raycast( &world
.geo
, pos
, dir
, hit
);
119 static int ray_hit_is_terrain( ray_hit
*hit
)
122 valid_end
= world
.sm_terrain
.vertex_count
;
124 return (hit
->tri
[0] >= valid_start
) &&
125 (hit
->tri
[0] < valid_end
);
128 static int ray_hit_is_ramp( ray_hit
*hit
)
130 u32 valid_start
= world
.sm_geo_std
.vertex_start
,
131 valid_end
= world
.sm_geo_vb
.vertex_start
;
133 return (hit
->tri
[0] >= valid_start
) &&
134 (hit
->tri
[0] < valid_end
);
137 static void world_register(void)
139 shader_terrain_register();
140 shader_sky_register();
141 shader_planeinf_register();
142 shader_gpos_register();
143 shader_fscolour_register();
144 shader_alphatest_register();
146 world_routes_register();
147 world_sfd_register();
150 static void world_free(void)
157 static void render_world_depth( m4x4f projection
, m4x3f camera
);
159 static void add_all_if_material( m4x3f transform
, scene
*pscene
,
160 mdl_header
*mdl
, u32 id
)
162 for( int i
=0; i
<mdl
->node_count
; i
++ )
164 mdl_node
*pnode
= mdl_node_from_id( mdl
, i
);
166 for( int j
=0; j
<pnode
->submesh_count
; j
++ )
168 mdl_submesh
*sm
= mdl_node_submesh( mdl
, pnode
, j
);
170 if( sm
->material_id
== id
)
173 mdl_node_transform( pnode
, transform2
);
174 m4x3_mul( transform
, transform2
, transform2
);
176 scene_add_submesh( pscene
, mdl
, sm
, transform2
);
180 if( pnode
->classtype
== k_classtype_instance
)
184 u32 instance_id
= pnode
->sub_uid
-1;
185 struct instance_cache
*cache
= &world
.instance_cache
[instance_id
];
186 mdl_header
*mdl2
= cache
->mdl
;
189 mdl_node_transform( pnode
, transform2
);
190 m4x3_mul( transform
, transform2
, transform2
);
192 add_all_if_material( transform2
, pscene
, mdl2
, id
);
198 static void world_apply_procedural_foliage(void)
200 mdl_header
*mfoliage
= mdl_load("models/rs_foliage.mdl");
203 v3_sub( world
.geo
.bbx
[1], world
.geo
.bbx
[0], volume
);
207 mdl_node
*mblob
= mdl_node_from_name( mfoliage
, "blob" );
208 mdl_submesh
*sm_blob
= mdl_node_submesh( mfoliage
, mblob
, 0 );
210 for( int i
=0;i
<100000;i
++ )
213 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
215 v3_add( pos
, world
.geo
.bbx
[0], pos
);
220 if( ray_world( pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
222 if( (hit
.normal
[1] > 0.8f
) && ray_hit_is_terrain(&hit
) &&
223 (hit
.pos
[1] > water_height()+10.0f
) )
225 v4f qsurface
, qrandom
;
228 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
.normal
, axis
);
230 float angle
= v3_dot(hit
.normal
,(v3f
){0.0f
,1.0f
,0.0f
});
231 q_axis_angle( qsurface
, axis
, angle
);
232 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf()*VG_TAUf
);
233 q_mul( qsurface
, qrandom
, qsurface
);
234 q_m3x3( qsurface
, transform
);
236 v3_copy( hit
.pos
, transform
[3] );
237 scene_add_submesh( &world
.foliage
, mfoliage
, sm_blob
, transform
);
244 static void world_load(void)
246 mdl_header
*mworld
= mdl_load( "models/mp_dev.mdl" );
248 world
.spawn_count
= 0;
249 world
.traffic_count
= 0;
250 world
.instance_cache
= NULL
;
255 for( int i
=0; i
<mworld
->node_count
; i
++ )
257 mdl_node
*pnode
= mdl_node_from_id( mworld
, i
);
259 if( pnode
->classtype
== k_classtype_none
)
261 else if( pnode
->classtype
== k_classtype_spawn
)
263 struct respawn_point
*rp
= &world
.spawns
[ world
.spawn_count
++ ];
265 v3_copy( pnode
->co
, rp
->co
);
266 v4_copy( pnode
->q
, rp
->q
);
267 strcpy( rp
->name
, mdl_pstr( mworld
, pnode
->pstr_name
) );
269 else if( pnode
->classtype
== k_classtype_water
)
271 if( wrender
.enabled
)
273 vg_warn( "Multiple water surfaces in level! ('%s')\n",
274 mdl_pstr( mworld
, pnode
->pstr_name
));
278 mdl_submesh
*sm
= mdl_node_submesh( mworld
, pnode
, 0 );
283 mdl_unpack_submesh( mworld
, &surf
, sm
);
285 water_set_surface( &surf
, pnode
->co
[1] );
288 else if( pnode
->classtype
== k_classtype_car_path
)
290 struct classtype_car_path
*p
= mdl_get_entdata( mworld
, pnode
);
291 traffic_node
*tn
= &world
.traffic
[ world
.traffic_count
];
295 if( p
->target
) tn
->mn_next
= mdl_node_from_id( mworld
, p
->target
);
296 if( p
->target1
) tn
->mn_next1
= mdl_node_from_id( mworld
, p
->target1
);
299 mdl_node_transform( pnode
, transform
);
300 m3x3_mulv( transform
, (v3f
){1.0f
,0.0f
,0.0f
}, tn
->h
);
301 v3_copy( transform
[3], tn
->co
);
303 pnode
->sub_uid
= world
.traffic_count
++;
305 else if( pnode
->classtype
== k_classtype_instance
)
307 struct classtype_instance
*inst
= mdl_get_entdata( mworld
, pnode
);
311 for( int i
=0; i
<world
.instance_cache_count
; i
++ )
313 struct instance_cache
*cache
= &world
.instance_cache
[i
];
314 if( inst
->pstr_file
== cache
->pstr_file
)
317 pnode
->sub_uid
= i
+1;
324 world
.instance_cache
= buffer_reserve(
325 world
.instance_cache
, world
.instance_cache_count
,
326 &world
.instance_cache_cap
, 1,
327 sizeof(struct instance_cache
) );
329 struct instance_cache
*cache
=
330 &world
.instance_cache
[world
.instance_cache_count
];
332 const char *filename
= mdl_pstr(mworld
, inst
->pstr_file
);
334 cache
->pstr_file
= inst
->pstr_file
;
335 cache
->mdl
= mdl_load( filename
);
339 world
.instance_cache_count
++;
340 pnode
->sub_uid
= world
.instance_cache_count
;
341 mdl_link_materials( mworld
, cache
->mdl
);
342 vg_success( "Cached %s\n", filename
);
346 vg_warn( "Failed to cache %s\n", filename
);
352 world
.instance_cache
= buffer_fix( world
.instance_cache
,
353 world
.instance_cache_count
,
354 &world
.instance_cache_cap
,
355 sizeof( struct instance_cache
) );
358 traffic_finalize( world
.traffic
, world
.traffic_count
);
359 for( int i
=0; i
<vg_list_size(world
.van_man
); i
++ )
360 world
.van_man
[i
].current
=&world
.traffic
[vg_randint(world
.traffic_count
)];
364 * Compile meshes into the world scenes
366 scene_init( &world
.geo
);
370 mat_vertex_blend
= 0,
376 for( int i
=1; i
<mworld
->material_count
; i
++ )
378 mdl_material
*mat
= mdl_material_from_id( mworld
, i
);
379 const char *mat_name
= mdl_pstr( mworld
, mat
->pstr_name
);
381 if( !strcmp( "surf", mat_name
))
383 else if( !strcmp( "surf_oob", mat_name
))
385 else if( !strcmp( "vertex_blend", mat_name
))
386 mat_vertex_blend
= i
;
387 else if( !strcmp( "alphatest", mat_name
))
389 else if( !strcmp( "graffitibox", mat_name
))
391 else if( !strcmp( "terrain", mat_name
) )
396 m4x3_identity( midentity
);
399 add_all_if_material( midentity
, &world
.geo
, mworld
, mat_terrain
);
400 scene_copy_slice( &world
.geo
, &world
.sm_terrain
);
403 add_all_if_material( midentity
, &world
.geo
, mworld
, mat_surf_oob
);
405 vg_warn( "No OOB surface\n" );
406 scene_copy_slice( &world
.geo
, &world
.sm_geo_std_oob
);
409 add_all_if_material( midentity
, &world
.geo
, mworld
, mat_surf
);
410 scene_copy_slice( &world
.geo
, &world
.sm_geo_std
);
412 if( mat_vertex_blend
)
413 add_all_if_material( midentity
, &world
.geo
, mworld
, mat_vertex_blend
);
414 scene_copy_slice( &world
.geo
, &world
.sm_geo_vb
);
416 scene_upload( &world
.geo
);
417 scene_bh_create( &world
.geo
);
420 /* Foliage /nocollide layer.
421 * TODO: Probably should have material traits for this
423 scene_init( &world
.foliage
);
425 world_apply_procedural_foliage();
426 scene_copy_slice( &world
.foliage
, &world
.sm_foliage_main
);
428 add_all_if_material( midentity
, &world
.foliage
, mworld
, mat_alphatest
);
429 scene_copy_slice( &world
.foliage
, &world
.sm_foliage_alphatest
);
431 add_all_if_material( midentity
, &world
.foliage
, mworld
, mat_graffiti
);
432 scene_copy_slice( &world
.foliage
, &world
.sm_graffiti
);
434 scene_upload( &world
.foliage
);
435 world_routes_loadfrom( mworld
);
437 for( int i
=0; i
<world
.instance_cache_count
; i
++ )
438 free( world
.instance_cache
[i
].mdl
);
440 free( world
.instance_cache
);
444 * Rendering the depth map
450 v3_sub( world
.geo
.bbx
[1], world
.geo
.bbx
[0], extent
);
452 float fl
= world
.geo
.bbx
[0][0],
453 fr
= world
.geo
.bbx
[1][0],
454 fb
= world
.geo
.bbx
[0][2],
455 ft
= world
.geo
.bbx
[1][2],
460 ortho
[0][0] = 2.0f
* rl
;
461 ortho
[2][1] = 2.0f
* tb
;
462 ortho
[3][0] = (fr
+ fl
) * -rl
;
463 ortho
[3][1] = (ft
+ fb
) * -tb
;
465 m4x3_identity( camera
);
467 glViewport( 0, 0, 1024, 1024 );
468 glDisable(GL_DEPTH_TEST
);
469 glBindFramebuffer( GL_FRAMEBUFFER
, gpipeline
.fb_depthmap
);
470 shader_fscolour_use();
471 shader_fscolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
475 glBlendFunc(GL_ONE
, GL_ONE
);
476 glBlendEquation(GL_MAX
);
477 render_world_depth( ortho
, camera
);
479 glEnable(GL_DEPTH_TEST
);
482 * TODO: World settings entity
484 struct ub_world_lighting
*winfo
= &gpipeline
.ub_world_lighting
;
485 v4_copy( wrender
.plane
, winfo
->g_water_plane
);
488 bounds
[0] = world
.geo
.bbx
[0][0];
489 bounds
[1] = world
.geo
.bbx
[0][2];
490 bounds
[2] = 1.0f
/ (world
.geo
.bbx
[1][0]-world
.geo
.bbx
[0][0]);
491 bounds
[3] = 1.0f
/ (world
.geo
.bbx
[1][2]-world
.geo
.bbx
[0][2]);
492 v4_copy( bounds
, winfo
->g_depth_bounds
);
494 winfo
->g_water_fog
= 0.04f
;
495 render_update_lighting_ub();
498 world
.mr_ball
.type
= k_rb_shape_sphere
;
499 world
.mr_ball
.inf
.sphere
.radius
= 2.0f
;
500 v3_copy( (v3f
){ 0.0f
, 110.0f
, 0.0f
}, world
.mr_ball
.co
);
502 q_identity(world
.mr_ball
.q
);
503 rb_init( &world
.mr_ball
);
506 * Setup scene collider
508 v3_zero( world
.rb_geo
.co
);
509 q_identity( world
.rb_geo
.q
);
511 world
.rb_geo
.type
= k_rb_shape_scene
;
512 world
.rb_geo
.inf
.scene
.pscene
= &world
.geo
;
513 world
.rb_geo
.is_world
= 1;
514 rb_init( &world
.rb_geo
);
517 static void world_init(void)
519 vg_tex2d_init( (vg_tex2d
*[]){ &tex_terrain_colours
,
522 &tex_graffiti
}, 4 );
524 mdl_header
*mcars
= mdl_load( "models/rs_cars.mdl" );
525 mdl_unpack_glmesh( mcars
, &world
.cars
);
526 mdl_node
*nholden
= mdl_node_from_name( mcars
, "holden" );
527 world
.car_holden
= *mdl_node_submesh( mcars
, nholden
, 0 );
531 mdl_header
*msky
= mdl_load("models/rs_skydome.mdl");
532 mdl_unpack_glmesh( msky
, &world
.skydome
);
534 mdl_node
*nlower
= mdl_node_from_name( msky
, "dome_lower" ),
535 *nupper
= mdl_node_from_name( msky
, "dome_upper" );
537 world
.dome_lower
= *mdl_node_submesh( msky
, nlower
, 0 );
538 world
.dome_upper
= *mdl_node_submesh( msky
, nupper
, 0 );
547 static void world_update(void)
549 world_routes_update();
550 world_routes_debug();
553 float min_dist
= INFINITY
;
555 for( int i
=0; i
<world
.routes
.route_count
; i
++ )
557 float dist
= v3_dist2( world
.routes
.routes
[i
].scoreboard_transform
[3],
560 if( dist
< min_dist
)
567 if( (world
.active_route_board
!= closest
) || network_scores_updated
)
569 network_scores_updated
= 0;
570 world
.active_route_board
= closest
;
571 struct subworld_sfd
*sfd
= subworld_sfd();
573 struct route
*route
= &world
.routes
.routes
[closest
];
575 u32 id
= route
->track_id
;
577 if( id
!= 0xffffffff )
579 struct netmsg_board
*local_board
= &scoreboard_client_data
.boards
[id
];
581 for( int i
=0; i
<13; i
++ )
583 sfd_encode( &sfd
->tester
, i
, &local_board
->data
[27*i
] );
588 sfd_update( &world
.sfd
.tester
);
592 rb_build_manifold_terrain_sphere( &world
.mr_ball
);
594 for( int i
=0; i
<5; i
++ )
595 rb_solve_contacts( rb_contact_buffer
, rb_contact_count
);
597 rb_iter( &world
.mr_ball
);
598 rb_update_transform( &world
.mr_ball
);
599 rb_debug( &world
.mr_ball
, 0 );
601 for( int i
=0; i
<vg_list_size(world
.van_man
); i
++ )
603 traffic_drive( &world
.van_man
[i
] );
604 traffic_visualize_car( &world
.van_man
[i
] );
613 static void bind_terrain_textures(void)
615 vg_tex2d_bind( &tex_terrain_noise
, 0 );
616 vg_tex2d_bind( &tex_terrain_colours
, 1 );
619 static void render_world_vb( m4x4f projection
, v3f camera
)
621 m4x3f identity_matrix
;
622 m4x3_identity( identity_matrix
);
625 shader_vblend_uTexGarbage(0);
626 shader_vblend_uTexGradients(1);
627 shader_link_standard_ub( _shader_vblend
.id
, 2 );
628 bind_terrain_textures();
630 shader_vblend_uPv( projection
);
631 shader_vblend_uMdl( identity_matrix
);
632 shader_vblend_uCamera( camera
);
634 scene_bind( &world
.geo
);
635 mdl_draw_submesh( &world
.sm_geo_vb
);
637 mesh_bind( &world
.cars
);
640 for( int i
=0; i
<vg_list_size(world
.van_man
); i
++ )
642 shader_vblend_uMdl( world
.van_man
[i
].transform
);
643 mdl_draw_submesh( &world
.car_holden
);
648 static void render_world_alphatest( m4x4f projection
, v3f camera
)
650 m4x3f identity_matrix
;
651 m4x3_identity( identity_matrix
);
653 shader_alphatest_use();
654 shader_alphatest_uTexGarbage(0);
655 shader_alphatest_uTexMain(1);
656 shader_link_standard_ub( _shader_alphatest
.id
, 2 );
658 vg_tex2d_bind( &tex_terrain_noise
, 0 );
659 vg_tex2d_bind( &tex_alphatest
, 1 );
661 shader_alphatest_uPv( projection
);
662 shader_alphatest_uMdl( identity_matrix
);
663 shader_alphatest_uCamera( camera
);
665 glDisable(GL_CULL_FACE
);
666 scene_bind( &world
.foliage
);
667 mdl_draw_submesh( &world
.sm_foliage_alphatest
);
669 vg_tex2d_bind( &tex_graffiti
, 1 );
670 mdl_draw_submesh( &world
.sm_graffiti
);
672 glEnable(GL_CULL_FACE
);
675 static void render_terrain( m4x4f projection
, v3f camera
)
677 m4x3f identity_matrix
;
678 m4x3_identity( identity_matrix
);
680 shader_terrain_use();
681 shader_terrain_uTexGarbage(0);
682 shader_terrain_uTexGradients(1);
683 shader_link_standard_ub( _shader_terrain
.id
, 2 );
684 bind_terrain_textures();
686 shader_terrain_uPv( projection
);
687 shader_terrain_uMdl( identity_matrix
);
688 shader_terrain_uCamera( camera
);
690 scene_bind( &world
.geo
);
691 mdl_draw_submesh( &world
.sm_terrain
);
692 mdl_draw_submesh( &world
.sm_geo_std_oob
);
693 mdl_draw_submesh( &world
.sm_geo_std
);
694 mdl_draw_submesh( &world
.sm_subworld
);
696 /* TODO: Dont draw in reflection */
697 glDisable(GL_CULL_FACE
);
698 scene_bind( &world
.foliage
);
699 mdl_draw_submesh( &world
.sm_foliage_main
);
700 glEnable(GL_CULL_FACE
);
703 static void render_lowerdome( m4x3f camera
)
705 m4x4f projection
, full
;
706 pipeline_projection( projection
, 0.4f
, 1000.0f
);
709 m3x3_transpose( camera
, inverse
);
710 v3_copy((v3f
){0.0f
,0.0f
,0.0f
}, inverse
[3]);
711 m4x3_expand( inverse
, full
);
712 m4x4_mul( projection
, full
, full
);
714 m4x3f identity_matrix
;
715 m4x3_identity( identity_matrix
);
717 shader_planeinf_use();
718 shader_planeinf_uMdl(identity_matrix
);
719 shader_planeinf_uPv(full
);
720 shader_planeinf_uCamera(camera
[3]);
721 shader_planeinf_uPlane( (v4f
){0.0f
,1.0f
,0.0f
, water_height()} );
723 mdl_draw_submesh( &world
.dome_lower
);
726 static void render_sky(m4x3f camera
)
728 m4x4f projection
, full
;
729 pipeline_projection( projection
, 0.4f
, 1000.0f
);
732 m3x3_transpose( camera
, inverse
);
733 v3_copy((v3f
){0.0f
,0.0f
,0.0f
}, inverse
[3]);
734 m4x3_expand( inverse
, full
);
735 m4x4_mul( projection
, full
, full
);
737 m4x3f identity_matrix
;
738 m4x3_identity( identity_matrix
);
741 shader_sky_uMdl(identity_matrix
);
742 shader_sky_uPv(full
);
743 shader_sky_uTexGarbage(0);
744 shader_sky_uTime( vg_time
);
746 vg_tex2d_bind( &tex_terrain_noise
, 0 );
748 glDepthMask( GL_FALSE
);
749 glDisable( GL_DEPTH_TEST
);
751 mesh_bind( &world
.skydome
);
752 mdl_draw_submesh( &world
.dome_upper
);
754 glEnable( GL_DEPTH_TEST
);
755 glDepthMask( GL_TRUE
);
758 static void render_world_gates( m4x4f projection
, v3f playerco
, m4x3f camera
)
760 float closest
= INFINITY
;
763 for( int i
=0; i
<world
.routes
.gate_count
; i
++ )
765 struct route_gate
*rg
= &world
.routes
.gates
[i
];
766 float dist
= v3_dist2( rg
->gate
.co
[0], camera
[3] );
775 render_gate( &world
.routes
.gates
[id
].gate
, playerco
, camera
);
776 v3_lerp( world
.render_gate_pos
,
777 world
.routes
.gates
[id
].gate
.co
[0],
779 world
.render_gate_pos
);
782 static void render_world( m4x4f projection
, m4x3f camera
)
784 render_sky( camera
);
785 render_world_routes( projection
, camera
[3] );
786 render_world_vb( projection
, camera
[3] );
787 render_world_alphatest( projection
, camera
[3] );
788 render_terrain( projection
, camera
[3] );
791 float min_dist
= INFINITY
;
793 for( int i
=0; i
<world
.routes
.route_count
; i
++ )
795 float dist
= v3_dist2( world
.routes
.routes
[i
].scoreboard_transform
[3],
798 if( dist
< min_dist
)
805 sfd_render( &world
.sfd
.tester
, projection
, camera
[3],
806 world
.routes
.routes
[closest
].scoreboard_transform
);
809 static void render_world_depth( m4x4f projection
, m4x3f camera
)
811 m4x3f identity_matrix
;
812 m4x3_identity( identity_matrix
);
815 shader_gpos_uCamera( camera
[3] );
816 shader_gpos_uPv( projection
);
817 shader_gpos_uMdl( identity_matrix
);
819 scene_bind( &world
.geo
);
820 scene_draw( &world
.geo
);
823 glDisable(GL_CULL_FACE
);
824 scene_bind( &world
.foliage
);
825 scene_draw( &world
.foliage
);
826 glEnable(GL_CULL_FACE
);