2 * The following is used to read the existing content from CS:GO compiled assets
10 #ifndef CXR_VALVE_BIN_H
11 #define CXR_VALVE_BIN_H
16 #include "cxr_types.h"
22 typedef struct VPKHeader VPKHeader
;
23 typedef struct VPKDirectoryEntry VPKDirectoryEntry
;
24 typedef struct vdf_kv vdf_kv
;
25 typedef struct vdf_node vdf_node
;
26 typedef struct vdf_ctx vdf_ctx
;
27 typedef struct valve_file_system valve_file_system
;
33 static struct valve_file_system
41 cxr_abuffer searchpaths
;
43 FILE *current_archive
;
48 fs_global
= { .initialized
= 0 };
50 CXR_API
int cxr_fs_set_gameinfo( const char *path
); /* Setup system */
51 CXR_API
void cxr_fs_exit(void); /* Clean up */
52 CXR_API
char *cxr_fs_get( const char *path
); /* Get a file */
58 static VPKDirectoryEntry
*vpk_find( VPKHeader
*self
, const char *asset
);
59 static void vpk_free( VPKHeader
*self
);
65 static vdf_node
*vdf_open_file( const char *fn
);
66 static void vdf_free_r( vdf_node
*p
);
68 /* Starting from *it, get next child with matching name from node. */
69 static vdf_node
*vdf_next( vdf_node
*node
, const char *name
, int *it
);
71 /* Create new empty node attached to parent. name can be NULL */
72 static vdf_node
*vdf_create_node( vdf_node
*parent
, const char *name
);
75 static const char *kv_get( vdf_node
*node
, const char *key
,
76 const char *value_defalt
);
78 /* Iterate each keyvalue starting from *it until key is matched */
79 static char *kv_next( vdf_node
*node
, const char *key
, int *it
);
81 static int kv_get_int( vdf_node
*node
, const char *key
, const int fallback
);
82 static float kv_get_float( vdf_node
*node
, const char *key
, float fallback
);
84 static void kv_int_array( vdf_node
*node
, const char *key
, u32 count
,
86 static void kv_float_array( vdf_node
*node
, const char *key
, u32 count
,
88 static void kv_double_array( vdf_node
*node
, const char *key
, u32 count
,
91 #define vdf_foreach( NODE, STR, AS ) \
92 int __vdf_it_##AS = 0; \
94 while( (AS = vdf_next( NODE, STR, &__vdf_it_##AS )) )
96 #define kv_foreach( NODE, STR, AS ) \
97 int __kv_it_##AS = 0; \
99 while( (AS = kv_next( NODE, STR, &__kv_it_##AS )) )
100 #pragma pack(push, 1)
107 u32 FileDataSectionSize
;
108 u32 ArchiveMD5SectionSize
;
109 u32 OtherMD5SectionSize
;
110 u32 SignatureSectionSize
;
113 struct VPKDirectoryEntry
124 static void vpk_free( VPKHeader
*self
)
129 static VPKDirectoryEntry
*vpk_find( VPKHeader
*self
, const char *asset
)
135 strcpy( wbuf
, asset
);
138 * This currently fails if the filename doesn't have a file extension, or
139 * if it is located at the root path. I'm not sure if this is defined
140 * behaviour or not. TODO: allow it to work anyway
143 char *ext
= cxr_findext( wbuf
, '.' );
145 if( !ext
) return NULL
;
148 char *fn
= cxr_findext( wbuf
, '/' );
150 if( !fn
) return NULL
;
154 char *pCur
= ((char *)self
) + sizeof( VPKHeader
);
160 int bExt
= !strcmp( ext
, pCur
);
162 while( *( pCur
++ ) ) {};
165 if( !*pCur
) { pCur
++; break; }
167 int bDir
= !strcmp( dir
, pCur
);
169 while( *( pCur
++ ) ) {};
172 if( !*pCur
) { pCur
++; break; }
174 const char *vpk_fn
= pCur
;
176 while( *( pCur
++ ) ) {};
177 VPKDirectoryEntry
*entry
= (VPKDirectoryEntry
*)pCur
;
179 if( !strcmp( vpk_fn
, fn
) && bExt
&& bDir
)
184 pCur
+= entry
->PreloadBytes
+ sizeof( VPKDirectoryEntry
);
187 if( bDir
&& bExt
) return NULL
;
190 if( bExt
) return NULL
;
219 static vdf_node
*vdf_next( vdf_node
*node
, const char *name
, int *it
)
224 for( int i
= it
? *it
: 0; i
< node
->abnodes
.count
; i
++ )
226 vdf_node
**ptr_child
= cxr_ab_ptr( &node
->abnodes
, i
),
229 if( !name
|| !strcmp( name
, child
->name
))
239 static char *kv_next( vdf_node
*node
, const char *key
, int *it
)
245 while( *it
< node
->abpairs
.count
)
247 vdf_kv
*kv
= cxr_ab_ptr( &node
->abpairs
, *it
);
249 if( !strcmp( kv
->key
, key
) )
263 static const char *kv_get( vdf_node
*node
, const char *key
,
264 const char *value_defalt
)
267 char *val
= kv_next( node
, key
, &it
);
275 static void vdf_str_to_int( const char *src
, void *dest
)
277 *((int *)dest
) = atoi( src
);
280 static void vdf_str_to_float( const char *src
, void *dest
)
282 *((float *)dest
) = atof( src
);
285 static void vdf_str_to_double( const char *src
, void *dest
)
287 *((double *)dest
) = atof( src
);
290 static void kv_parse_array( const char *source
, u32 esize
, u32 count
,
291 void(*interp_func
)(const char *src
, void *dest
), void *arr
)
296 char value_buf
[ 64 ];
302 char const *c
= source
;
306 if( *c
==' ' || *c
=='\t' || *c
=='[' || *c
==']' || *c
=='(' || *c
==')' )
310 value_buf
[ k
] = 0x00;
313 interp_func( value_buf
, ((u8
*)arr
) + i
*esize
);
332 if( k
< sizeof( value_buf
) - 1 )
334 value_buf
[ k
++ ] = *c
;
342 /* Add remaining case if we hit null */
343 if( token
&& (i
< count
) )
345 value_buf
[ k
] = 0x00;
346 interp_func( value_buf
, ((u8
*)arr
) + i
*esize
);
350 static void kv_int_array( vdf_node
*node
, const char *key
, u32 count
, int *arr
)
352 kv_parse_array( kv_get( node
, key
, NULL
), sizeof(int), count
,
353 vdf_str_to_int
, arr
);
356 static void kv_float_array( vdf_node
*node
, const char *key
, u32 count
,
359 kv_parse_array( kv_get( node
, key
, NULL
), sizeof(float), count
,
360 vdf_str_to_float
, arr
);
363 static void kv_double_array( vdf_node
*node
, const char *key
, u32 count
,
366 kv_parse_array( kv_get( node
, key
, NULL
), sizeof(double), count
,
367 vdf_str_to_double
, arr
);
370 static int kv_get_int( vdf_node
*node
, const char *key
,
371 const int default_value
)
373 const char *v
= kv_get( node
, key
, NULL
);
374 return v
? atoi(v
): default_value
;
377 static float kv_get_float( vdf_node
*node
, const char *key
,
378 float default_value
)
380 const char *v
= kv_get( node
, key
, NULL
);
381 return v
? atof( v
): default_value
;
384 static vdf_node
*vdf_create_node( vdf_node
*parent
, const char *name
)
386 vdf_node
*node
= calloc( 1, sizeof( vdf_node
) );
389 cxr_ab_init( &node
->abnodes
, sizeof( vdf_node
* ), 0 );
390 cxr_ab_init( &node
->abpairs
, sizeof( vdf_kv
), 0 );
394 node
->name
= cxr_str_clone(name
, 0);
399 node
->parent
= parent
;
401 vdf_node
**child
= cxr_ab_empty( &parent
->abnodes
);
408 static void vdf_kv_append( vdf_node
*p
, const char *k
, const char *v
)
410 vdf_kv
*kv
= cxr_ab_empty( &p
->abpairs
);
412 u32 sv
= strlen(v
)+1;
413 u32 sk
= strlen(k
)+1;
415 kv
->key
= malloc( sv
+sk
);
416 kv
->value
= kv
->key
+sk
;
418 memcpy( kv
->key
, k
, sk
);
419 memcpy( kv
->value
, v
, sv
);
422 static void vdf_free_r( vdf_node
*p
)
424 for( int i
= 0; i
< p
->abpairs
.count
; i
++ )
426 vdf_kv
*kv
= cxr_ab_ptr( &p
->abpairs
, i
);
427 free( kv
->key
); /* key and value are allocated in the same buffer */
430 for( int i
= 0; i
< p
->abnodes
.count
; i
++ )
432 vdf_node
**ptr_node
= cxr_ab_ptr( &p
->abnodes
, i
);
433 vdf_free_r( *ptr_node
);
436 cxr_ab_free( &p
->abpairs
);
437 cxr_ab_free( &p
->abnodes
);
471 static void vdf_newln( vdf_ctx
*ctx
)
475 ctx
->st
.tokens
[0] = NULL
;
476 ctx
->st
.tokens
[1] = NULL
;
480 static void vdf_endl( vdf_ctx
*ctx
)
482 if( ctx
->st
.tokens
[0] )
485 if( ctx
->st
.tokens
[1] )
487 vdf_kv_append( ctx
->st
.pnode
, ctx
->st
.tokens
[0], ctx
->st
.tokens
[1] );
492 strcpy( ctx
->name
, ctx
->st
.tokens
[0] );
493 ctx
->st
.expect_decl
= 1;
500 static int vdf_line_control( vdf_ctx
*ctx
)
502 if( *ctx
->st
.ptr_read
== '\r' )
504 *ctx
->st
.ptr_read
= 0x00;
507 if( *ctx
->st
.ptr_read
== '\n' )
509 *ctx
->st
.ptr_read
= 0x00;
517 static void vdf_wait_endl( vdf_ctx
*ctx
)
519 while( (*ctx
->st
.ptr_read
) && (*ctx
->st
.ptr_read
!= '\n') )
521 if( vdf_line_control( ctx
) == 2 )
530 static void vdf_parse_string( vdf_ctx
*ctx
)
532 while( *ctx
->st
.ptr_read
)
534 if( *ctx
->st
.ptr_read
== '"' )
536 *ctx
->st
.ptr_read
= 0x00;
540 if( vdf_line_control( ctx
) )
542 /* Unexpected end of line */
550 static int vdf_parse_structure( vdf_ctx
*ctx
)
552 if( *ctx
->st
.ptr_read
== '{' )
554 if( ctx
->st
.tokens
[0] || !ctx
->st
.expect_decl
)
556 /* Unexpected token '{' */
560 ctx
->st
.expect_decl
= 0;
561 ctx
->st
.pnode
= vdf_create_node( ctx
->st
.pnode
, ctx
->name
);
563 vdf_wait_endl( ctx
);
567 if( *ctx
->st
.ptr_read
== '}' )
569 if( !ctx
->st
.pnode
->parent
)
571 /* Unexpected token '}' */
576 ctx
->st
.pnode
= ctx
->st
.pnode
->parent
;
579 vdf_wait_endl( ctx
);
586 static void vdf_parse_begin_token( vdf_ctx
*ctx
, char *ptr
)
588 ctx
->st
.tokens
[ ctx
->st
.i
] = ptr
;
590 if( ctx
->st
.expect_decl
)
592 /* Unexpected token 'name' */
597 static void vdf_parse_feedbuffer( vdf_ctx
*ctx
, char *buf
)
599 ctx
->st
.ptr_read
= buf
;
601 while( *ctx
->st
.ptr_read
)
603 if( !vdf_line_control( ctx
) )
605 if( (*ctx
->st
.ptr_read
== '/') && (ctx
->st
.ptr_read
[1] == '/') )
607 *ctx
->st
.ptr_read
= 0x00;
608 ctx
->st
.ptr_read
+= 2;
611 vdf_wait_endl( ctx
);
615 if( !vdf_parse_structure( ctx
) )
617 if( *ctx
->st
.ptr_read
== ' ' || *ctx
->st
.ptr_read
== '\t' )
619 *ctx
->st
.ptr_read
= 0x00;
621 if( ctx
->st
.tokens
[ ctx
->st
.i
] )
627 vdf_wait_endl( ctx
);
633 else if( !ctx
->st
.tokens
[ ctx
->st
.i
] )
635 if( *ctx
->st
.ptr_read
== '"' )
637 *ctx
->st
.ptr_read
= 0x00;
640 vdf_parse_begin_token( ctx
, ctx
->st
.ptr_read
);
641 vdf_parse_string( ctx
);
645 if( !( *ctx
->st
.ptr_read
== '/' &&
646 *(ctx
->st
.ptr_read
+ 1) == *ctx
->st
.ptr_read
) )
648 vdf_parse_begin_token( ctx
, ctx
->st
.ptr_read
);
660 static int vdf_load_into( const char *fn
, vdf_node
*node
)
662 char *text_src
= cxr_textasset_read( fn
);
670 ctx
.root
= ctx
.st
.pnode
= node
;
673 vdf_parse_feedbuffer( &ctx
, text_src
);
679 static vdf_node
*vdf_open_file( const char *fn
)
681 vdf_node
*root
= vdf_create_node( NULL
, NULL
);
682 if( vdf_load_into( fn
, root
) )
697 CXR_API i32
cxr_fs_set_gameinfo( const char *path
)
699 valve_file_system
*fs
= &fs_global
;
701 if( fs
->initialized
)
704 vdf_node
*info
= vdf_open_file( path
);
708 fs
->gamedir
= cxr_str_clone( path
, 0 );
709 cxr_downlvl( fs
->gamedir
);
711 fs
->exedir
= cxr_str_clone( fs
->gamedir
, 0 );
712 cxr_downlvl( fs
->exedir
);
714 cxr_log( "Setting up file system:\n"
719 path
, fs
->gamedir
, fs
->exedir
);
721 /* get search paths */
722 vdf_node
*search_paths
=
727 vdf_next( info
, "GameInfo", NULL
),
735 cxr_ab_init( &fs
->searchpaths
, sizeof( char *), 0 );
737 kv_foreach( search_paths
, "Game", kv_game
)
739 cxr_log( "Game %s\n", kv_game
);
741 if( kv_game
[0] == '|' ) continue;
744 if( cxr_path_is_abs( kv_game
) )
746 buf
= cxr_str_clone( kv_game
, 1 );
751 buf
= cxr_str_clone( fs
->exedir
, strlen(kv_game
)+1 );
752 strcat( buf
, kv_game
);
756 char **sp
= cxr_ab_empty( &fs
->searchpaths
);
762 /* Find pack diretory */
764 for( int i
= 0; i
< fs
->searchpaths
.count
; i
++ )
766 char **sp
= cxr_ab_ptr( &fs
->searchpaths
, i
);
768 strcpy( pack_path
, *sp
);
769 strcat( pack_path
, "pak01_dir.vpk" );
771 if( (fs
->vpk
= (VPKHeader
*)cxr_asset_read( pack_path
)) )
777 cxr_log( "Could not locate pak01_dir.vpk in %i searchpaths. "
778 "Stock models will not load!\n", fs
->searchpaths
.count
);
785 CXR_API
void cxr_fs_exit(void)
787 valve_file_system
*fs
= &fs_global
;
789 for( int i
= 0; i
< fs
->searchpaths
.count
; i
++ )
791 char **sp
= cxr_ab_ptr( &fs
->searchpaths
, i
);
795 cxr_ab_free( &fs
->searchpaths
);
803 if( fs
->current_archive
)
805 fclose( fs
->current_archive
);
806 fs
->current_archive
= NULL
;
812 memset( fs
, 0, sizeof( valve_file_system
) );
815 CXR_API
char *cxr_fs_get( const char *path
)
817 valve_file_system
*fs
= &fs_global
;
819 if( !fs
->initialized
)
822 VPKDirectoryEntry
*entry
;
827 if( (entry
= vpk_find( fs
->vpk
, path
)) )
829 if( entry
->ArchiveIndex
!= fs
->current_idx
)
831 if( fs
->current_archive
)
833 fclose( fs
->current_archive
);
834 fs
->current_archive
= NULL
;
837 fs
->current_idx
= entry
->ArchiveIndex
;
840 if( !fs
->current_archive
)
842 sprintf( pak
, "%scsgo/pak01_%03hu.vpk", fs
->exedir
,
844 fs
->current_archive
= fopen( pak
, "rb" );
846 if( !fs
->current_archive
)
848 cxr_log( "Could not locate %s\n", pak
);
853 char *filebuf
= malloc( entry
->EntryLength
);
855 fseek( fs
->current_archive
, entry
->EntryOffset
, SEEK_SET
);
856 if( fread( filebuf
, 1, entry
->EntryLength
, fs
->current_archive
)
857 == entry
->EntryLength
)
869 /* Use physical search paths */
870 char path_buf
[ 512 ];
872 for( int i
= 0; i
< fs
->searchpaths
.count
; i
++ )
874 char **sp
= cxr_ab_ptr( &fs
->searchpaths
, i
);
876 strcpy( path_buf
, *sp
);
877 strcat( path_buf
, path
);
880 if( (filebuf
= cxr_asset_read( path_buf
)) )
891 * This software is not affiliated with Valve Corporation
892 * We are not affiliated, associated, authorized, endorsed by, or in any way
893 * officially connected with Valve Corporation, or any of its subsidiaries or
896 * All trademarks are property of their respective owners
899 #define MAX_NUM_LODS 8
900 #define MAX_NUM_BONES_PER_VERT 3
902 #pragma pack(push, 1)
905 float weight
[MAX_NUM_BONES_PER_VERT
];
906 char bone
[MAX_NUM_BONES_PER_VERT
];
913 boneWeight_t boneweights
;
926 int numLodVertexes
[MAX_NUM_LODS
];
930 int tangentDataStart
;
936 static mstudiovertex_t
*GetVertexData( vertexFileHeader_t
*t
)
938 return (mstudiovertex_t
*) ( (char *)t
+ t
->vertexDataStart
);
945 #pragma pack(push, 1)
949 unsigned char boneWeightIndex
[3];
950 unsigned char numBones
;
952 unsigned short origMeshVertID
;
959 STRIPGROUP_IS_FLEXED
= 0x01,
960 STRIPGROUP_IS_HWSKINNED
= 0x02,
961 STRIPGROUP_IS_DELTA_FLEXED
= 0x04,
962 STRIPGROUP_SUPPRESS_HW_MORPH
= 0x08
965 enum StripHeaderFlags_t
{
966 STRIP_IS_TRILIST
= 0x01,
967 STRIP_IS_TRISTRIP
= 0x02 /* Unused by studiomdl 2015? */
982 int numBoneStateChanges
;
983 int boneStateChangeOffset
;
1000 VTXStripGroupHeader_t
;
1002 static VTXVertex_t
*pVertexVTX( VTXStripGroupHeader_t
*t
, int i
)
1004 return (VTXVertex_t
*)(((char *)t
) + t
->vertOffset
) + i
;
1007 static unsigned short *pIndexVTX( VTXStripGroupHeader_t
*t
, int i
)
1009 return (unsigned short *)(((char *)t
) + t
->indexOffset
) + i
;
1012 static VTXStripHeader_t
*pStripVTX( VTXStripGroupHeader_t
*t
, int i
)
1014 return (VTXStripHeader_t
*)(((char *)t
) + t
->stripOffset
) + i
;
1020 int stripGroupHeaderOffset
;
1022 unsigned char flags
;
1025 static VTXStripGroupHeader_t
*pStripGroupVTX( VTXMeshHeader_t
*t
, int i
)
1027 return (VTXStripGroupHeader_t
*)(((char *)t
) + t
->stripGroupHeaderOffset
) +i
;
1037 VTXModelLODHeader_t
;
1038 static VTXMeshHeader_t
*pMeshVTX( VTXModelLODHeader_t
*t
, int i
)
1040 return (VTXMeshHeader_t
*)(((char *)t
) + t
->meshOffset
) + i
;
1049 static VTXModelLODHeader_t
*pLODVTX( VTXModelHeader_t
*t
, int i
)
1051 return (VTXModelLODHeader_t
*)(((char *)t
) + t
->lodOffset
) + i
;
1059 VTXBodyPartHeader_t
;
1060 static VTXModelHeader_t
*pModelVTX( VTXBodyPartHeader_t
*t
, int i
)
1062 return (VTXModelHeader_t
*)(((char *)t
) + t
->modelOffset
) + i
;
1067 int version
; /* 7 */
1069 /* hardware params that affect how the model is to be optimized. */
1071 unsigned short maxBonesPerStrip
;
1072 unsigned short maxBonesPerTri
;
1073 int maxBonesPerVert
;
1077 int materialReplacementListOffset
;
1082 static VTXBodyPartHeader_t
*pBodyPartVTX( VTXFileHeader_t
*t
, int i
)
1084 return (VTXBodyPartHeader_t
*)(((char *)t
) + t
->bodyPartOffset
) + i
;
1089 =============================================
1097 L VerticesTable[StudioMDL.Vertex]
1098 L IndicesTable[UINT16]
1111 #pragma pack(push, 1)
1118 mstudio_modelvertexdata_t
;
1122 int unused_modelvertexdata
;
1123 int numLODVertexes
[MAX_NUM_LODS
];
1125 mstudio_modelvertexdata_t
*_the_death_ptr
;
1127 mstudio_meshvertexdata_t
;
1129 typedef struct mstudiomodel_t mstudiomodel_t
;
1142 mstudio_meshvertexdata_t vertexdata
;
1147 struct mstudiomodel_t
1151 float boundingradius
;
1161 int attachmentindex
;
1166 mstudio_modelvertexdata_t vertexdata
;
1170 static mstudiomesh_t
*studiomodel_pMesh( mstudiomodel_t
*t
, int i
)
1172 return (mstudiomesh_t
*)(((char *)t
) + t
->meshindex
) + i
;
1181 } mstudiobodyparts_t
;
1183 static mstudiomodel_t
*mstudiobodyparts_pModel( mstudiobodyparts_t
*t
, int i
)
1185 return (mstudiomodel_t
*)(((char *)t
) + t
->modelindex
) + i
;
1195 float eyeposition
[3];
1196 float illumposition
[3];
1199 float view_bbmin
[3];
1200 float view_bbmax
[3];
1204 int numbonecontrollers
;
1205 int bonecontrollerindex
;
1212 int activitylistversion
;
1219 int numskinfamilies
;
1223 int numlocalattachments
;
1224 int localattachmentindex
;
1227 int localnodenameindex
;
1230 int numflexcontrollers
;
1231 int flexcontrollerindex
;
1238 int numlocalposeparameters
;
1239 int localposeparamindex
;
1240 int surfacepropindex
;
1243 int numlocalikautoplaylocks
;
1244 int localikautoplaylockindex
;
1247 int numincludemodels
;
1248 int includemodelindex
;
1249 int szanimblocknameindex
;
1252 int bonetablebynameindex
;
1253 char constdirectionallightdot
;
1255 char numAllowedRootLODs
;
1258 int numflexcontrollerui
;
1259 int flexcontrolleruiindex
;
1260 float flVertAnimFixedPointScale
;
1262 int studiohdr2index
;
1267 static mstudiobodyparts_t
*studiohdr_pBodypart( studiohdr_t
*t
, int i
)
1269 return (mstudiobodyparts_t
*)(((char *)t
) + t
->bodypartindex
) + i
;
1274 static u32
vtx_count_indices( VTXFileHeader_t
*pVtxHdr
, studiohdr_t
*pMdl
)
1276 int indice_count
= 0;
1278 for( int bodyID
= 0; bodyID
< pVtxHdr
->numBodyParts
; ++bodyID
)
1281 VTXBodyPartHeader_t
* pVtxBodyPart
= pBodyPartVTX( pVtxHdr
, bodyID
);
1282 mstudiobodyparts_t
*pBodyPart
= studiohdr_pBodypart( pMdl
, bodyID
);
1284 for( int modelID
= 0; modelID
< pBodyPart
->nummodels
; ++modelID
)
1287 VTXModelHeader_t
* pVtxModel
= pModelVTX( pVtxBodyPart
, modelID
);
1288 mstudiomodel_t
*pStudioModel
=
1289 mstudiobodyparts_pModel( pBodyPart
, modelID
);
1292 VTXModelLODHeader_t
*pVtxLOD
= pLODVTX( pVtxModel
, nLod
);
1294 for( int nMesh
= 0; nMesh
< pStudioModel
->nummeshes
; ++nMesh
)
1297 VTXMeshHeader_t
* pVtxMesh
= pMeshVTX( pVtxLOD
, nMesh
);
1298 mstudiomesh_t
* pMesh
= studiomodel_pMesh( pStudioModel
, nMesh
);
1300 for ( int nGroup
= 0; nGroup
< pVtxMesh
->numStripGroups
; ++nGroup
)
1303 VTXStripGroupHeader_t
* pStripGroup
=
1304 pStripGroupVTX( pVtxMesh
, nGroup
);
1306 for ( int nStrip
= 0; nStrip
< pStripGroup
->numStrips
; nStrip
++ )
1309 VTXStripHeader_t
*pStrip
= pStripVTX( pStripGroup
, nStrip
);
1311 if ( pStrip
->flags
& STRIP_IS_TRILIST
)
1313 indice_count
+= pStrip
->numIndices
;
1321 return indice_count
;
1324 #endif /* CXR_VALVE_BIN_H */