1 typedef struct csr_frag csr_frag
;
2 typedef struct csr_target csr_target
;
3 typedef struct csr_filter csr_filter
;
27 const char *visgroup
; // Limit to this visgroup only
28 const char *classname
; // Limit to this exact classname. will not draw world
30 int compute_bounds_only
;
33 void csr_create_target( csr_target
*rt
, u32 x
, u32 y
)
39 rt
->fragments
= (csr_frag
*)csr_malloc( x
*y
*sizeof(csr_frag
)*rt
->num_samples
);
41 v3_fill( rt
->bounds
[0], INFINITY
);
42 v3_fill( rt
->bounds
[1], -INFINITY
);
45 void csr_update_subsamples( csr_target
*rt
)
47 float range_x
= (rt
->bounds
[1][0]-rt
->bounds
[0][0]);
48 float range_y
= (rt
->bounds
[1][1]-rt
->bounds
[0][1]);
50 v2f pixel_size
= { range_x
/(float)rt
->x
, range_y
/(float)rt
->y
};
52 rt
->subsamples
[0][0] = pixel_size
[0] * -0.25f
;
53 rt
->subsamples
[0][1] = 0.f
;
54 rt
->subsamples
[1][0] = pixel_size
[0] * 0.75f
;
55 rt
->subsamples
[1][1] = pixel_size
[1] * 0.25f
;
56 rt
->subsamples
[2][0] = 0.f
;
57 rt
->subsamples
[2][1] = pixel_size
[1] * 0.5f
;
58 rt
->subsamples
[3][0] = pixel_size
[0] * 0.5f
;
59 rt
->subsamples
[3][1] = pixel_size
[1] * 0.75f
;
62 void csr_rt_free( csr_target
*rt
)
64 free( rt
->fragments
);
67 void csr_rt_clear( csr_target
*rt
)
69 for( u32 i
= 0; i
< rt
->x
*rt
->y
*rt
->num_samples
; i
++ )
71 v3_zero( rt
->fragments
[ i
].co
);
72 v3_zero( rt
->fragments
[ i
].nrm
);
73 rt
->fragments
[i
].depth
= 0.f
;
77 void csr_auto_fit( csr_target
*rt
, float padding
)
79 // Correct aspect ratio to be square
80 float dx
, dy
, d
, l
, cx
, cy
;
81 dx
= rt
->bounds
[1][0] - rt
->bounds
[0][0];
82 dy
= rt
->bounds
[1][1] - rt
->bounds
[0][1];
85 d
= l
* ( l
/ dx
) * .5f
;
87 cx
= (rt
->bounds
[1][0] + rt
->bounds
[0][0]) * .5f
;
88 cy
= (rt
->bounds
[1][1] + rt
->bounds
[0][1]) * .5f
;
90 rt
->bounds
[0][0] = cx
- d
- padding
;
91 rt
->bounds
[1][0] = cx
+ d
+ padding
;
92 rt
->bounds
[0][1] = cy
- d
- padding
;
93 rt
->bounds
[1][1] = cy
+ d
+ padding
;
95 rt
->scale
= d
+ padding
;
97 csr_update_subsamples( rt
);
100 void csr_write_txt( char const *path
, const char *name
, csr_target
*rt
)
104 write_ptr
= fopen( path
, "w" );
106 fprintf( write_ptr
, "\"%s\"\n\{\n", name
);
107 fprintf( write_ptr
, "\t\"material\" \"overviews/%s\"\n", name
);
108 fprintf( write_ptr
, "\t\"pos_x\" \"%.8f\"\n", rt
->bounds
[0][0] );
109 fprintf( write_ptr
, "\t\"pos_y\" \"%.8f\"\n", rt
->bounds
[0][1] );
110 fprintf( write_ptr
, "\t\"scale\" \"%.8f\"\n", rt
->scale
/ (float)rt
->x
);
111 fprintf( write_ptr
, "}\n" );
116 void simple_raster( csr_target
*rt
, vmf_vert tri
[3] )
118 // Very very simplified rasterizing algorithm
119 v2f bmin
= { 0.f
, 0.f
};
120 v2f bmax
= { rt
->x
, rt
->y
};
122 v2_minv( tri
[0].co
, tri
[1].co
, bmin
);
123 v2_minv( tri
[2].co
, bmin
, bmin
);
125 v2_maxv( tri
[0].co
, tri
[1].co
, bmax
);
126 v2_maxv( tri
[2].co
, bmax
, bmax
);
128 float range_x
= (rt
->bounds
[1][0]-rt
->bounds
[0][0])/(float)rt
->x
;
129 float range_y
= (rt
->bounds
[1][1]-rt
->bounds
[0][1])/(float)rt
->y
;
131 int start_x
= csr_min( rt
->x
-1, csr_max( 0, floorf( (bmin
[0]-rt
->bounds
[0][0])/range_x
)));
132 int end_x
= csr_max( 0, csr_min( rt
->x
-1, ceilf( (bmax
[0]-rt
->bounds
[0][0])/range_x
)));
133 int start_y
= csr_min( rt
->y
-1, csr_max( 0, floorf( (bmin
[1]-rt
->bounds
[0][1])/range_y
)));
134 int end_y
= csr_max( 0, csr_min( rt
->y
-1, ceilf( (bmax
[1]-rt
->bounds
[0][1])/range_y
)));
137 float d
, bca
= 0.f
, bcb
= 0.f
, bcc
= 0.f
;
139 v2_sub( tri
[1].co
, tri
[0].co
, v0
);
140 v2_sub( tri
[2].co
, tri
[0].co
, v1
);
141 v2_sub( tri
[1].co
, tri
[2].co
, v2
);
142 d
= 1.f
/ (v0
[0]*v1
[1] - v1
[0]*v0
[1]);
145 if( v2_cross( v0
, v1
) > 0.f
)
150 for( u32 py
= start_y
; py
<= end_y
; py
++ )
152 trace_origin
[1] = csr_lerpf( rt
->bounds
[0][1], rt
->bounds
[1][1], (float)py
/(float)rt
->y
);
154 for( u32 px
= start_x
; px
<= end_x
; px
++ )
156 csr_frag
*frag
= &rt
->fragments
[ (py
* rt
->y
+ px
) * rt
->num_samples
];
158 trace_origin
[0] = csr_lerpf( rt
->bounds
[0][0], rt
->bounds
[1][0], (float)px
/(float)rt
->x
);
160 // Determine coverage
161 for( int i
= 0; i
< rt
->num_samples
; i
++ )
165 v2_add( rt
->subsamples
[ i
], trace_origin
, sample_origin
);
166 v2_sub( sample_origin
, tri
[0].co
, vp
);
168 if( v2_cross( v0
, vp
) > 0.f
)
170 if( v2_cross( vp
, v1
) > 0.f
)
174 v2_sub( sample_origin
, tri
[2].co
, vp2
);
176 if( v2_cross( vp2
, v2
) > 0.f
)
179 bcb
= (vp
[0]*v1
[1] - v1
[0]*vp
[1]) * d
;
180 bcc
= (v0
[0]*vp
[1] - vp
[0]*v0
[1]) * d
;
181 bca
= 1.f
- bcb
- bcc
;
183 float hit
= (tri
[0].co
[2] * bca
+ tri
[1].co
[2] * bcb
+ tri
[2].co
[2] * bcc
) +16385.f
;
185 if( hit
> frag
[i
].depth
)
188 v3_muls( tri
[0].co
, bca
, frag
[i
].co
);
189 v3_muladds( frag
[i
].co
, tri
[1].co
, bcb
, frag
[i
].co
);
190 v3_muladds( frag
[i
].co
, tri
[2].co
, bcc
, frag
[i
].co
);
192 // TODO: Same for normal map
199 void csr_draw( csr_target
*rt
, vmf_vert
*triangles
, u32 triangle_count
, m4x3f transform
)
204 // Derive normal matrix
205 m4x3_to_3x3( transform
, normal
);
206 m3x3_inv_transpose( normal
, normal
);
208 for( u32 i
= 0; i
< triangle_count
; i
++ )
210 vmf_vert
*triangle
= triangles
+ i
*3;
212 m4x3_mulv( transform
, triangle
[0].co
, new_tri
[0].co
);
213 m4x3_mulv( transform
, triangle
[1].co
, new_tri
[1].co
);
214 m4x3_mulv( transform
, triangle
[2].co
, new_tri
[2].co
);
215 m3x3_mulv( normal
, triangle
[0].nrm
, new_tri
[0].nrm
);
216 m3x3_mulv( normal
, triangle
[1].nrm
, new_tri
[1].nrm
);
217 m3x3_mulv( normal
, triangle
[2].nrm
, new_tri
[2].nrm
);
219 simple_raster( rt
, new_tri
);
223 void draw_vmf_group( csr_target
*rt
, vmf_map
*map
, vdf_node
*root
, csr_filter
*filter
, m4x3f prev
, m4x3f inst
)
225 m4x3f transform
= M4X3_IDENTITY
;
232 int filter_visgroups
= 0, filter_classname
= 0, compute_bounds_only
= 0;
236 if( filter
->visgroup
)
238 filter_visgroups
= 1;
239 group_id
= vmf_visgroup_id( root
, filter
->visgroup
);
242 if( filter
->classname
)
244 filter_classname
= 1;
247 compute_bounds_only
= filter
->compute_bounds_only
;
250 // Multiply previous transform with instance transform to create basis
253 m4x3_mul( prev
, inst
, transform
);
256 // Gather world brushes
257 solidgen_ctx_init( &solid
);
259 if( !filter_classname
)
261 vdf_node
*world
= vdf_next( root
, "world", NULL
);
263 vdf_foreach( world
, "solid", brush
)
265 if( filter_visgroups
&& !vmf_visgroup_match( brush
, group_id
) )
268 solidgen_push( &solid
, brush
);
272 // Actual entity loop
275 vdf_foreach( root
, "entity", ent
)
277 if( filter_visgroups
&& !vmf_visgroup_match( ent
, group_id
) )
280 if( filter_classname
)
281 if( strcmp( kv_get( ent
, "classname", "" ), filter
->classname
) )
284 if( ent
->user
& VMF_FLAG_IS_PROP
)
286 // Create model transform
287 m4x3_identity( model
);
289 vmf_entity_transform( ent
, model
);
290 m4x3_mul( transform
, model
, model
);
293 mdl_mesh_t
*mdl
= &map
->models
[ ent
->user1
].mdl
;
295 if( compute_bounds_only
)
297 box_copy( mdl
->bounds
, trf_bounds
);
298 m4x3_transform_aabb( model
, trf_bounds
);
301 box_concat( rt
->bounds
, trf_bounds
);
305 for( int i
= 0; i
< mdl
->num_indices
/3; i
++ )
307 for( int j
= 0; j
< 3; j
++ )
309 v3_copy( &mdl
->vertices
[ mdl
->indices
[ i
*3+j
] *8 ], tri
[j
].co
);
310 v3_copy( &mdl
->vertices
[ mdl
->indices
[ i
*3+j
] *8+3 ], tri
[j
].nrm
);
315 csr_draw( rt
, tri
, 1, model
);
319 else if( ent
->user
& VMF_FLAG_IS_INSTANCE
)
321 m4x3_identity( model
);
322 vmf_entity_transform( ent
, model
);
324 draw_vmf_group( rt
, map
, map
->cache
[ ent
->user1
].root
, filter
, transform
, model
);
329 if( (ent_solid
= vdf_next( ent
, "solid", NULL
)) )
331 solidgen_push( &solid
, ent_solid
);
336 if( compute_bounds_only
)
338 solidgen_bounds( &solid
, trf_bounds
);
339 m4x3_transform_aabb( transform
, trf_bounds
);
340 box_concat( rt
->bounds
, trf_bounds
);
345 for( int i
= 0; i
< csr_sb_count( solid
.indices
)/3; i
++ )
347 u32
* base
= solid
.indices
+ i
*3;
349 tri
[0] = solid
.verts
[ base
[0] ];
350 tri
[1] = solid
.verts
[ base
[1] ];
351 tri
[2] = solid
.verts
[ base
[2] ];
353 csr_draw( rt
, tri
, 1, transform
);
357 solidgen_ctx_reset( &solid
);
358 solidgen_ctx_free( &solid
);
361 void csr_rt_save_buffers( csr_target
*rt
, const char *basename
, const char *subname
)
365 float *image
= (float *)csr_malloc( 1024*1024*sizeof(float)*3 );
367 for( int l
= 0; l
< rt
->x
; l
++ )
369 for( int x
= 0; x
< rt
->y
; x
++ )
371 float *dst
= &image
[ (l
*1024+x
)*3 ];
372 csr_frag
*src
= &rt
->fragments
[ ((1023-l
)*1024+x
)*rt
->num_samples
];
375 v3_muls( src
[0].co
, 1.f
/(float)rt
->num_samples
, dst
);
376 v3_muladds( dst
, src
[1].co
, 1.f
/(float)rt
->num_samples
, dst
);
377 v3_muladds( dst
, src
[2].co
, 1.f
/(float)rt
->num_samples
, dst
);
378 v3_muladds( dst
, src
[3].co
, 1.f
/(float)rt
->num_samples
, dst
);
382 // Save position buffer
383 strcpy( output
, basename
);
384 strcat( output
, "." );
385 strcat( output
, subname
);
386 strcat( output
, "_position.pfm" );
387 csr_32f_write( output
, rt
->x
, rt
->y
, image
);