vpk loading/models
[csRadar.git] / vmf.h
diff --git a/vmf.h b/vmf.h
index 9baa117510e54accfb98861f5647db90942fb136..887fe849b9da5e684a0286ee7d2b4a754ca8684b 100644 (file)
--- a/vmf.h
+++ b/vmf.h
@@ -1,12 +1,11 @@
-#include "csrTypes.h"
-#include "csrComb.h"
-
 #define SOLID_MAX_SIDES 512
 
 typedef struct vmf_solid vmf_solid;
 typedef struct vmf_vert vmf_vert;
 typedef struct vmf_mat vmf_mat;
 typedef struct vmf_face vmf_face;
+typedef struct vmf_userdata vmf_userdata;
+typedef struct vmf_map vmf_map;
 
 typedef enum ESolidResult ESolidResult;
 
@@ -49,6 +48,29 @@ struct vmf_mat
        u32     hash;
 };
 
+struct vmf_map
+{
+       vdf_node *root;
+
+       struct vmf_model
+       {
+               char *str;
+               u32     hash;
+               
+               mdl_mesh_t mdl;
+       }
+       *models;
+       
+       struct vmf_instance
+       {
+               char *name;
+               u32     hash;
+               
+               vdf_node *root;
+       }
+       *cache;
+};
+
 // IMPLEMENTATION
 
 void solidgen_ctx_init( vmf_solid *ctx )
@@ -534,6 +556,185 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node )
        return flag;
 }
 
+u32 vmf_get_mdl( vmf_map *map, const char *mdl )
+{
+       u32 hash = djb2( (const unsigned char *)mdl );
+       
+       for( u32 i = 0; i < csr_sb_count( map->models ); i ++ )
+       {
+               if( hash == map->models[i].hash && !strcmp( map->models[i].str, mdl ) )
+               {
+                       return i;
+               }
+       }
+       
+       return 0;
+}
+
+void vmf_populate_models( vdf_node *vmf, vmf_map *map )
+{
+       vdf_foreach( vmf, "entity", ent )
+       {
+               // Use any class name with prop_
+               if( !strncmp( kv_get( ent, "classname", "" ), "prop_", 5 ))
+               {
+                       // Check if it exists
+                       const char *model_path = kv_get( ent, "model", "" );
+                       u32 mdl_id = vmf_get_mdl( map, model_path );
+                       
+                       if( !mdl_id )
+                       {
+                               map->models = csr_sb_reserve( map->models, 1, sizeof( struct vmf_model ));
+                               
+                               struct vmf_model *entry = &map->models[ csr_sb_count( map->models ) ];
+                               entry->str = csr_malloc( strlen( model_path ) +1 );
+                               strcpy( entry->str, model_path );
+                               entry->hash = djb2( (const unsigned char *)model_path );
+                               
+                               mdl_id = csr_sb_count( map->models );
+                               csr_sb_use( map->models );                              
+                       }
+                       
+                       // Assign prop-ID for later use
+                       ent->user = mdl_id;
+               }
+       }
+}
+
+// Load all models
+void vmf_load_models( vmf_map *map )
+{
+       printf( "Loading all models\n" );
+       
+       // Error model. TODO: Maybe don't have this be junk data.
+       map->models = csr_sb_reserve( map->models, 1, sizeof( struct vmf_model ));
+       csr_sb_use( map->models );
+       mdl_error( &map->models[0].mdl );
+       
+       // Create listings for each model
+       vmf_populate_models( map->root, map );
+       
+       for( int i = 0; i < csr_sb_count( map->cache ); i ++ )
+       {
+               vmf_populate_models( map->cache[i].root, map );
+       }
+       
+       printf( "Indexed (%u) models\n", csr_sb_count( map->models ) );
+       
+       u32 num_success = 0;
+       
+       // Load model data
+       // TODO: Make nice loading bar
+       for( int i = 1; i < csr_sb_count( map->models ); i ++ )
+       {
+               printf( "Load model (%d)\n", i );
+               
+               struct vmf_model *mdl = &map->models[i];
+               
+               if( mdl_from_find_files( mdl->str, &mdl->mdl ) )
+               {
+                       num_success ++;
+               }
+       }
+       
+       printf( "Done (%u of %u loaded)\n", num_success, csr_sb_count( map->models ) );
+}
+
+void vmf_init_subvmf( vmf_map *map, const char *subvmf );
+
+void vmf_load_all_instances( vmf_map *map, vdf_node *vmf )
+{
+       vdf_foreach( vmf, "entity", ent )
+       {
+               if( !strcmp( kv_get( ent, "classname", "" ), "func_instance" ))
+               {
+                       // Entity is in use if file is specified, if not just ignore the entity.
+                       const char *path = kv_get( ent, "file", "" );
+                       if( strcmp( path, "" ) )
+                       {
+                               vmf_init_subvmf( map, path );
+                       }
+               }
+       }
+}
+
+void vmf_init_subvmf( vmf_map *map, const char *subvmf )
+{
+       printf( "Loading subvmf: %s\n", subvmf );
+       
+       u32 hash = djb2( (const unsigned char *)subvmf );
+       
+       // Check if present
+       for( int i = 0; i < csr_sb_count( map->cache ); i ++ )
+       {
+               if( hash == map->cache[i].hash )
+               {
+                       if( !strcmp( map->cache[i].name, subvmf ) )
+                       {
+                               return;
+                       }
+               }
+       }
+       
+       map->cache = csr_sb_reserve( map->cache, 1, sizeof( struct vmf_instance ));
+       struct vmf_instance *inst = &map->cache[ csr_sb_count( map->cache ) ];
+       
+       if( (inst->root = vdf_open_file( subvmf )) )
+       {
+               csr_sb_use( map->cache );
+               
+               inst->hash = hash;
+               inst->name = csr_malloc( strlen( subvmf )+1 );
+               strcpy( inst->name, subvmf );
+               
+               // Recursive load other instances
+               vmf_load_all_instances( map, inst->root );
+       }
+       else
+       {
+               // TODO: Don't die here?
+               fprintf( stderr, "Failed to load instance file\n" );
+               exit(0);
+       }
+}
+
+vmf_map *vmf_init( const char *path, int load_models )
+{
+       vmf_map *map = csr_calloc( sizeof( vmf_map ) );
+       map->root = vdf_open_file( path );
+       
+       // Prepare instances
+       vmf_load_all_instances( map, map->root );
+       
+       // Other resources
+       if( load_models )
+       {
+               vmf_load_models( map );
+       }
+       
+       return map;
+}
+
+void vmf_free( vmf_map *map )
+{
+       for( int i = 0; i < csr_sb_count( map->cache ); i ++ )
+       {
+               vdf_free_r( map->cache[i].root );
+               free( map->cache[i].name );
+       }
+       
+       for( int i = 1; i < csr_sb_count( map->models ); i ++ )
+       {
+               free( map->models[i].str );
+               mdl_free( &map->models[i].mdl );
+       }
+
+       vdf_free_r( map->root );
+       csr_sb_free( map->models );
+       csr_sb_free( map->cache );
+       free( map );
+}
+
 void solidgen_to_obj( vmf_solid *ctx, const char *path )
 {
        FILE *fp = fopen( path, "w" );