achievements and stuff
[carveJwlIkooP6JGAAIwe30JlM.git] / world_gen.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef WORLD_GEN_H
6 #define WORLD_GEN_H
7
8 /*
9 * FUTURE:
10 * If we have multiple levels, write an unloader
11 */
12
13 #include "world.h"
14
15 static void world_add_all_if_material( m4x3f transform, scene *pscene,
16 mdl_header *mdl, u32 id )
17 {
18 for( int i=0; i<mdl->node_count; i++ )
19 {
20 mdl_node *pnode = mdl_node_from_id( mdl, i );
21
22 for( int j=0; j<pnode->submesh_count; j++ )
23 {
24 mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
25
26 if( sm->material_id == id )
27 {
28 m4x3f transform2;
29 mdl_node_transform( pnode, transform2 );
30 m4x3_mul( transform, transform2, transform2 );
31
32 scene_add_submesh( pscene, mdl, sm, transform2 );
33 }
34 }
35
36 if( pnode->classtype == k_classtype_instance )
37 {
38 if( pnode->sub_uid )
39 {
40 u32 instance_id = pnode->sub_uid -1;
41 struct instance_cache *cache = &world.instance_cache[instance_id];
42 mdl_header *mdl2 = cache->mdl;
43
44 m4x3f transform2;
45 mdl_node_transform( pnode, transform2 );
46 m4x3_mul( transform, transform2, transform2 );
47
48 world_add_all_if_material( transform2, pscene, mdl2, id );
49 }
50 }
51 }
52 }
53
54 static void world_apply_procedural_foliage(void)
55 {
56 mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
57
58 v3f volume;
59 v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume );
60 volume[1] = 1.0f;
61
62 m4x3f transform;
63 mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" );
64 mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 );
65
66 for( int i=0;i<100000;i++ )
67 {
68 v3f pos;
69 v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
70 pos[1] = 1000.0f;
71 v3_add( pos, world.geo.bbx[0], pos );
72
73 ray_hit hit;
74 hit.dist = INFINITY;
75
76 if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
77 {
78 if( (hit.normal[1] > 0.8f) && ray_hit_is_terrain(&hit) &&
79 (hit.pos[1] > 0.0f+10.0f) )
80 {
81 v4f qsurface, qrandom;
82 v3f axis;
83
84 v3_cross( (v3f){0.0f,1.0f,0.0f}, hit.normal, axis );
85
86 float angle = v3_dot(hit.normal,(v3f){0.0f,1.0f,0.0f});
87 q_axis_angle( qsurface, axis, angle );
88 q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf );
89 q_mul( qsurface, qrandom, qsurface );
90 q_m3x3( qsurface, transform );
91
92 v3_copy( hit.pos, transform[3] );
93 scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform);
94 }
95 }
96 }
97
98 vg_free( mfoliage );
99 }
100
101 static void world_load(void)
102 {
103 mdl_header *mworld = mdl_load( "models/mp_dev.mdl" );
104 vg_info( "Loading world: models/mp_dev.mdl\n" );
105
106 world.spawn_count = 0;
107 world.traffic_count = 0;
108 world.instance_cache = NULL;
109
110 /*
111 * Process entities
112 */
113 for( int i=0; i<mworld->node_count; i++ )
114 {
115 mdl_node *pnode = mdl_node_from_id( mworld, i );
116
117 if( pnode->classtype == k_classtype_none )
118 {}
119 else if( pnode->classtype == k_classtype_spawn )
120 {
121 struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
122
123 v3_copy( pnode->co, rp->co );
124 v4_copy( pnode->q, rp->q );
125 strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) );
126 }
127 else if( pnode->classtype == k_classtype_water )
128 {
129 if( wrender.enabled )
130 {
131 vg_warn( "Multiple water surfaces in level! ('%s')\n",
132 mdl_pstr( mworld, pnode->pstr_name ));
133 continue;
134 }
135
136 mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 );
137
138 if( sm )
139 {
140 vg_acquire_thread_sync();
141 {
142 glmesh surf;
143 mdl_unpack_submesh( mworld, &surf, sm );
144 water_set_surface( &surf, pnode->co[1] );
145 }
146 vg_release_thread_sync();
147 }
148 }
149 else if( pnode->classtype == k_classtype_car_path )
150 {
151 struct classtype_car_path *p = mdl_get_entdata( mworld, pnode );
152 traffic_node *tn = &world.traffic[ world.traffic_count ];
153 tn->mn_next = NULL;
154 tn->mn_next1 = NULL;
155
156 if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target );
157 if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 );
158
159 m4x3f transform;
160 mdl_node_transform( pnode, transform );
161 m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h );
162 v3_copy( transform[3], tn->co );
163
164 pnode->sub_uid = world.traffic_count ++;
165 }
166 else if( pnode->classtype == k_classtype_instance )
167 {
168 struct classtype_instance *inst = mdl_get_entdata( mworld, pnode );
169 pnode->sub_uid = 0;
170
171 int cached = 0;
172 for( int i=0; i<world.instance_cache_count; i++ )
173 {
174 struct instance_cache *cache = &world.instance_cache[i];
175 if( inst->pstr_file == cache->pstr_file )
176 {
177 cached = 1;
178 pnode->sub_uid = i+1;
179 break;
180 }
181 }
182
183 if( !cached )
184 {
185 world.instance_cache = buffer_reserve(
186 world.instance_cache, world.instance_cache_count,
187 &world.instance_cache_cap, 1,
188 sizeof(struct instance_cache) );
189
190 struct instance_cache *cache =
191 &world.instance_cache[world.instance_cache_count];
192
193 const char *filename = mdl_pstr(mworld, inst->pstr_file);
194
195 cache->pstr_file = inst->pstr_file;
196 cache->mdl = mdl_load( filename );
197
198 if( cache->mdl )
199 {
200 world.instance_cache_count ++;
201 pnode->sub_uid = world.instance_cache_count;
202 mdl_link_materials( mworld, cache->mdl );
203 vg_success( "Cached %s\n", filename );
204 }
205 else
206 {
207 vg_warn( "Failed to cache %s\n", filename );
208 }
209 }
210 }
211 else if( pnode->classtype == k_classtype_achievement_box )
212 {
213 world.achievement_zones =
214 buffer_reserve( world.achievement_zones,
215 world.achievement_zones_count,
216 &world.achievement_zones_cap, 1,
217 sizeof(struct achievement_zone) );
218
219 struct achievement_zone *zone = &world.achievement_zones[
220 world.achievement_zones_count ++ ];
221
222
223 struct classtype_achievement_box *box = mdl_get_entdata(mworld,pnode);
224
225 mdl_node_transform( pnode, zone->transform );
226 m4x3_invert_full( zone->transform, zone->inv_transform );
227 vg_strncpy( mdl_pstr(mworld, box->pstr_name), zone->name, 31 );
228 zone->name[31] = 0x00;
229 zone->triggered = 0;
230 }
231 }
232
233 world.instance_cache = buffer_fix( world.instance_cache,
234 world.instance_cache_count,
235 &world.instance_cache_cap,
236 sizeof( struct instance_cache ) );
237
238 #if 0
239 traffic_finalize( world.traffic, world.traffic_count );
240 for( int i=0; i<vg_list_size(world.van_man); i++ )
241 world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
242 #endif
243
244 /*
245 * Compile meshes into the world scenes
246 */
247 scene_init( &world.geo );
248
249 u32 mat_surf = 0,
250 mat_surf_oob = 0,
251 mat_vertex_blend = 0,
252 mat_alphatest = 0,
253 mat_graffiti = 0,
254 mat_subworld = 0,
255 mat_terrain = 0;
256
257 for( int i=1; i<mworld->material_count; i++ )
258 {
259 mdl_material *mat = mdl_material_from_id( mworld, i );
260 const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
261
262 if( !strcmp( "surf", mat_name ))
263 mat_surf = i;
264 else if( !strcmp( "surf_oob", mat_name ))
265 mat_surf_oob = i;
266 else if( !strcmp( "vertex_blend", mat_name ))
267 mat_vertex_blend = i;
268 else if( !strcmp( "alphatest", mat_name ))
269 mat_alphatest = i;
270 else if( !strcmp( "graffitibox", mat_name ))
271 mat_graffiti = i;
272 else if( !strcmp( "terrain", mat_name ) )
273 mat_terrain = i;
274 }
275
276 m4x3f midentity;
277 m4x3_identity( midentity );
278
279 if( mat_terrain )
280 world_add_all_if_material( midentity, &world.geo, mworld, mat_terrain );
281 scene_copy_slice( &world.geo, &world.sm_terrain );
282
283 if( mat_surf_oob )
284 world_add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
285 else
286 vg_warn( "No OOB surface\n" );
287 scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
288
289 if( mat_surf )
290 world_add_all_if_material( midentity, &world.geo, mworld, mat_surf );
291 scene_copy_slice( &world.geo, &world.sm_geo_std );
292
293 if( mat_vertex_blend )
294 world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend);
295 scene_copy_slice( &world.geo, &world.sm_geo_vb );
296
297 vg_acquire_thread_sync();
298 scene_upload( &world.geo );
299 vg_release_thread_sync();
300
301 scene_bh_create( &world.geo );
302
303
304 /* Foliage /nocollide layer.
305 * TODO: Probably should have material traits for this
306 */
307 scene_init( &world.foliage );
308
309 world_apply_procedural_foliage();
310 scene_copy_slice( &world.foliage, &world.sm_foliage_main );
311
312 world_add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest);
313 scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
314
315 world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti );
316 scene_copy_slice( &world.foliage, &world.sm_graffiti );
317
318
319 vg_acquire_thread_sync();
320 {
321 scene_upload( &world.foliage );
322
323 /*
324 * Rendering the depth map
325 */
326 m4x4f ortho;
327 m4x3f camera;
328
329 v3f extent;
330 v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
331
332 float fl = world.geo.bbx[0][0],
333 fr = world.geo.bbx[1][0],
334 fb = world.geo.bbx[0][2],
335 ft = world.geo.bbx[1][2],
336 rl = 1.0f / (fr-fl),
337 tb = 1.0f / (ft-fb);
338
339 m4x4_zero( ortho );
340 ortho[0][0] = 2.0f * rl;
341 ortho[2][1] = 2.0f * tb;
342 ortho[3][0] = (fr + fl) * -rl;
343 ortho[3][1] = (ft + fb) * -tb;
344 ortho[3][3] = 1.0f;
345 m4x3_identity( camera );
346
347 glViewport( 0, 0, 1024, 1024 );
348 glDisable(GL_DEPTH_TEST);
349 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
350 shader_fscolour_use();
351 shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
352 render_fsquad();
353
354 glEnable(GL_BLEND);
355 glBlendFunc(GL_ONE, GL_ONE);
356 glBlendEquation(GL_MAX);
357 render_world_depth( ortho, camera );
358 glDisable(GL_BLEND);
359 glEnable(GL_DEPTH_TEST);
360 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
361
362
363 /*
364 * TODO: World settings entity
365 */
366 struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
367 v4_copy( wrender.plane, winfo->g_water_plane );
368
369 v4f bounds;
370 bounds[0] = world.geo.bbx[0][0];
371 bounds[1] = world.geo.bbx[0][2];
372 bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
373 bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
374 v4_copy( bounds, winfo->g_depth_bounds );
375
376 winfo->g_water_fog = 0.04f;
377 render_update_lighting_ub();
378 }
379
380 vg_release_thread_sync();
381
382 world_routes_loadfrom( mworld );
383
384 for( int i=0; i<world.instance_cache_count; i++ )
385 vg_free( world.instance_cache[i].mdl );
386
387 vg_free( world.instance_cache );
388 vg_free( mworld );
389 scene_free_offline_buffers( &world.foliage );
390
391 /*
392 * Setup scene collider
393 */
394 v3_zero( world.rb_geo.co );
395 q_identity( world.rb_geo.q );
396
397 world.rb_geo.type = k_rb_shape_scene;
398 world.rb_geo.inf.scene.pscene = &world.geo;
399 world.rb_geo.is_world = 1;
400 rb_init( &world.rb_geo );
401 }
402
403 #endif /* WORLD_GEN_H */