Notices & clean
[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 }
212
213 world.instance_cache = buffer_fix( world.instance_cache,
214 world.instance_cache_count,
215 &world.instance_cache_cap,
216 sizeof( struct instance_cache ) );
217
218 #if 0
219 traffic_finalize( world.traffic, world.traffic_count );
220 for( int i=0; i<vg_list_size(world.van_man); i++ )
221 world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
222 #endif
223
224 /*
225 * Compile meshes into the world scenes
226 */
227 scene_init( &world.geo );
228
229 u32 mat_surf = 0,
230 mat_surf_oob = 0,
231 mat_vertex_blend = 0,
232 mat_alphatest = 0,
233 mat_graffiti = 0,
234 mat_subworld = 0,
235 mat_terrain = 0;
236
237 for( int i=1; i<mworld->material_count; i++ )
238 {
239 mdl_material *mat = mdl_material_from_id( mworld, i );
240 const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
241
242 if( !strcmp( "surf", mat_name ))
243 mat_surf = i;
244 else if( !strcmp( "surf_oob", mat_name ))
245 mat_surf_oob = i;
246 else if( !strcmp( "vertex_blend", mat_name ))
247 mat_vertex_blend = i;
248 else if( !strcmp( "alphatest", mat_name ))
249 mat_alphatest = i;
250 else if( !strcmp( "graffitibox", mat_name ))
251 mat_graffiti = i;
252 else if( !strcmp( "terrain", mat_name ) )
253 mat_terrain = i;
254 }
255
256 m4x3f midentity;
257 m4x3_identity( midentity );
258
259 if( mat_terrain )
260 world_add_all_if_material( midentity, &world.geo, mworld, mat_terrain );
261 scene_copy_slice( &world.geo, &world.sm_terrain );
262
263 if( mat_surf_oob )
264 world_add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
265 else
266 vg_warn( "No OOB surface\n" );
267 scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
268
269 if( mat_surf )
270 world_add_all_if_material( midentity, &world.geo, mworld, mat_surf );
271 scene_copy_slice( &world.geo, &world.sm_geo_std );
272
273 if( mat_vertex_blend )
274 world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend);
275 scene_copy_slice( &world.geo, &world.sm_geo_vb );
276
277 vg_acquire_thread_sync();
278 scene_upload( &world.geo );
279 vg_release_thread_sync();
280
281 scene_bh_create( &world.geo );
282
283
284 /* Foliage /nocollide layer.
285 * TODO: Probably should have material traits for this
286 */
287 scene_init( &world.foliage );
288
289 world_apply_procedural_foliage();
290 scene_copy_slice( &world.foliage, &world.sm_foliage_main );
291
292 world_add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest);
293 scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
294
295 world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti );
296 scene_copy_slice( &world.foliage, &world.sm_graffiti );
297
298
299 vg_acquire_thread_sync();
300 {
301 scene_upload( &world.foliage );
302
303 /*
304 * Rendering the depth map
305 */
306 m4x4f ortho;
307 m4x3f camera;
308
309 v3f extent;
310 v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
311
312 float fl = world.geo.bbx[0][0],
313 fr = world.geo.bbx[1][0],
314 fb = world.geo.bbx[0][2],
315 ft = world.geo.bbx[1][2],
316 rl = 1.0f / (fr-fl),
317 tb = 1.0f / (ft-fb);
318
319 m4x4_zero( ortho );
320 ortho[0][0] = 2.0f * rl;
321 ortho[2][1] = 2.0f * tb;
322 ortho[3][0] = (fr + fl) * -rl;
323 ortho[3][1] = (ft + fb) * -tb;
324 ortho[3][3] = 1.0f;
325 m4x3_identity( camera );
326
327 glViewport( 0, 0, 1024, 1024 );
328 glDisable(GL_DEPTH_TEST);
329 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
330 shader_fscolour_use();
331 shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
332 render_fsquad();
333
334 glEnable(GL_BLEND);
335 glBlendFunc(GL_ONE, GL_ONE);
336 glBlendEquation(GL_MAX);
337 render_world_depth( ortho, camera );
338 glDisable(GL_BLEND);
339 glEnable(GL_DEPTH_TEST);
340 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
341
342
343 /*
344 * TODO: World settings entity
345 */
346 struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
347 v4_copy( wrender.plane, winfo->g_water_plane );
348
349 v4f bounds;
350 bounds[0] = world.geo.bbx[0][0];
351 bounds[1] = world.geo.bbx[0][2];
352 bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
353 bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
354 v4_copy( bounds, winfo->g_depth_bounds );
355
356 winfo->g_water_fog = 0.04f;
357 render_update_lighting_ub();
358 }
359
360 vg_release_thread_sync();
361
362 world_routes_loadfrom( mworld );
363
364 for( int i=0; i<world.instance_cache_count; i++ )
365 vg_free( world.instance_cache[i].mdl );
366
367 vg_free( world.instance_cache );
368 vg_free( mworld );
369 scene_free_offline_buffers( &world.foliage );
370
371 /*
372 * Setup scene collider
373 */
374 v3_zero( world.rb_geo.co );
375 q_identity( world.rb_geo.q );
376
377 world.rb_geo.type = k_rb_shape_scene;
378 world.rb_geo.inf.scene.pscene = &world.geo;
379 world.rb_geo.is_world = 1;
380 rb_init( &world.rb_geo );
381 }
382
383 #endif /* WORLD_GEN_H */