-#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;
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;
}
// 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
// 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;
}
is_displacement = 1;
+ */
}
int it = 0;
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" );
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;
+}