vpk loading/models
[csRadar.git] / vmf.h
1 #define SOLID_MAX_SIDES 512
2
3 typedef struct vmf_solid vmf_solid;
4 typedef struct vmf_vert vmf_vert;
5 typedef struct vmf_mat vmf_mat;
6 typedef struct vmf_face vmf_face;
7 typedef struct vmf_userdata vmf_userdata;
8 typedef struct vmf_map vmf_map;
9
10 typedef enum ESolidResult ESolidResult;
11
12 enum ESolidResult
13 {
14 k_ESolidResult_valid,
15 k_ESolidResult_maxsides,
16 k_ESolidResult_invalid,
17 k_ESolidResult_errnomem,
18 k_ESolidResult_corrupt,
19 k_ESolidResult_degenerate
20 };
21
22 struct vmf_vert
23 {
24 v3f co;
25 v3f nrm;
26 v2f xy;
27 };
28
29 struct vmf_face
30 {
31 u32 *indices;
32
33 vdf_node *dispinfo;
34
35 const char *material;
36 int blacklisted;
37 };
38
39 struct vmf_solid
40 {
41 vmf_vert *verts;
42 u32 *indices;
43 };
44
45 struct vmf_mat
46 {
47 char *str;
48 u32 hash;
49 };
50
51 struct vmf_map
52 {
53 vdf_node *root;
54
55 struct vmf_model
56 {
57 char *str;
58 u32 hash;
59
60 mdl_mesh_t mdl;
61 }
62 *models;
63
64 struct vmf_instance
65 {
66 char *name;
67 u32 hash;
68
69 vdf_node *root;
70 }
71 *cache;
72 };
73
74 // IMPLEMENTATION
75
76 void solidgen_ctx_init( vmf_solid *ctx )
77 {
78 const u32 init_size = 128;
79
80 ctx->verts = csr_sb_reserve( NULL, init_size, sizeof(vmf_vert) );
81 ctx->indices = csr_sb_reserve( NULL, init_size, sizeof(u32) );
82 }
83
84 void solidgen_ctx_free( vmf_solid *ctx )
85 {
86 csr_sb_free( ctx->verts );
87 csr_sb_free( ctx->indices );
88 }
89
90 // Compute bounds of solid gen ctx
91 void solidgen_bounds( vmf_solid *ctx, u32 start, u32 end, v3f min, v3f max )
92 {
93 v3f mine = { INFINITY, INFINITY, INFINITY };
94 v3f maxe = {-INFINITY,-INFINITY,-INFINITY };
95
96 for( int i = start; i < end; i ++ )
97 {
98 vmf_vert *vert = ctx->verts + i;
99 float *co = vert->co;
100
101 mine[0] = fminf( mine[0], co[0] );
102 mine[1] = fminf( mine[1], co[1] );
103 mine[2] = fminf( mine[2], co[2] );
104
105 maxe[0] = fmaxf( maxe[0], co[0] );
106 maxe[1] = fmaxf( maxe[1], co[1] );
107 maxe[2] = fmaxf( maxe[2], co[2] );
108 }
109
110 v3_copy( mine, min );
111 v3_copy( maxe, max );
112 }
113
114 struct
115 {
116 vmf_mat *blacklist;
117
118 double planes[ SOLID_MAX_SIDES*4 ];
119 u32 bisectors;
120 }
121 vmf_api;
122
123 // put an extra plane into the planes list
124 void vmf_addbisector( double p[4] )
125 {
126 double *plane = vmf_api.planes + vmf_api.bisectors * 4;
127
128 plane[0] = p[0];
129 plane[1] = p[1];
130 plane[2] = p[2];
131 plane[3] = p[3];
132
133 vmf_api.bisectors ++;
134 }
135
136 void vmf_clearbisectors( void )
137 {
138 vmf_api.bisectors = 0;
139 }
140
141 void vmf_ignore_mat( const char *material )
142 {
143 vmf_api.blacklist = csr_sb_reserve( vmf_api.blacklist, 1, sizeof( vmf_mat ) );
144 vmf_mat *mat = (vmf_mat *)csr_sb_use( vmf_api.blacklist );
145
146 mat->str = csr_malloc( strlen( material ) + 1 );
147 strcpy( mat->str, material );
148
149 mat->hash = djb2( ( const unsigned char * )material );
150 }
151
152 void vmf_clearignore( void )
153 {
154 for( int i = 0; i < csr_sb_count( vmf_api.blacklist ); i ++ )
155 {
156 free( vmf_api.blacklist[ i ].str );
157 }
158
159 csr_sb_free( vmf_api.blacklist );
160 vmf_api.blacklist = NULL;
161 }
162
163 int mat_blacklisted( const char *material )
164 {
165 u32 hash = djb2((const u8 *)material);
166
167 for( int j = 0; j < csr_sb_count( vmf_api.blacklist ); j ++ )
168 {
169 if( vmf_api.blacklist[ j ].hash == hash )
170 {
171 if( !strcmp( material, vmf_api.blacklist[ j ].str ) )
172 {
173 return 1;
174 }
175 }
176 }
177
178 return 0;
179 }
180
181 void sort_coplanar( double p[4], vmf_vert *points, u32 *indices, u32 count )
182 {
183 v3f center = {0.f, 0.f, 0.f};
184 v3f norm;
185 v3d_v3f( p, norm );
186 v3_normalize( norm );
187
188 for( int i = 0; i < count; i ++ )
189 {
190 v3_add( points[ indices[i] ].co, center, center );
191 }
192 v3_divs( center, count, center );
193
194 v3f ref;
195 v3_sub( points[ indices[0] ].co, center, ref );
196
197 // Calc angles compared to ref
198 float *angles = (float*)alloca( sizeof(float)*count );
199 for( int i = 0; i < count; i ++ )
200 {
201 v3f diff;
202 v3f c;
203
204 v3_sub( points[ indices[i] ].co, center, diff );
205 v3_cross( diff, ref, c );
206
207 angles[i] =
208 atan2f( v3_length(c), v3_dot( diff, ref ) )
209 * (v3_dot( c, norm ) < 0.f ? -1.f: 1.f);
210 }
211
212 // Temporary local indexes
213 u32 *temp_indices = (u32 *)alloca( sizeof(u32)*count );
214 for( u32 i = 0; i < count; i ++ ) temp_indices[i] = i;
215
216 // Slow sort on large vertex counts
217 int it = 0;
218 while(1)
219 {
220 int modified = 0;
221 for( int i = 0; i < count-1; i ++ )
222 {
223 int s0 = i; int s1 = i + 1;
224
225 if( angles[temp_indices[s0]] > angles[temp_indices[s1]] )
226 {
227 // swap indices and mirror on local
228 u32 temp = indices[s1];
229 indices[s1] = indices[s0];
230 indices[s0] = temp;
231
232 temp = temp_indices[s1];
233 temp_indices[s1] = temp_indices[s0];
234 temp_indices[s0] = temp;
235
236 modified = 1;
237 }
238 }
239
240 it ++;
241 if( !modified ) break;
242 }
243 }
244
245 int solid_has_displacement( vdf_node *node )
246 {
247 int it = 0;
248 vdf_node *pSide;
249
250 while( (pSide = vdf_next(node, "side", &it)) )
251 {
252 if( vdf_next( pSide, "dispinfo", NULL ) )
253 {
254 return 1;
255 }
256 }
257 return 0;
258 }
259
260 void solid_disp_tri( vmf_solid *ctx, u32 a, u32 b, u32 c )
261 {
262 *((u32 *)csr_sb_use( ctx->indices )) = a;
263 *((u32 *)csr_sb_use( ctx->indices )) = b;
264 *((u32 *)csr_sb_use( ctx->indices )) = c;
265 }
266
267 void face_add_indice( vmf_face *f, u32 idx )
268 {
269 f->indices = csr_sb_reserve( f->indices, 1, sizeof( u32 ) );
270 *((u32 *)csr_sb_use( f->indices )) = idx;
271 }
272
273 ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node )
274 {
275 ESolidResult flag = k_ESolidResult_valid;
276
277 vmf_face faces[ SOLID_MAX_SIDES ];
278
279 int is_displacement = 0;
280 int num_planes = 0;
281
282 // TODO: What is this for again? surely it should be the other way around... i think...
283 if( solid_has_displacement( node ) )
284 {
285 printf( "solid_has_displacement\n" );
286 num_planes = vmf_api.bisectors;
287
288 // Add dummy stuff for globals
289 // ???
290 for( int k = 0; k < vmf_api.bisectors; k ++ )
291 {
292 vmf_face *dummy = faces + k;
293 dummy->indices = NULL;
294 dummy->dispinfo = NULL;
295 dummy->material = NULL;
296 }
297
298 is_displacement = 1;
299 }
300
301 int it = 0;
302 vdf_node *pSide;
303 while( (pSide = vdf_next(node, "side", &it)) )
304 {
305 if( num_planes >= SOLID_MAX_SIDES )
306 {
307 flag = k_ESolidResult_maxsides;
308 fprintf( stderr, "Solid over maxsides limit (%i)\n", SOLID_MAX_SIDES );
309 break;
310 }
311
312 double points[3*3];
313
314 vmf_face *face = faces + num_planes;
315 face->indices = NULL;
316 face->dispinfo = vdf_next( pSide, "dispinfo", NULL );
317 face->material = kv_get( pSide, "material", "" );
318 face->blacklisted = mat_blacklisted( face->material );
319
320 kv_double_array( pSide, "plane", 9, points );
321
322 tri_to_plane( points+6, points+3, points+0, vmf_api.planes + num_planes * 4 );
323 num_planes ++;
324 }
325
326 // Compute plane intersections
327 int i[3];
328 csr_comb_init( 3, i );
329
330 v3f center = { 0.f, 0.f, 0.f };
331 int numpoints = 0;
332 u32 vert_start = csr_sb_count( ctx->verts );
333
334 do
335 {
336 // DO something with i j k
337 double p[3];
338
339 if( (faces[ i[0] ].blacklisted && faces[ i[1] ].blacklisted && faces[ i[2] ].blacklisted) )
340 continue;
341
342 if( !plane_intersect( vmf_api.planes+i[0]*4, vmf_api.planes+i[1]*4, vmf_api.planes+i[2]*4, p ) )
343 continue;
344
345 // Check for illegal verts (eg: got clipped by bisectors)
346 int valid = 1;
347 for( int m = 0; m < num_planes; m ++ )
348 {
349 if( plane_polarity( vmf_api.planes+m*4, p ) > 1e-6f )
350 {
351 valid = 0;
352 break;
353 }
354 }
355
356 if( valid )
357 {
358 ctx->verts = csr_sb_reserve( ctx->verts, 3, sizeof( vmf_vert ) );
359
360 // Take the vertex position and add it for centering base on average
361 numpoints ++;
362 v3_add( (v3f){ p[0], p[1], p[2] }, center, center );
363
364 // Store point / respecive normal for each plane that triggered the collision
365 for( int k = 0; k < 3; k ++ )
366 {
367 if( !faces[ i[k] ].blacklisted )
368 {
369 u32 c = csr_sb_count( ctx->verts );
370
371 face_add_indice( faces + i[k], c );
372
373 v3d_v3f( p, ctx->verts[ c ].co );
374 v3d_v3f( vmf_api.planes+i[k]*4, ctx->verts[ c ].nrm );
375
376 csr_sb_inc( ctx->verts, 1 );
377 }
378 }
379 }
380 }
381 while( csr_comb( 3, num_planes, i ) );
382
383 // Retrospectively set the center for each point
384 v3_divs( center, (float)numpoints, center );
385 for( ; vert_start < csr_sb_count( ctx->verts ); vert_start ++ )
386 {
387 v2_copy( center, ctx->verts[ vert_start ].xy );
388 }
389
390 // Sort each faces and trianglulalate them
391 for( int k = vmf_api.bisectors; k < num_planes; k ++ )
392 {
393 vmf_face *face = faces + k;
394
395 if( face->blacklisted ) continue;
396
397 if( csr_sb_count( face->indices ) < 3 )
398 {
399 if( !vmf_api.bisectors )
400 {
401 flag = k_ESolidResult_degenerate;
402 fprintf( stderr, "Skipping degenerate face\n" );
403 }
404 continue;
405 }
406
407 // Sort only if there is no displacements, or if this side is
408 if( !is_displacement || ( is_displacement && face->dispinfo ) )
409 {
410 sort_coplanar( vmf_api.planes+k*4, ctx->verts, face->indices, csr_sb_count( face->indices ) );
411 }
412
413 if( is_displacement )
414 {
415 // Compute displacement
416 if( face->dispinfo )
417 {
418 if( csr_sb_count( face->indices ) != 4 )
419 {
420 // Mute error if we have global planes cause they
421 // are of course gonna fuck things up here
422 if( !vmf_api.bisectors )
423 {
424 flag = k_ESolidResult_degenerate;
425 fprintf( stderr, "Skipping degenerate displacement\n" );
426 }
427 continue;
428 }
429
430 // Match starting position
431 v3f start;
432 int sw = 0;
433 float dmin = 999999.f;
434
435 vdf_node *dispinfo = face->dispinfo;
436 vdf_node *vdf_normals = vdf_next( dispinfo, "normals", NULL );
437 vdf_node *vdf_distances = vdf_next( dispinfo, "distances", NULL );
438
439 kv_float_array( dispinfo, "startposition", 3, start );
440
441 for( int j = 0; j < csr_sb_count( face->indices ); j ++ )
442 {
443 float d2 = v3_dist2( start, ctx->verts[ face->indices[ j ] ].co );
444 if( d2 < dmin )
445 {
446 dmin = d2;
447 sw = j;
448 }
449 }
450
451 // Get corners of displacement
452 float *SW = ctx->verts[ face->indices[ sw ] ].co;
453 float *NW = ctx->verts[ face->indices[ (sw+1) % 4] ].co;
454 float *NE = ctx->verts[ face->indices[ (sw+2) % 4] ].co;
455 float *SE = ctx->verts[ face->indices[ (sw+3) % 4] ].co;
456
457 // Can be either 5, 9, 17
458 numpoints = pow( 2, kv_get_int( dispinfo, "power", 2 ) ) + 1;
459 u32 reqverts = numpoints*numpoints;
460 u32 reqidx = (numpoints-1)*(numpoints-1)*6;
461
462 ctx->verts = csr_sb_reserve( ctx->verts, reqverts, sizeof( vmf_vert ) );
463 ctx->indices = csr_sb_reserve( ctx->indices, reqidx, sizeof( u32 ) );
464
465 float normals[ 17*3 ];
466 float distances[ 17 ];
467
468 // Calculate displacement positions
469 for( int j = 0; j < numpoints; j ++ )
470 {
471 char key[14];
472 sprintf( key, "row%i", j );
473
474 kv_float_array( vdf_normals, key, 17*3, normals );
475 kv_float_array( vdf_distances, key, 17, distances );
476
477 float dx = (float)j / (float)(numpoints - 1); //Time values for linear interpolation
478
479 for( int m = 0; m < numpoints; m ++ )
480 {
481 vmf_vert *vert = &ctx->verts[ csr_sb_count( ctx->verts ) + j*numpoints + m ];
482
483 float dy = (float)m / (float)(numpoints - 1);
484
485 v3f lwr; v3f upr;
486
487 v3_lerp( SW, SE, dx, lwr );
488 v3_lerp( NW, NE, dx, upr );
489 v3_lerp( lwr, upr, dy, vert->co );
490
491 v3_muladds( vert->co, normals + m * 3, distances[ m ], vert->co );
492
493 // Todo, put correct normal
494 v3_copy( (v3f){ 0.f, 0.f, 1.f }, vert->nrm );
495 }
496 }
497
498 // Build displacement indices
499 int condition = 0;
500 for( int row = 0; row < numpoints - 1; row ++ )
501 {
502 for( int col = 0; col < numpoints - 1; col ++ )
503 {
504 u32 c = csr_sb_count( ctx->verts );
505
506 u32 idxsw = c + ( row + 0 ) * numpoints + col + 0 ;
507 u32 idxse = c + ( row + 0 ) * numpoints + col + 1 ;
508 u32 idxnw = c + ( row + 1 ) * numpoints + col + 0 ;
509 u32 idxne = c + ( row + 1 ) * numpoints + col + 1 ;
510
511 if( (condition ++) % 2 == 0 )
512 {
513 solid_disp_tri( ctx, idxne, idxnw, idxsw );
514 solid_disp_tri( ctx, idxse, idxne, idxsw );
515 }
516 else
517 {
518 solid_disp_tri( ctx, idxse, idxnw, idxsw );
519 solid_disp_tri( ctx, idxse, idxne, idxnw );
520 }
521 }
522 condition ++;
523 }
524
525 csr_sb_inc( ctx->verts, numpoints*numpoints );
526 }
527 }
528 else
529 {
530 u32 tris = csr_sb_count( face->indices ) -2;
531 ctx->indices = csr_sb_reserve( ctx->indices, tris*3, sizeof( u32 ) );
532
533 u32 c = csr_sb_count( ctx->indices );
534
535 for( int j = 0; j < tris; j ++ )
536 {
537 ctx->indices[ c +j*3 +0 ] = face->indices[ 0 ];
538 ctx->indices[ c +j*3 +1 ] = face->indices[ j+1 ];
539 ctx->indices[ c +j*3 +2 ] = face->indices[ j+2 ];
540
541 // A 0,1,2:: A,B,C
542 // D B 0,2,3:: A,C,D
543 // C
544 }
545
546 csr_sb_inc( ctx->indices, tris*3 );
547 }
548 }
549
550 // Free temp polyon buffers
551 for( int j = 0; j < num_planes; j ++ )
552 {
553 csr_sb_free( faces[ j ].indices );
554 }
555
556 return flag;
557 }
558
559 u32 vmf_get_mdl( vmf_map *map, const char *mdl )
560 {
561 u32 hash = djb2( (const unsigned char *)mdl );
562
563 for( u32 i = 0; i < csr_sb_count( map->models ); i ++ )
564 {
565 if( hash == map->models[i].hash && !strcmp( map->models[i].str, mdl ) )
566 {
567 return i;
568 }
569 }
570
571 return 0;
572 }
573
574 void vmf_populate_models( vdf_node *vmf, vmf_map *map )
575 {
576 vdf_foreach( vmf, "entity", ent )
577 {
578 // Use any class name with prop_
579 if( !strncmp( kv_get( ent, "classname", "" ), "prop_", 5 ))
580 {
581 // Check if it exists
582 const char *model_path = kv_get( ent, "model", "" );
583 u32 mdl_id = vmf_get_mdl( map, model_path );
584
585 if( !mdl_id )
586 {
587 map->models = csr_sb_reserve( map->models, 1, sizeof( struct vmf_model ));
588
589 struct vmf_model *entry = &map->models[ csr_sb_count( map->models ) ];
590 entry->str = csr_malloc( strlen( model_path ) +1 );
591 strcpy( entry->str, model_path );
592 entry->hash = djb2( (const unsigned char *)model_path );
593
594 mdl_id = csr_sb_count( map->models );
595 csr_sb_use( map->models );
596 }
597
598 // Assign prop-ID for later use
599 ent->user = mdl_id;
600 }
601 }
602 }
603
604 // Load all models
605 void vmf_load_models( vmf_map *map )
606 {
607 printf( "Loading all models\n" );
608
609 // Error model. TODO: Maybe don't have this be junk data.
610 map->models = csr_sb_reserve( map->models, 1, sizeof( struct vmf_model ));
611 csr_sb_use( map->models );
612 mdl_error( &map->models[0].mdl );
613
614 // Create listings for each model
615 vmf_populate_models( map->root, map );
616
617 for( int i = 0; i < csr_sb_count( map->cache ); i ++ )
618 {
619 vmf_populate_models( map->cache[i].root, map );
620 }
621
622 printf( "Indexed (%u) models\n", csr_sb_count( map->models ) );
623
624 u32 num_success = 0;
625
626 // Load model data
627 // TODO: Make nice loading bar
628 for( int i = 1; i < csr_sb_count( map->models ); i ++ )
629 {
630 printf( "Load model (%d)\n", i );
631
632 struct vmf_model *mdl = &map->models[i];
633
634 if( mdl_from_find_files( mdl->str, &mdl->mdl ) )
635 {
636 num_success ++;
637 }
638 }
639
640 printf( "Done (%u of %u loaded)\n", num_success, csr_sb_count( map->models ) );
641 }
642
643 void vmf_init_subvmf( vmf_map *map, const char *subvmf );
644
645 void vmf_load_all_instances( vmf_map *map, vdf_node *vmf )
646 {
647 vdf_foreach( vmf, "entity", ent )
648 {
649 if( !strcmp( kv_get( ent, "classname", "" ), "func_instance" ))
650 {
651 // Entity is in use if file is specified, if not just ignore the entity.
652 const char *path = kv_get( ent, "file", "" );
653 if( strcmp( path, "" ) )
654 {
655 vmf_init_subvmf( map, path );
656 }
657 }
658 }
659 }
660
661 void vmf_init_subvmf( vmf_map *map, const char *subvmf )
662 {
663 printf( "Loading subvmf: %s\n", subvmf );
664
665 u32 hash = djb2( (const unsigned char *)subvmf );
666
667 // Check if present
668 for( int i = 0; i < csr_sb_count( map->cache ); i ++ )
669 {
670 if( hash == map->cache[i].hash )
671 {
672 if( !strcmp( map->cache[i].name, subvmf ) )
673 {
674 return;
675 }
676 }
677 }
678
679 map->cache = csr_sb_reserve( map->cache, 1, sizeof( struct vmf_instance ));
680 struct vmf_instance *inst = &map->cache[ csr_sb_count( map->cache ) ];
681
682 if( (inst->root = vdf_open_file( subvmf )) )
683 {
684 csr_sb_use( map->cache );
685
686 inst->hash = hash;
687 inst->name = csr_malloc( strlen( subvmf )+1 );
688 strcpy( inst->name, subvmf );
689
690 // Recursive load other instances
691 vmf_load_all_instances( map, inst->root );
692 }
693 else
694 {
695 // TODO: Don't die here?
696 fprintf( stderr, "Failed to load instance file\n" );
697 exit(0);
698 }
699 }
700
701 vmf_map *vmf_init( const char *path, int load_models )
702 {
703 vmf_map *map = csr_calloc( sizeof( vmf_map ) );
704 map->root = vdf_open_file( path );
705
706 // Prepare instances
707 vmf_load_all_instances( map, map->root );
708
709 // Other resources
710 if( load_models )
711 {
712 vmf_load_models( map );
713 }
714
715 return map;
716 }
717
718 void vmf_free( vmf_map *map )
719 {
720 for( int i = 0; i < csr_sb_count( map->cache ); i ++ )
721 {
722 vdf_free_r( map->cache[i].root );
723 free( map->cache[i].name );
724 }
725
726 for( int i = 1; i < csr_sb_count( map->models ); i ++ )
727 {
728 free( map->models[i].str );
729 mdl_free( &map->models[i].mdl );
730 }
731
732 vdf_free_r( map->root );
733 csr_sb_free( map->models );
734 csr_sb_free( map->cache );
735 free( map );
736 }
737
738 void solidgen_to_obj( vmf_solid *ctx, const char *path )
739 {
740 FILE *fp = fopen( path, "w" );
741
742 if( fp )
743 {
744 fprintf( fp, "o vmf_export\n" );
745
746 vmf_vert *vert;
747
748 // Write vertex block
749 for( int i = 0; i < csr_sb_count( ctx->verts ); i ++ )
750 {
751 vert = &ctx->verts[i];
752 fprintf( fp, "v %f %f %f\n", vert->co[0], vert->co[1], vert->co[2] );
753 }
754
755 // Write normals block
756 for( int i = 0; i < csr_sb_count( ctx->verts ); i ++ )
757 {
758 vert = &ctx->verts[i];
759 fprintf( fp, "vn %f %f %f\n", vert->nrm[0], vert->nrm[1], vert->nrm[2] );
760 }
761
762 fprintf( fp, "s off\n" );
763
764 // Indices
765 for( int i = 0; i < csr_sb_count( ctx->indices )/3; i ++ )
766 {
767 u32 * base = ctx->indices + i*3;
768 fprintf( fp, "f %u//%u %u//%u %u//%u\n",
769 base[2]+1, base[2]+1,
770 base[1]+1, base[1]+1,
771 base[0]+1, base[0]+1
772 );
773 }
774
775 fclose( fp );
776 }
777 else
778 {
779 fprintf( stderr, "Could not open %s for writing\n", path );
780 }
781 }