+ if( filter )
+ {
+ if( filter->visgroup )
+ {
+ filter_visgroups = 1;
+ group_id = vmf_visgroup_id( root, filter->visgroup );
+ }
+
+ if( filter->classname )
+ {
+ filter_classname = 1;
+ }
+
+ compute_bounds_only = filter->compute_bounds_only;
+ }
+
+ // Multiply previous transform with instance transform to create basis
+ if( prev )
+ {
+ m4x3_mul( prev, inst, transform );
+ }
+
+ // Gather world brushes
+ solidgen_ctx_init( &solid );
+
+ if( !filter_classname )
+ {
+ vdf_node *world = vdf_next( root, "world", NULL );
+
+ vdf_foreach( world, "solid", brush )
+ {
+ if( filter_visgroups && !vmf_visgroup_match( brush, group_id ) )
+ continue;
+
+ // TODO: heap-use-after-free
+ solidgen_push( &solid, brush );
+ }
+ }
+
+ // Actual entity loop
+ m4x3f model;
+
+ vdf_foreach( root, "entity", ent )
+ {
+ if( filter_visgroups && !vmf_visgroup_match( ent, group_id ) )
+ continue;
+
+ if( filter_classname )
+ if( strcmp( kv_get( ent, "classname", "" ), filter->classname ) )
+ continue;
+
+ if( ent->user & VMF_FLAG_IS_PROP )
+ {
+ // Create model transform
+ m4x3_identity( model );
+
+ vmf_entity_transform( ent, model );
+ m4x3_mul( transform, model, model );
+
+ // Draw model
+ mdl_mesh_t *mdl = &map->models[ ent->user1 ].mdl;
+
+ if( compute_bounds_only )
+ {
+ map->models[ ent->user1 ].need_load = 1;
+ m4x3_expand_aabb_point( model, rt->bounds, (v3f){0.f,0.f,0.f} );
+ }
+ else
+ {
+ for( int i = 0; i < mdl->num_indices/3; i ++ )
+ {
+ for( int j = 0; j < 3; j ++ )
+ {
+ v3_copy( &mdl->vertices[ mdl->indices[ i*3+j ] *8 ], tri[j].co );
+ v3_copy( &mdl->vertices[ mdl->indices[ i*3+j ] *8+3 ], tri[j].nrm );
+ v3_zero( tri[j].origin );
+ }
+
+ csr_draw( rt, tri, 1, model );
+ }
+ }
+ }
+ else if( ent->user & VMF_FLAG_IS_INSTANCE )
+ {
+ m4x3_identity( model );
+ vmf_entity_transform( ent, model );
+
+ csr_vmf_render( rt, map, map->cache[ ent->user1 ].root, filter, transform, model );
+ }
+ else
+ {
+ // Brush entity
+ vdf_foreach( ent, "solid", ent_solid )
+ {
+ solidgen_push( &solid, ent_solid );
+ }
+ }
+ }
+
+ if( compute_bounds_only )
+ {
+ solidgen_bounds( &solid, trf_bounds );
+ m4x3_transform_aabb( transform, trf_bounds );
+ box_concat( rt->bounds, trf_bounds );
+ }
+ else
+ {
+ // Draw brushes
+ for( int i = 0; i < csr_sb_count( solid.indices )/3; i ++ )
+ {
+ u32 * base = solid.indices + i*3;
+
+ tri[0] = solid.verts[ base[0] ];
+ tri[1] = solid.verts[ base[1] ];
+ tri[2] = solid.verts[ base[2] ];
+
+ csr_draw( rt, tri, 1, transform );
+ }
+ }
+
+ solidgen_ctx_reset( &solid );
+ solidgen_ctx_free( &solid );
+}
+
+void csr_write_filerr( const char *path )
+{
+ log_error( "File write error (No such file or directory): '%s'\n", path );