fixed aabb transform func
[csRadar.git] / vmf.h
diff --git a/vmf.h b/vmf.h
index 9baa117510e54accfb98861f5647db90942fb136..ff3804d8c29691add5a67d82ba4f2eb64305f4e4 100644 (file)
--- a/vmf.h
+++ b/vmf.h
@@ -1,12 +1,14 @@
-#include "csrTypes.h"
-#include "csrComb.h"
-
 #define SOLID_MAX_SIDES 512
+#define VMF_FLAG_IS_PROP 0x1
+#define VMF_FLAG_IS_INSTANCE 0x2
+#define VMF_FLAG_BRUSH_ENT 0x4
 
 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,8 +51,41 @@ 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;
+               
+               m4x3f transform;
+       }
+       *cache;
+       
+       m4x3f transform;
+};
+
 // IMPLEMENTATION
 
+void solidgen_ctx_reset( vmf_solid *ctx )
+{
+       csr_sb_clear( ctx->verts );
+       csr_sb_clear( ctx->indices );
+}
+
 void solidgen_ctx_init( vmf_solid *ctx )
 {
        const u32 init_size = 128;
@@ -66,27 +101,20 @@ void solidgen_ctx_free( vmf_solid *ctx )
 }
 
 // Compute bounds of solid gen ctx
-void solidgen_bounds( vmf_solid *ctx, u32 start, u32 end, v3f min, v3f max )
+void solidgen_bounds( vmf_solid *ctx, boxf box )
 {
        v3f mine = { INFINITY, INFINITY, INFINITY };
        v3f maxe = {-INFINITY,-INFINITY,-INFINITY };
 
-       for( int i = start; i < end; i ++ )
+       for( int i = 0; i < csr_sb_count( ctx->verts ); i ++ )
        {
                vmf_vert *vert = ctx->verts + i;
-               float *co = vert->co;
-               
-               mine[0] = fminf( mine[0], co[0] );
-               mine[1] = fminf( mine[1], co[1] );
-               mine[2] = fminf( mine[2], co[2] );
-               
-               maxe[0] = fmaxf( maxe[0], co[0] );
-               maxe[1] = fmaxf( maxe[1], co[1] );
-               maxe[2] = fmaxf( maxe[2], co[2] );
+               v3_minv( mine, vert->co, mine );
+               v3_maxv( maxe, vert->co, maxe );
        }
        
-       v3_copy( mine, min );
-       v3_copy( maxe, max );
+       v3_copy( mine, box[0] );
+       v3_copy( maxe, box[1] );
 }
 
 struct
@@ -260,6 +288,9 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node )
        // TODO: What is this for again? surely it should be the other way around... i think...
        if( solid_has_displacement( node ) )
        {
+               is_displacement = 1;
+               /*
+       
                printf( "solid_has_displacement\n" );
                num_planes = vmf_api.bisectors;
        
@@ -274,6 +305,7 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node )
                }
                
                is_displacement = 1;
+               */
        }
        
        int it = 0; 
@@ -534,6 +566,207 @@ 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;
+}
+
+int vmf_class_is_prop( vdf_node *ent )
+{
+       return !strncmp( kv_get( ent, "classname", "" ), "prop_", 5 );
+}
+
+void vmf_populate_models( vdf_node *vmf, vmf_map *map )
+{
+       vdf_foreach( vmf, "entity", ent )
+       {
+               // Use any class name with prop_
+               if( vmf_class_is_prop( ent ) )
+               {
+                       // 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 = VMF_FLAG_IS_PROP;
+                       ent->user1 = 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 )-1 );
+       
+       u32 num_success = 0;
+       
+       // Load model data
+       // TODO: Make nice loading bar
+       for( int i = 1; i < csr_sb_count( map->models ); i ++ )
+       {
+               struct vmf_model *mdl = &map->models[i];
+               
+               if( mdl_from_find_files( mdl->str, &mdl->mdl ) )
+               {
+                       num_success ++;
+               }
+               else
+               {
+                       fprintf( stderr, "Failed to load model: %s\n", mdl->str );
+               }
+       }
+       
+       printf( "Done (%u of %u loaded)\n", num_success, csr_sb_count( map->models )-1 );
+}
+
+u32 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, "" ) )
+                       {
+                               if( (ent->user1 = vmf_init_subvmf( map, path )))
+                               {
+                                       ent->user1 --;
+                                       ent->user = VMF_FLAG_IS_INSTANCE;
+                               }
+                       }
+               }
+       }
+}
+
+// TODO: Merge this into above function.. doesnt need to be seperated
+u32 vmf_init_subvmf( vmf_map *map, const char *subvmf )
+{
+       u32 id;
+       u32 hash = djb2( (const unsigned char *)subvmf );
+       
+       // Check if present
+       for( u32 i = 0; i < csr_sb_count( map->cache ); i ++ )
+       {
+               if( hash == map->cache[i].hash )
+               {
+                       if( !strcmp( map->cache[i].name, subvmf ) )
+                       {
+                               return i+1;
+                       }
+               }
+       }
+       
+       printf( "Loading subvmf: %s\n", subvmf );
+       
+       id = csr_sb_count( map->cache );
+       map->cache = csr_sb_reserve( map->cache, 1, sizeof( struct vmf_instance ));
+       struct vmf_instance *inst = &map->cache[ id ];
+       
+       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 );
+               
+               return id+1;
+       }
+       else
+       {
+               fprintf( stderr, "Failed to load instance file\n" );
+               return 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 );
+       
+       if( !map->root )
+       {
+               free( map );
+               return NULL;
+       }
+       
+       // 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" );
@@ -578,3 +811,60 @@ void solidgen_to_obj( vmf_solid *ctx, const char *path )
                fprintf( stderr, "Could not open %s for writing\n", path );
        }
 }
+
+void vmf_entity_transform( vdf_node *ent, m4x3f mat )
+{
+       v3f angles = {0.f,0.f,0.f};
+       v3f offset = {0.f,0.f,0.f};
+       float scale;
+       
+       // Parse
+       scale = kv_get_float( ent, "uniformscale", 1.f );
+       kv_float_array( ent, "angles", 3, angles );
+       kv_float_array( ent, "origin", 3, offset );
+       
+       // Translation
+       m4x3_translate( mat, offset );
+       
+       // Make rotation ( Pitch yaw roll // YZX. Source->OpenGL ordering a lil messed up )
+       m4x3_rotate_z( mat, csr_rad( angles[1] ) );
+       m4x3_rotate_y( mat, csr_rad( angles[0] ) );
+       m4x3_rotate_x( mat, csr_rad( angles[2] ) );
+       
+       // Scale
+       m4x3_scale( mat, scale );
+}
+
+u32 vmf_visgroup_id( vdf_node *root, const char *name )
+{
+       vdf_node *dict = vdf_next( root, "visgroups", NULL );
+       
+       if( dict )
+       {
+               vdf_foreach( dict, "visgroup", group )
+               {
+                       if( !strcmp( kv_get( group, "name", "" ), name ) )
+                       {
+                               return kv_get_int( group, "visgroupid", 0 );
+                       }
+               }
+       }
+       
+       return 0;
+}
+
+int vmf_visgroup_match( vdf_node *ent, u32 target )
+{
+       vdf_node *editor = vdf_next( ent, "editor", NULL );
+       
+       if( editor )
+       {
+               kv_foreach( editor, "visgroupid", groupe )
+               {
+                       if( target == atoi( groupe ) )
+                               return 1;
+               }
+       }
+       
+       return 0;
+}