f2b007fdd92bd13b0f1b65defa3602916e92fe54
1 typedef struct csr_frag csr_frag
;
2 typedef struct csr_target csr_target
;
3 typedef struct csr_filter csr_filter
;
19 v2f csr_msaa_2x2rgss
[] =
46 const char *visgroup
; // Limit to this visgroup only
47 const char *classname
; // Limit to this exact classname. will not draw world
49 int compute_bounds_only
;
52 void csr_create_target( csr_target
*rt
, u32 x
, u32 y
)
58 rt
->fragments
= (csr_frag
*)csr_malloc( x
*y
*sizeof(csr_frag
)*rt
->num_samples
);
60 v3_fill( rt
->bounds
[0], INFINITY
);
61 v3_fill( rt
->bounds
[1], -INFINITY
);
64 void csr_update_subsamples( csr_target
*rt
)
66 float range_x
= (rt
->bounds
[1][0]-rt
->bounds
[0][0]);
67 float range_y
= (rt
->bounds
[1][1]-rt
->bounds
[0][1]);
69 v2f pixel_size
= { range_x
/(float)rt
->x
, range_y
/(float)rt
->y
};
71 rt
->subsamples
[0][0] = pixel_size
[0] * -0.25f
;
72 rt
->subsamples
[0][1] = 0.f
;
73 rt
->subsamples
[1][0] = pixel_size
[0] * 0.75f
;
74 rt
->subsamples
[1][1] = pixel_size
[1] * 0.25f
;
75 rt
->subsamples
[2][0] = 0.f
;
76 rt
->subsamples
[2][1] = pixel_size
[1] * 0.5f
;
77 rt
->subsamples
[3][0] = pixel_size
[0] * 0.5f
;
78 rt
->subsamples
[3][1] = pixel_size
[1] * 0.75f
;
81 void csr_rt_free( csr_target
*rt
)
83 free( rt
->fragments
);
86 void csr_rt_clear( csr_target
*rt
)
88 for( u32 i
= 0; i
< rt
->x
*rt
->y
*rt
->num_samples
; i
++ )
90 v3_zero( rt
->fragments
[ i
].co
);
91 v3_zero( rt
->fragments
[ i
].nrm
);
92 rt
->fragments
[i
].depth
= 0.f
;
96 void csr_auto_fit( csr_target
*rt
, float padding
)
98 // Correct aspect ratio to be square
99 float dx
, dy
, d
, l
, cx
, cy
;
100 dx
= rt
->bounds
[1][0] - rt
->bounds
[0][0];
101 dy
= rt
->bounds
[1][1] - rt
->bounds
[0][1];
103 l
= fmaxf( dx
, dy
) * .5f
;
105 cx
= (rt
->bounds
[1][0] + rt
->bounds
[0][0]) * .5f
;
106 cy
= (rt
->bounds
[1][1] + rt
->bounds
[0][1]) * .5f
;
108 rt
->bounds
[0][0] = cx
- l
- padding
;
109 rt
->bounds
[1][0] = cx
+ l
+ padding
;
110 rt
->bounds
[0][1] = cy
- l
- padding
;
111 rt
->bounds
[1][1] = cy
+ l
+ padding
;
113 rt
->scale
= l
+ padding
;
115 csr_update_subsamples( rt
);
118 void csr_write_txt( char const *path
, const char *name
, csr_target
*rt
)
122 write_ptr
= fopen( path
, "w" );
124 fprintf( write_ptr
, "\"%s\"\n\{\n", name
);
125 fprintf( write_ptr
, "\t\"material\" \"overviews/%s\"\n", name
);
126 fprintf( write_ptr
, "\t\"pos_x\" \"%.8f\"\n", rt
->bounds
[0][0] );
127 fprintf( write_ptr
, "\t\"pos_y\" \"%.8f\"\n", rt
->bounds
[0][1] );
128 fprintf( write_ptr
, "\t\"scale\" \"%.8f\"\n", rt
->scale
/ (float)rt
->x
);
129 fprintf( write_ptr
, "}\n" );
134 void simple_raster( csr_target
*rt
, vmf_vert tri
[3] )
136 // Very very simplified rasterizing algorithm
137 v2f bmin
= { 0.f
, 0.f
};
138 v2f bmax
= { rt
->x
, rt
->y
};
140 v2_minv( tri
[0].co
, tri
[1].co
, bmin
);
141 v2_minv( tri
[2].co
, bmin
, bmin
);
143 v2_maxv( tri
[0].co
, tri
[1].co
, bmax
);
144 v2_maxv( tri
[2].co
, bmax
, bmax
);
146 float range_x
= (rt
->bounds
[1][0]-rt
->bounds
[0][0])/(float)rt
->x
;
147 float range_y
= (rt
->bounds
[1][1]-rt
->bounds
[0][1])/(float)rt
->y
;
149 int start_x
= csr_min( rt
->x
-1, csr_max( 0, floorf( (bmin
[0]-rt
->bounds
[0][0])/range_x
)));
150 int end_x
= csr_max( 0, csr_min( rt
->x
-1, ceilf( (bmax
[0]-rt
->bounds
[0][0])/range_x
)));
151 int start_y
= csr_min( rt
->y
-1, csr_max( 0, floorf( (bmin
[1]-rt
->bounds
[0][1])/range_y
)));
152 int end_y
= csr_max( 0, csr_min( rt
->y
-1, ceilf( (bmax
[1]-rt
->bounds
[0][1])/range_y
)));
155 float d
, bca
= 0.f
, bcb
= 0.f
, bcc
= 0.f
;
157 v2_sub( tri
[1].co
, tri
[0].co
, v0
);
158 v2_sub( tri
[2].co
, tri
[0].co
, v1
);
159 v2_sub( tri
[1].co
, tri
[2].co
, v2
);
160 d
= 1.f
/ (v0
[0]*v1
[1] - v1
[0]*v0
[1]);
163 if( v2_cross( v0
, v1
) > 0.f
)
168 for( u32 py
= start_y
; py
<= end_y
; py
++ )
170 trace_origin
[1] = csr_lerpf( rt
->bounds
[0][1], rt
->bounds
[1][1], (float)py
/(float)rt
->y
);
172 for( u32 px
= start_x
; px
<= end_x
; px
++ )
174 csr_frag
*frag
= &rt
->fragments
[ (py
* rt
->y
+ px
) * rt
->num_samples
];
176 trace_origin
[0] = csr_lerpf( rt
->bounds
[0][0], rt
->bounds
[1][0], (float)px
/(float)rt
->x
);
178 // Determine coverage
179 for( int i
= 0; i
< rt
->num_samples
; i
++ )
183 v2_add( rt
->subsamples
[ i
], trace_origin
, sample_origin
);
184 v2_sub( sample_origin
, tri
[0].co
, vp
);
186 if( v2_cross( v0
, vp
) > 0.f
)
188 if( v2_cross( vp
, v1
) > 0.f
)
192 v2_sub( sample_origin
, tri
[2].co
, vp2
);
194 if( v2_cross( vp2
, v2
) > 0.f
)
197 bcb
= (vp
[0]*v1
[1] - v1
[0]*vp
[1]) * d
;
198 bcc
= (v0
[0]*vp
[1] - vp
[0]*v0
[1]) * d
;
199 bca
= 1.f
- bcb
- bcc
;
201 float hit
= (tri
[0].co
[2] * bca
+ tri
[1].co
[2] * bcb
+ tri
[2].co
[2] * bcc
) +16385.f
;
203 if( hit
> frag
[i
].depth
)
206 v3_muls( tri
[0].co
, bca
, frag
[i
].co
);
207 v3_muladds( frag
[i
].co
, tri
[1].co
, bcb
, frag
[i
].co
);
208 v3_muladds( frag
[i
].co
, tri
[2].co
, bcc
, frag
[i
].co
);
210 // TODO: Same for normal map
217 void csr_draw( csr_target
*rt
, vmf_vert
*triangles
, u32 triangle_count
, m4x3f transform
)
222 // Derive normal matrix
223 m4x3_to_3x3( transform
, normal
);
225 // NOTE: This isn't strictly necessary since CS:GO only uses uniform scaling.
226 m3x3_inv_transpose( normal
, normal
);
228 for( u32 i
= 0; i
< triangle_count
; i
++ )
230 vmf_vert
*triangle
= triangles
+ i
*3;
232 m4x3_mulv( transform
, triangle
[0].co
, new_tri
[0].co
);
233 m4x3_mulv( transform
, triangle
[1].co
, new_tri
[1].co
);
234 m4x3_mulv( transform
, triangle
[2].co
, new_tri
[2].co
);
235 m3x3_mulv( normal
, triangle
[0].nrm
, new_tri
[0].nrm
);
236 m3x3_mulv( normal
, triangle
[1].nrm
, new_tri
[1].nrm
);
237 m3x3_mulv( normal
, triangle
[2].nrm
, new_tri
[2].nrm
);
239 simple_raster( rt
, new_tri
);
243 void draw_vmf_group( csr_target
*rt
, vmf_map
*map
, vdf_node
*root
, csr_filter
*filter
, m4x3f prev
, m4x3f inst
)
245 m4x3f transform
= M4X3_IDENTITY
;
251 int filter_visgroups
= 0, filter_classname
= 0, compute_bounds_only
= 0;
255 if( filter
->visgroup
)
257 filter_visgroups
= 1;
258 group_id
= vmf_visgroup_id( root
, filter
->visgroup
);
261 if( filter
->classname
)
263 filter_classname
= 1;
266 compute_bounds_only
= filter
->compute_bounds_only
;
269 // Multiply previous transform with instance transform to create basis
272 m4x3_mul( prev
, inst
, transform
);
275 // Gather world brushes
276 solidgen_ctx_init( &solid
);
278 if( !filter_classname
)
280 vdf_node
*world
= vdf_next( root
, "world", NULL
);
282 vdf_foreach( world
, "solid", brush
)
284 if( filter_visgroups
&& !vmf_visgroup_match( brush
, group_id
) )
287 // TODO: heap-use-after-free
288 solidgen_push( &solid
, brush
);
292 // Actual entity loop
295 vdf_foreach( root
, "entity", ent
)
297 if( filter_visgroups
&& !vmf_visgroup_match( ent
, group_id
) )
300 if( filter_classname
)
301 if( strcmp( kv_get( ent
, "classname", "" ), filter
->classname
) )
304 if( ent
->user
& VMF_FLAG_IS_PROP
)
306 // Create model transform
307 m4x3_identity( model
);
309 vmf_entity_transform( ent
, model
);
310 m4x3_mul( transform
, model
, model
);
313 mdl_mesh_t
*mdl
= &map
->models
[ ent
->user1
].mdl
;
315 if( compute_bounds_only
)
317 box_copy( mdl
->bounds
, trf_bounds
);
318 m4x3_transform_aabb( model
, trf_bounds
);
321 box_concat( rt
->bounds
, trf_bounds
);
325 for( int i
= 0; i
< mdl
->num_indices
/3; i
++ )
327 for( int j
= 0; j
< 3; j
++ )
329 v3_copy( &mdl
->vertices
[ mdl
->indices
[ i
*3+j
] *8 ], tri
[j
].co
);
330 v3_copy( &mdl
->vertices
[ mdl
->indices
[ i
*3+j
] *8+3 ], tri
[j
].nrm
);
335 csr_draw( rt
, tri
, 1, model
);
339 else if( ent
->user
& VMF_FLAG_IS_INSTANCE
)
341 m4x3_identity( model
);
342 vmf_entity_transform( ent
, model
);
344 draw_vmf_group( rt
, map
, map
->cache
[ ent
->user1
].root
, filter
, transform
, model
);
349 vdf_foreach( ent
, "solid", ent_solid
)
351 solidgen_push( &solid
, ent_solid
);
356 if( compute_bounds_only
)
358 solidgen_bounds( &solid
, trf_bounds
);
359 m4x3_transform_aabb( transform
, trf_bounds
);
360 box_concat( rt
->bounds
, trf_bounds
);
365 for( int i
= 0; i
< csr_sb_count( solid
.indices
)/3; i
++ )
367 u32
* base
= solid
.indices
+ i
*3;
369 tri
[0] = solid
.verts
[ base
[0] ];
370 tri
[1] = solid
.verts
[ base
[1] ];
371 tri
[2] = solid
.verts
[ base
[2] ];
373 csr_draw( rt
, tri
, 1, transform
);
377 solidgen_ctx_reset( &solid
);
378 solidgen_ctx_free( &solid
);
381 void csr_rt_save_buffers( csr_target
*rt
, const char *basename
, const char *subname
)
385 float *image
= (float *)csr_malloc( 1024*1024*sizeof(float)*3 );
387 for( int l
= 0; l
< rt
->x
; l
++ )
389 for( int x
= 0; x
< rt
->y
; x
++ )
391 float *dst
= &image
[ (l
*1024+x
)*3 ];
392 csr_frag
*src
= &rt
->fragments
[ ((1023-l
)*1024+x
)*rt
->num_samples
];
395 v3_muls( src
[0].co
, 1.f
/(float)rt
->num_samples
, dst
);
396 v3_muladds( dst
, src
[1].co
, 1.f
/(float)rt
->num_samples
, dst
);
397 v3_muladds( dst
, src
[2].co
, 1.f
/(float)rt
->num_samples
, dst
);
398 v3_muladds( dst
, src
[3].co
, 1.f
/(float)rt
->num_samples
, dst
);
402 // Save position buffer
403 strcpy( output
, basename
);
404 strcat( output
, "." );
405 strcat( output
, subname
);
406 strcat( output
, "_position.pfm" );
407 csr_32f_write( output
, rt
->x
, rt
->y
, image
);