X-Git-Url: https://harrygodden.com/git/?p=csRadar.git;a=blobdiff_plain;f=vmf.h;h=740a3749da0af94070dabd7da5077aaae7ac8197;hp=887fe849b9da5e684a0286ee7d2b4a754ca8684b;hb=HEAD;hpb=0399aad1d7374badf037a2696d9e276d71b7a297 diff --git a/vmf.h b/vmf.h index 887fe84..740a374 100644 --- a/vmf.h +++ b/vmf.h @@ -1,4 +1,8 @@ -#define SOLID_MAX_SIDES 512 +// This software is not affiliated with Valve Corporation +// We are not affiliated, associated, authorized, endorsed by, or in any way officially +// connected with Valve Corporation, or any of its subsidiaries or its affiliates. +// +// All trademarks are property of their respective owners typedef struct vmf_solid vmf_solid; typedef struct vmf_vert vmf_vert; @@ -9,6 +13,53 @@ typedef struct vmf_map vmf_map; typedef enum ESolidResult ESolidResult; +// API +//======================================================================================================================= + +// Load vmf from disk +vmf_map *vmf_init( const char *path ); +void vmf_free( vmf_map *map ); + +// Solidgen API ~ Converting brushes into meshes +// --------------------------------------------- +void solidgen_ctx_init( vmf_solid *ctx ); +void solidgen_ctx_reset( vmf_solid *ctx ); +void solidgen_ctx_free( vmf_solid *ctx ); +void solidgen_bounds( vmf_solid *ctx, boxf box ); + +ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ); + +// General VMF +// ----------- +int solid_has_displacement( vdf_node *node ); +int vmf_class_is_prop( vdf_node *ent ); + +// Build the list of all models used in this map, including instances +void vmf_index_models( vmf_map *map ); + +// Loads all models that have the resource flagged with need_load +void vmf_load_models( vmf_map *map ); + +// Create matrix describing this entities transform +void vmf_entity_transform( vdf_node *ent, m4x3f mat ); + +int vmf_visgroup_id( vdf_node *root, const char *name ); +int vmf_visgroup_match( vdf_node *ent, u32 target ); + +// Currently unused +//void vmf_addbisector( double p[4] ); +//void vmf_clearbisectors( void ); +//void vmf_ignore_mat( const char *material ); +//void vmf_clearignore( void ); + +// Implementation +//======================================================================================================================= + +#define SOLID_MAX_SIDES 512 +#define VMF_FLAG_IS_PROP 0x1 +#define VMF_FLAG_IS_INSTANCE 0x2 +#define VMF_FLAG_BRUSH_ENT 0x4 + enum ESolidResult { k_ESolidResult_valid, @@ -23,7 +74,7 @@ struct vmf_vert { v3f co; v3f nrm; - v2f xy; + v3f origin; }; struct vmf_face @@ -58,6 +109,8 @@ struct vmf_map u32 hash; mdl_mesh_t mdl; + + int need_load; } *models; @@ -67,11 +120,21 @@ struct vmf_map u32 hash; vdf_node *root; + + m4x3f transform; } *cache; + + m4x3f transform; }; -// IMPLEMENTATION +#ifdef VALVE_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 ) { @@ -88,27 +151,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 @@ -274,30 +330,12 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) { ESolidResult flag = k_ESolidResult_valid; + double planes[ SOLID_MAX_SIDES*4 ]; vmf_face faces[ SOLID_MAX_SIDES ]; - int is_displacement = 0; + int is_displacement = solid_has_displacement( node ); int num_planes = 0; - // TODO: What is this for again? surely it should be the other way around... i think... - if( solid_has_displacement( node ) ) - { - printf( "solid_has_displacement\n" ); - num_planes = vmf_api.bisectors; - - // Add dummy stuff for globals - // ??? - for( int k = 0; k < vmf_api.bisectors; k ++ ) - { - vmf_face *dummy = faces + k; - dummy->indices = NULL; - dummy->dispinfo = NULL; - dummy->material = NULL; - } - - is_displacement = 1; - } - int it = 0; vdf_node *pSide; while( (pSide = vdf_next(node, "side", &it)) ) @@ -305,7 +343,7 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) if( num_planes >= SOLID_MAX_SIDES ) { flag = k_ESolidResult_maxsides; - fprintf( stderr, "Solid over maxsides limit (%i)\n", SOLID_MAX_SIDES ); + log_error( "Solid over maxsides limit (%i)\n", SOLID_MAX_SIDES ); break; } @@ -319,7 +357,7 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) kv_double_array( pSide, "plane", 9, points ); - tri_to_plane( points+6, points+3, points+0, vmf_api.planes + num_planes * 4 ); + tri_to_plane( points+6, points+3, points+0, planes + num_planes * 4 ); num_planes ++; } @@ -339,14 +377,14 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) if( (faces[ i[0] ].blacklisted && faces[ i[1] ].blacklisted && faces[ i[2] ].blacklisted) ) continue; - if( !plane_intersect( vmf_api.planes+i[0]*4, vmf_api.planes+i[1]*4, vmf_api.planes+i[2]*4, p ) ) + if( !plane_intersect( planes+i[0]*4, planes+i[1]*4, planes+i[2]*4, p ) ) continue; // Check for illegal verts (eg: got clipped by bisectors) int valid = 1; for( int m = 0; m < num_planes; m ++ ) { - if( plane_polarity( vmf_api.planes+m*4, p ) > 1e-6f ) + if( plane_polarity( planes+m*4, p ) > 1e-6f ) { valid = 0; break; @@ -371,7 +409,7 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) face_add_indice( faces + i[k], c ); v3d_v3f( p, ctx->verts[ c ].co ); - v3d_v3f( vmf_api.planes+i[k]*4, ctx->verts[ c ].nrm ); + v3d_v3f( planes+i[k]*4, ctx->verts[ c ].nrm ); csr_sb_inc( ctx->verts, 1 ); } @@ -384,11 +422,11 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) v3_divs( center, (float)numpoints, center ); for( ; vert_start < csr_sb_count( ctx->verts ); vert_start ++ ) { - v2_copy( center, ctx->verts[ vert_start ].xy ); + v3_copy( center, ctx->verts[ vert_start ].origin ); } // Sort each faces and trianglulalate them - for( int k = vmf_api.bisectors; k < num_planes; k ++ ) + for( int k = 0; k < num_planes; k ++ ) { vmf_face *face = faces + k; @@ -396,18 +434,15 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) if( csr_sb_count( face->indices ) < 3 ) { - if( !vmf_api.bisectors ) - { - flag = k_ESolidResult_degenerate; - fprintf( stderr, "Skipping degenerate face\n" ); - } + flag = k_ESolidResult_degenerate; + log_error( "Skipping degenerate face\n" ); continue; } // Sort only if there is no displacements, or if this side is if( !is_displacement || ( is_displacement && face->dispinfo ) ) { - sort_coplanar( vmf_api.planes+k*4, ctx->verts, face->indices, csr_sb_count( face->indices ) ); + sort_coplanar( planes+k*4, ctx->verts, face->indices, csr_sb_count( face->indices ) ); } if( is_displacement ) @@ -417,13 +452,8 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) { if( csr_sb_count( face->indices ) != 4 ) { - // Mute error if we have global planes cause they - // are of course gonna fuck things up here - if( !vmf_api.bisectors ) - { - flag = k_ESolidResult_degenerate; - fprintf( stderr, "Skipping degenerate displacement\n" ); - } + flag = k_ESolidResult_degenerate; + log_error( "Skipping degenerate displacement\n" ); continue; } @@ -448,12 +478,6 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) } } - // Get corners of displacement - float *SW = ctx->verts[ face->indices[ sw ] ].co; - float *NW = ctx->verts[ face->indices[ (sw+1) % 4] ].co; - float *NE = ctx->verts[ face->indices[ (sw+2) % 4] ].co; - float *SE = ctx->verts[ face->indices[ (sw+3) % 4] ].co; - // Can be either 5, 9, 17 numpoints = pow( 2, kv_get_int( dispinfo, "power", 2 ) ) + 1; u32 reqverts = numpoints*numpoints; @@ -461,6 +485,12 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) ctx->verts = csr_sb_reserve( ctx->verts, reqverts, sizeof( vmf_vert ) ); ctx->indices = csr_sb_reserve( ctx->indices, reqidx, sizeof( u32 ) ); + + // Get corners of displacement + float *SW = ctx->verts[ face->indices[ sw ] ].co; + float *NW = ctx->verts[ face->indices[ (sw+1) % 4] ].co; + float *NE = ctx->verts[ face->indices[ (sw+2) % 4] ].co; + float *SE = ctx->verts[ face->indices[ (sw+3) % 4] ].co; float normals[ 17*3 ]; float distances[ 17 ]; @@ -492,6 +522,9 @@ ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node ) // Todo, put correct normal v3_copy( (v3f){ 0.f, 0.f, 1.f }, vert->nrm ); + + // Todo: use real bounds of displaced vertices + v3_copy( center, vert->origin ); } } @@ -571,12 +604,17 @@ u32 vmf_get_mdl( vmf_map *map, const char *mdl ) 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( !strncmp( kv_get( ent, "classname", "" ), "prop_", 5 )) + if( vmf_class_is_prop( ent ) ) { // Check if it exists const char *model_path = kv_get( ent, "model", "" ); @@ -587,6 +625,9 @@ void vmf_populate_models( vdf_node *vmf, vmf_map *map ) map->models = csr_sb_reserve( map->models, 1, sizeof( struct vmf_model )); struct vmf_model *entry = &map->models[ csr_sb_count( map->models ) ]; + entry->need_load = 0; + mdl_error( &entry->mdl ); // (just setting arrays to 0) + entry->str = csr_malloc( strlen( model_path ) +1 ); strcpy( entry->str, model_path ); entry->hash = djb2( (const unsigned char *)model_path ); @@ -596,17 +637,18 @@ void vmf_populate_models( vdf_node *vmf, vmf_map *map ) } // Assign prop-ID for later use - ent->user = mdl_id; + ent->user = VMF_FLAG_IS_PROP; + ent->user1 = mdl_id; } } } // Load all models -void vmf_load_models( vmf_map *map ) +void vmf_index_models( vmf_map *map ) { - printf( "Loading all models\n" ); + log_info( "Indexing all models\n" ); - // Error model. TODO: Maybe don't have this be junk data. + // Error model == blank map->models = csr_sb_reserve( map->models, 1, sizeof( struct vmf_model )); csr_sb_use( map->models ); mdl_error( &map->models[0].mdl ); @@ -619,99 +661,130 @@ void vmf_load_models( vmf_map *map ) vmf_populate_models( map->cache[i].root, map ); } - printf( "Indexed (%u) models\n", csr_sb_count( map->models ) ); - + log_info( "Indexed (%u) models\n", csr_sb_count( map->models )-1 ); +} + +void vmf_load_models( vmf_map *map ) +{ u32 num_success = 0; + u32 num_reqs = 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 ) ) + if( mdl->need_load ) { - num_success ++; + num_reqs ++; + + if( mdl_from_find_files( mdl->str, &mdl->mdl ) ) + { + num_success ++; + } + else + { + log_warn( "Failed to load model: %s\n", mdl->str ); + } } } - printf( "Done (%u of %u loaded)\n", num_success, csr_sb_count( map->models ) ); + log_info( "Done (%u of %u loaded)\n", num_success, num_reqs ); } -void vmf_init_subvmf( vmf_map *map, const char *subvmf ); +u32 vmf_init_subvmf( vmf_map *map, const char *subvmf ); void vmf_load_all_instances( vmf_map *map, vdf_node *vmf ) { + char nextvmf[ 512 ]; + const char *base = kv_get( vmf, "csr_path", "" ); + 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, "" ) ) + const char *path = kv_get( ent, "file", NULL ); + + if( path ) { - vmf_init_subvmf( map, path ); + // Make relative path real + strcpy( nextvmf, base ); + csr_downlvl( nextvmf ); + strcat( nextvmf, path ); + + if( (ent->user1 = vmf_init_subvmf( map, nextvmf ))) + { + ent->user1 --; + ent->user = VMF_FLAG_IS_INSTANCE; + } } } } } -void vmf_init_subvmf( vmf_map *map, const char *subvmf ) +// TODO: Merge this into above function.. doesnt need to be seperated +u32 vmf_init_subvmf( vmf_map *map, const char *subvmf ) { - printf( "Loading subvmf: %s\n", subvmf ); - + u32 id; u32 hash = djb2( (const unsigned char *)subvmf ); // Check if present - for( int i = 0; i < csr_sb_count( map->cache ); i ++ ) + 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; + if( map->cache[i].root ) + return i+1; + else + return 0; } } } + id = csr_sb_count( map->cache ); map->cache = csr_sb_reserve( map->cache, 1, sizeof( struct vmf_instance )); - struct vmf_instance *inst = &map->cache[ csr_sb_count( map->cache ) ]; + struct vmf_instance *inst = &map->cache[ id ]; + + csr_sb_use( map->cache ); + inst->hash = hash; + inst->name = csr_malloc( strlen( subvmf )+1 ); + strcpy( inst->name, subvmf ); 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 ); + vdf_kv_append( inst->root, "csr_path", subvmf ); // Recursive load other instances - vmf_load_all_instances( map, inst->root ); + vmf_load_all_instances( map, inst->root ); + return id+1; } else { - // TODO: Don't die here? - fprintf( stderr, "Failed to load instance file\n" ); - exit(0); + log_error( "Failed to load instance file: %s\n", subvmf ); + return 0; } } -vmf_map *vmf_init( const char *path, int load_models ) +vmf_map *vmf_init( const char *path ) { vmf_map *map = csr_calloc( sizeof( vmf_map ) ); map->root = vdf_open_file( path ); + if( !map->root ) + { + free( map ); + return NULL; + } + + vdf_kv_append( map->root, "csr_path", path ); + // Prepare instances vmf_load_all_instances( map, map->root ); // Other resources - if( load_models ) - { - vmf_load_models( map ); - } - + vmf_index_models( map ); return map; } @@ -719,7 +792,9 @@ void vmf_free( vmf_map *map ) { for( int i = 0; i < csr_sb_count( map->cache ); i ++ ) { - vdf_free_r( map->cache[i].root ); + if( map->cache[i].root ) + vdf_free_r( map->cache[i].root ); + free( map->cache[i].name ); } @@ -735,47 +810,61 @@ void vmf_free( vmf_map *map ) free( map ); } -void solidgen_to_obj( vmf_solid *ctx, const char *path ) +void vmf_entity_transform( vdf_node *ent, m4x3f mat ) { - FILE *fp = fopen( path, "w" ); - - if( fp ) - { - fprintf( fp, "o vmf_export\n" ); + v3f angles = {0.f,0.f,0.f}; + v3f offset = {0.f,0.f,0.f}; + float scale; - vmf_vert *vert; + // Parse + scale = kv_get_float( ent, "uniformscale", 1.f ); + kv_float_array( ent, "angles", 3, angles ); + kv_float_array( ent, "origin", 3, offset ); - // Write vertex block - for( int i = 0; i < csr_sb_count( ctx->verts ); i ++ ) - { - vert = &ctx->verts[i]; - fprintf( fp, "v %f %f %f\n", vert->co[0], vert->co[1], vert->co[2] ); - } - - // Write normals block - for( int i = 0; i < csr_sb_count( ctx->verts ); i ++ ) - { - vert = &ctx->verts[i]; - fprintf( fp, "vn %f %f %f\n", vert->nrm[0], vert->nrm[1], vert->nrm[2] ); - } - - fprintf( fp, "s off\n" ); - - // Indices - for( int i = 0; i < csr_sb_count( ctx->indices )/3; i ++ ) + // 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 ); +} + +int vmf_visgroup_id( vdf_node *root, const char *name ) +{ + vdf_node *dict = vdf_next( root, "visgroups", NULL ); + + if( dict ) + { + vdf_foreach( dict, "visgroup", group ) { - u32 * base = ctx->indices + i*3; - fprintf( fp, "f %u//%u %u//%u %u//%u\n", - base[2]+1, base[2]+1, - base[1]+1, base[1]+1, - base[0]+1, base[0]+1 - ); + if( !strcmp( kv_get( group, "name", "" ), name ) ) + { + return kv_get_int( group, "visgroupid", 0 ); + } } - - fclose( fp ); } - else + + return -1; +} + +int vmf_visgroup_match( vdf_node *ent, u32 target ) +{ + vdf_node *editor = vdf_next( ent, "editor", NULL ); + + if( editor ) { - fprintf( stderr, "Could not open %s for writing\n", path ); + kv_foreach( editor, "visgroupid", groupe ) + { + if( target == atoi( groupe ) ) + return 1; + } } + + return 0; } + +#endif