1 typedef struct csr_frag csr_frag
;
2 typedef struct csr_target csr_target
;
3 typedef struct csr_filter csr_filter
;
7 u32 id
; // Triangle index
8 float depth
; // 'depth testing'
23 const char *visgroup
; // Limit to this visgroup only
24 const char *classname
; // Limit to this exact classname. will not draw world
27 void csr_create_target( csr_target
*rt
, u32 x
, u32 y
, v4f bounds
)
31 rt
->fragments
= (csr_frag
*)csr_malloc( x
*y
*sizeof(csr_frag
) );
32 v4_copy( bounds
, rt
->bounds
);
35 void csr_rt_free( csr_target
*rt
)
37 free( rt
->fragments
);
40 void csr_rt_clear( csr_target
*rt
)
42 for( u32 i
= 0; i
< rt
->x
*rt
->y
; i
++ )
44 rt
->fragments
[ i
].depth
= 0.f
;
48 void simple_raster( csr_target
*rt
, vmf_vert tri
[3], int id
)
50 // Very simplified tracing algorithm
51 float tqa
= 0.f
, tqb
= 0.f
;
53 v2f bmin
= { 0.f
, 0.f
};
54 v2f bmax
= { rt
->x
, rt
->y
};
56 v2_minv( tri
[0].co
, tri
[1].co
, bmin
);
57 v2_minv( tri
[2].co
, bmin
, bmin
);
59 v2_maxv( tri
[0].co
, tri
[1].co
, bmax
);
60 v2_maxv( tri
[2].co
, bmax
, bmax
);
62 float range_x
= (rt
->bounds
[2]-rt
->bounds
[0])/(float)rt
->x
;
63 float range_y
= (rt
->bounds
[3]-rt
->bounds
[1])/(float)rt
->y
;
65 int start_x
= csr_min( rt
->x
-1, csr_max( 0, floorf( (bmin
[0]-rt
->bounds
[0])/range_x
)));
66 int end_x
= csr_max( 0, csr_min( rt
->x
-1, floorf( (bmax
[0]-rt
->bounds
[0])/range_x
)));
67 int start_y
= csr_min( rt
->y
-1, csr_max( 0, ceilf( (bmin
[1]-rt
->bounds
[1])/range_y
)));
68 int end_y
= csr_max( 0, csr_min( rt
->y
-1, ceilf( (bmax
[1]-rt
->bounds
[1])/range_y
)));
70 v3f trace_dir
= { 0.f
, 0.f
, 1.f
};
71 v3f trace_origin
= { 0.f
, 0.f
, -16385.f
};
73 for( u32 py
= start_y
; py
<= end_y
; py
++ )
75 trace_origin
[1] = csr_lerpf( rt
->bounds
[1], rt
->bounds
[3], (float)py
/(float)rt
->y
);
77 for( u32 px
= start_x
; px
<= end_x
; px
++ )
79 csr_frag
*frag
= &rt
->fragments
[ py
* rt
->y
+ px
];
81 trace_origin
[0] = csr_lerpf( rt
->bounds
[0], rt
->bounds
[2], (float)px
/(float)rt
->x
);
82 float tdepth
= csr_ray_tri( trace_origin
, trace_dir
, tri
[0].co
, tri
[1].co
, tri
[2].co
, &tqa
, &tqb
);
84 if( tdepth
> frag
->depth
)
88 v3_muls( tri
[1].co
, tqa
, frag
->co
);
89 v3_muladds( frag
->co
, tri
[2].co
, tqb
, frag
->co
);
90 v3_muladds( frag
->co
, tri
[0].co
, 1.f
- tqa
- tqb
, frag
->co
);
96 void csr_draw( csr_target
*rt
, vmf_vert
*triangles
, u32 triangle_count
, m4x3f transform
)
101 // Derive normal matrix
102 m4x3_to_3x3( transform
, normal
);
103 m3x3_inv_transpose( normal
, normal
);
105 for( u32 i
= 0; i
< triangle_count
; i
++ )
107 vmf_vert
*triangle
= triangles
+ i
*3;
109 m4x3_mulv( transform
, triangle
[0].co
, new_tri
[0].co
);
110 m4x3_mulv( transform
, triangle
[1].co
, new_tri
[1].co
);
111 m4x3_mulv( transform
, triangle
[2].co
, new_tri
[2].co
);
112 m3x3_mulv( normal
, triangle
[0].nrm
, new_tri
[0].nrm
);
113 m3x3_mulv( normal
, triangle
[1].nrm
, new_tri
[1].nrm
);
114 m3x3_mulv( normal
, triangle
[2].nrm
, new_tri
[2].nrm
);
116 simple_raster( rt
, new_tri
, 0 );
120 void draw_vmf_group( csr_target
*rt
, vmf_map
*map
, vdf_node
*root
, csr_filter
*filter
, m4x3f prev
, m4x3f inst
)
122 m4x3f transform
= M4X3_IDENTITY
;
128 int filter_visgroups
= 0, filter_classname
= 0;
132 if( filter
->visgroup
)
134 filter_visgroups
= 1;
135 group_id
= vmf_visgroup_id( root
, filter
->visgroup
);
138 if( filter
->classname
)
140 filter_classname
= 1;
144 // Multiply previous transform with instance transform to create basis
147 m4x3_mul( prev
, inst
, transform
);
150 // Gather world brushes
151 solidgen_ctx_init( &solid
);
153 if( !filter_classname
)
155 vdf_node
*world
= vdf_next( root
, "world", NULL
);
157 vdf_foreach( world
, "solid", brush
)
159 if( filter_visgroups
&& !vmf_visgroup_match( brush
, group_id
) )
162 solidgen_push( &solid
, brush
);
166 // Actual entity loop
169 vdf_foreach( root
, "entity", ent
)
171 if( filter_visgroups
&& !vmf_visgroup_match( ent
, group_id
) )
174 if( filter_classname
)
175 if( strcmp( kv_get( ent
, "classname", "" ), filter
->classname
) )
178 if( ent
->user
& VMF_FLAG_IS_PROP
)
180 // Create model transform
181 m4x3_identity( model
);
183 vmf_entity_transform( ent
, model
);
184 m4x3_mul( transform
, model
, model
);
187 mdl_mesh_t
*mdl
= &map
->models
[ ent
->user1
].mdl
;
188 for( int i
= 0; i
< mdl
->num_indices
/3; i
++ )
190 for( int j
= 0; j
< 3; j
++ )
192 v3_copy( &mdl
->vertices
[ mdl
->indices
[ i
*3+j
] *8 ], tri
[j
].co
);
193 v3_copy( &mdl
->vertices
[ mdl
->indices
[ i
*3+j
] *8+3 ], tri
[j
].nrm
);
198 csr_draw( rt
, tri
, 1, model
);
201 else if( ent
->user
& VMF_FLAG_IS_INSTANCE
)
203 m4x3_identity( model
);
204 vmf_entity_transform( ent
, model
);
206 draw_vmf_group( rt
, map
, map
->cache
[ ent
->user1
].root
, filter
, transform
, model
);
211 if( (ent_solid
= vdf_next( ent
, "solid", NULL
)) )
213 solidgen_push( &solid
, ent_solid
);
219 for( int i
= 0; i
< csr_sb_count( solid
.indices
)/3; i
++ )
221 u32
* base
= solid
.indices
+ i
*3;
223 tri
[0] = solid
.verts
[ base
[0] ];
224 tri
[1] = solid
.verts
[ base
[1] ];
225 tri
[2] = solid
.verts
[ base
[2] ];
227 csr_draw( rt
, tri
, 1, transform
);
230 solidgen_ctx_reset( &solid
);
231 solidgen_ctx_free( &solid
);