+ *indices += pStrip->numIndices;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * The following section is the wrappers for the underlying types
+ */
+
+struct valve_material
+{
+ char *basetexture,
+ *bumpmap;
+};
+
+struct valve_model
+{
+ float *vertex_data; /* pos xyz, norm xyz, uv xy */
+
+ u32 *indices,
+ indices_count,
+ vertex_count,
+ part_count,
+ material_count;
+
+ char **materials;
+
+ struct valve_model_batch
+ {
+ u32 material,
+ ibstart,
+ ibcount;
+ }
+ *parts;
+
+ /* Internal valve data */
+ studiohdr_t *studiohdr;
+ VTXFileHeader_t *vtxhdr;
+ vertexFileHeader_t *vvdhdr;
+};
+
+CXR_API valve_model *valve_load_model( const char *relpath )
+{
+ char path[1024];
+ strcpy( path, relpath );
+
+ char *ext = cxr_stripext( path );
+
+ if( !ext )
+ return NULL;
+
+ /* Load data files */
+ valve_model *model = malloc( sizeof( valve_model ) );
+ model->studiohdr = NULL;
+ model->vtxhdr = NULL;
+ model->vvdhdr = NULL;
+
+ strcpy( ext, ".dx90.vtx" );
+ model->vtxhdr = cxr_fs_get( path, 0 );
+
+ strcpy( ext, ".vvd" );
+ model->vvdhdr = cxr_fs_get( path, 0 );
+
+ strcpy( ext, ".mdl" );
+ model->studiohdr = cxr_fs_get( path, 0 );
+
+ if( !model->vvdhdr || !model->studiohdr || !model->vtxhdr )
+ {
+ cxr_log( "Error, failed to load: (%s)\n", relpath );
+
+ free( model->studiohdr );
+ free( model->vvdhdr );
+ free( model->studiohdr );
+ free( model );
+
+ return NULL;
+ }
+
+ /* allocate resources */
+ vtx_resource_counts( model->vtxhdr, model->studiohdr,
+ &model->indices_count, &model->part_count );
+ model->vertex_count = model->vvdhdr->numLodVertexes[0];
+ model->material_count = model->studiohdr->numtextures;
+
+ model->materials = malloc( model->material_count * sizeof(char *) );
+ model->parts = malloc( sizeof( valve_model_batch ) * model->part_count );
+ model->indices = malloc( sizeof( u32 ) * model->indices_count );
+ model->vertex_data = malloc( sizeof( float ) * 8 * model->vertex_count );
+
+ /* Find materials */
+ for( int i=0; i<model->studiohdr->numtextures; i++ )
+ {
+ char material_path[ 1024 ];
+ fs_locator locator;
+
+ mstudiotexture_t *tex = studiohdr_pTexture( model->studiohdr, i );
+ const char *name = mstudiotexture_pszName( tex );
+
+ model->materials[i] = NULL;
+
+ for( int j=0; j<model->studiohdr->numcdtextures; j++ )
+ {
+ char *cdpath = studiohdr_pCdtexture( model->studiohdr, j );
+ snprintf( material_path, 1023, "materials/%s%s.vmt", cdpath, name );
+ cxr_unixpath( material_path );
+
+ if( cxr_fs_find( material_path, &locator ))
+ {
+ model->materials[i] = cxr_str_clone( material_path, 0 );
+ break;
+ }
+ }
+ }
+
+ u32 i_index = 0,
+ i_mesh = 0;
+
+ /* Extract meshes */
+ for( int bodyID = 0; bodyID < model->studiohdr->numbodyparts; ++bodyID )
+ {
+ /* Body parts */
+ VTXBodyPartHeader_t* pVtxBodyPart = pBodyPartVTX( model->vtxhdr, bodyID );
+ mstudiobodyparts_t *pBodyPart =
+ studiohdr_pBodypart( model->studiohdr, bodyID );
+
+ for( int modelID = 0; modelID < pBodyPart->nummodels; ++modelID )
+ {
+ /* models */
+ VTXModelHeader_t* pVtxModel = pModelVTX( pVtxBodyPart, modelID );
+ mstudiomodel_t *pStudioModel =
+ mstudiobodyparts_pModel( pBodyPart, modelID );
+
+ int nLod = 0;
+ VTXModelLODHeader_t *pVtxLOD = pLODVTX( pVtxModel, nLod );
+
+ for( int nMesh = 0; nMesh < pStudioModel->nummeshes; ++nMesh )
+ {
+ /* meshes, each of these creates a new draw CMD */
+ VTXMeshHeader_t* pVtxMesh = pMeshVTX( pVtxLOD, nMesh );
+ mstudiomesh_t* pMesh = studiomodel_pMesh( pStudioModel, nMesh );
+
+ valve_model_batch *curBatch = &model->parts[ i_mesh ++ ];
+ curBatch->material = pMesh->material;
+ curBatch->ibstart = i_index;
+ curBatch->ibcount = 0;
+
+ for( int nGroup = 0; nGroup < pVtxMesh->numStripGroups; ++nGroup )
+ {
+ /* groups */
+ VTXStripGroupHeader_t* pStripGroup =
+ pStripGroupVTX( pVtxMesh, nGroup );
+
+ for( int nStrip = 0; nStrip < pStripGroup->numStrips; nStrip++ )
+ {
+ /* strips */
+ VTXStripHeader_t *pStrip = pStripVTX( pStripGroup, nStrip );
+
+ if( pStrip->flags & STRIP_IS_TRILIST )
+ {
+ /* indices */
+ for( int i = 0; i < pStrip->numIndices; i ++ )
+ {
+ u16 i1 = *pIndexVTX( pStripGroup,
+ pStrip->indexOffset + i );
+
+ model->indices[ i_index ++ ] =
+ pVertexVTX( pStripGroup, i1 )->origMeshVertID +
+ pMesh->vertexoffset;
+
+ curBatch->ibcount ++;
+ }