e68237c5f46edf4d3220f2c8dac68506c01c2852
[csRadar.git] / csRadar.c
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <math.h>
6 #include <time.h>
7 #include <stdarg.h>
8
9 // CSR lib
10 #include "csrLog.h"
11 #include "csrOpt.h"
12 #include "csrTypes.h"
13 #include "csrMath.h"
14 #include "csrMem.h"
15 #include "csrIO.h"
16 #include "csrComb.h"
17
18 // Valve formats
19 #include "vdf.h"
20 #include "vpk.h"
21 #include "vfilesys.h"
22
23 #include "vmdl.h"
24 #include "vmf.h"
25
26 // CSR main
27 #include "csr32f.h"
28 #include "csrDraw.h"
29
30 #define CSR_VERSION "0.0.1"
31
32 // gcc -Wall -fsanitize=address csRadar.c -o csRadar -lm
33
34 int main( int argc, char *argv[] )
35 {
36 char *arg;
37 char *strings[ 20 ];
38 int num_strings = 0;
39
40 float padding = 128.f;
41 u32 resolution = 1024;
42 int standard_layers = 0;
43 int write_txt = 1;
44 int multi_sample = 1;
45 char output_path[ 512 ]; // Full path eg. /home/harry/my_map.vmf
46 char vmf_name[ 128 ]; // Just the base name eg. my_map
47 int output_set = 0;
48 EMSAA sampling_mode = k_EMSAA_RGSS;
49
50 while( csr_argp( argc, argv ) )
51 {
52 if( (arg = csr_arg()) )
53 {
54 if( num_strings == 20 )
55 {
56 log_error( "Too many arguments! Max 20\n" );
57 goto IL_CSR_EXIT;
58 }
59
60 strings[ num_strings ++ ] = arg;
61 }
62
63 if( (arg = csr_opt_arg( 'o' )) )
64 {
65 strcpy( output_path, arg );
66 csr_path_winunix( output_path );
67
68 output_set = 1;
69 }
70
71 if( (arg = csr_opt_arg( 'g' )) )
72 {
73 fs_set_gameinfo( arg );
74 }
75
76 if( (arg = csr_opt_arg( 'r' )) )
77 {
78 resolution = atoi( arg );
79 }
80
81 if( (arg = csr_long_opt_arg( "padding" )) )
82 {
83 padding = atof( arg );
84 }
85
86 if( (arg = csr_long_opt_arg( "multi-sample" )) )
87 {
88 if( !strcmp( arg, "none" ))
89 {
90 sampling_mode = k_EMSAA_none;
91 }
92 else if( !strcmp( arg, "rgss" ))
93 {
94 sampling_mode = k_EMSAA_RGSS;
95 }
96 else if( !strcmp( arg, "2x" ))
97 {
98 sampling_mode = k_EMSAA_2x2;
99 }
100 else if( !strcmp( arg, "8r" ))
101 {
102 sampling_mode = k_EMSAA_8R;
103 }
104 else
105 {
106 log_error( "Invalid sampling pattern '%s'\n", arg );
107 goto IL_CSR_EXIT;
108 }
109 }
110
111 if( csr_opt( 'v' ) || csr_long_opt( "version" ) )
112 {
113 printf( "csRadar version: " CSR_VERSION "\n" );
114 goto IL_CSR_EXIT;
115 }
116
117 if( csr_opt( 'h' ) || csr_long_opt( "help" ) )
118 {
119 // Display help
120 printf
121 (
122 "csRadar Copyright (C) 2021 Harry Godden (hgn)\n"
123 "\n"
124 "Usage: ./csRadar map.vmf -g \"/gamedir/gameinfo.txt\" layout cover\n"
125 " VMF file is first, then any other arguments (eg. layout, cover), will specify\n"
126 " visgroups to be rendered into individual files\n"
127 " No visgroups specified will simply draw everything\n"
128 "\n"
129 "Options:\n"
130 " -g <gameinfo.txt path> Required if you are loading models\n"
131 " -r 1024 Output resolution\n"
132 " -o <output> Specify output name/path\n"
133 " --padding=128 When cropping radar, add padding units to border\n"
134 //" --standard-layers Use standard TAR layers/groups\n"
135 " --no-txt Don't create matching radar txt\n"
136 " --multi-sample=RGSS [ none, 2x, rgss, 8r ]\n"
137 " --extension=TAR Use an extension binary instead\n"
138 "\n"
139 " -v --version Display program version\n"
140 " -h --help Display this help text\n"
141 );
142
143 goto IL_CSR_EXIT;
144 }
145 }
146
147 if( num_strings )
148 {
149 vmf_map *map = vmf_init( strings[0] );
150
151 if( map )
152 {
153 // Path handling
154 if( !output_set )
155 {
156 strcpy( output_path, strings[0] );
157 csr_stripext( output_path );
158 }
159
160 char *base_name;
161 if( !(base_name = csr_findext( output_path, '/' ) ))
162 {
163 base_name = output_path;
164 }
165
166 strcpy( vmf_name, base_name );
167
168 log_info( "output_path: '%s'\n", output_path );
169 log_info( "vmf_name: '%s'\n", vmf_name );
170
171 // Main
172 csr_target target;
173
174 csr_create_target( &target, resolution, resolution, sampling_mode );
175 csr_rt_clear( &target );
176
177 csr_use_program( &target, frag_gbuffer );
178
179 // Compute bounds
180 csr_filter filter =
181 {
182 .classname = NULL,
183 .visgroup = NULL,
184 .compute_bounds_only = 1
185 };
186
187 // One pass for fitting, second pass for drawing
188 for( int i = 0; i < 2; i ++ )
189 {
190 if( num_strings == 1 )
191 {
192 // Draw everything
193 draw_vmf_group( &target, map, map->root, &filter, NULL, NULL );
194 csr_rt_save_buffers( &target, output_path, "all" );
195 }
196 else
197 {
198 // Draw groups
199 for( int i = 1; i < num_strings; i ++ )
200 {
201 filter.visgroup = strings[ i ];
202
203 draw_vmf_group( &target, map, map->root, &filter, NULL, NULL );
204 csr_rt_save_buffers( &target, output_path, strings[i] );
205
206 csr_rt_clear( &target );
207 }
208 }
209
210 if( i == 0 )
211 {
212 filter.compute_bounds_only = 0;
213 csr_auto_fit( &target, padding );
214 vmf_load_models( map );
215 }
216 }
217
218 if( write_txt )
219 {
220 char txt_path[ 512 ];
221
222 strcpy( txt_path, output_path );
223 strcat( txt_path, ".txt" );
224
225 csr_write_txt( txt_path, vmf_name, &target );
226 }
227
228 csr_rt_free( &target );
229 vmf_free( map );
230 }
231 else
232 {
233 log_error( "Could not load VMF\n" );
234 }
235 }
236 else
237 {
238 log_error( "Missing required argument: mapfile\n" );
239 }
240
241 IL_CSR_EXIT:
242 fs_exit();
243 return 0;
244 }