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