radar txt
[csRadar.git] / csRadar.c
1 // Copyright (C) 2021 Harry Godden (hgn)
2
3 // Building:
4 // gcc -rdynamic csRadar.c -o csRadar -lm -ldl
5 //
6 // Plugins:
7 // gcc -fpic -shared -o ext/my_plugin.so my_plugin.c -lm
8
9 #define VALVE_IMPLEMENTATION
10 #define CSR_EXECUTABLE
11 #include "csRadar.h"
12
13 int main( int argc, char *argv[] )
14 {
15 csr_api api =
16 {
17 .padding = 128.f,
18 .resolution = 1024,
19 .min_z = -INFINITY,
20 .max_z = INFINITY,
21 .write_txt = 1,
22 .api_version = csr_api_version,
23 .sampling_mode = k_EMSAA_RGSS
24 };
25
26 int output_set = 0;
27 char *extension = NULL;
28 char *gameinfo = NULL;
29
30 char *arg;
31 while( csr_argp( argc, argv ) )
32 {
33 if( (arg = csr_arg()) )
34 {
35 if( api.num_strings == 20 )
36 {
37 log_error( "Too many arguments! Max 20\n" );
38 goto IL_CSR_EXIT;
39 }
40
41 api.strings[ api.num_strings ++ ].str = arg;
42 }
43
44 if( (arg = csr_opt_arg( 'o' )) )
45 {
46 strcpy( api.output_path, arg );
47 csr_path_winunix( api.output_path );
48
49 output_set = 1;
50 }
51
52 if( (arg = csr_opt_arg( 'g' )) )
53 {
54 gameinfo = arg;
55 }
56
57 if( (arg = csr_opt_arg( 'r' )) )
58 {
59 api.resolution = atoi( arg );
60 }
61
62 if( (arg = csr_long_opt_arg( "padding" )) )
63 {
64 api.padding = atof( arg );
65 }
66
67 if( (arg = csr_long_opt_arg( "multi-sample" )) )
68 {
69 if( !strcmp( arg, "none" ))
70 {
71 api.sampling_mode = k_EMSAA_none;
72 }
73 else if( !strcmp( arg, "rgss" ))
74 {
75 api.sampling_mode = k_EMSAA_RGSS;
76 }
77 else if( !strcmp( arg, "2x" ))
78 {
79 api.sampling_mode = k_EMSAA_2x2;
80 }
81 else if( !strcmp( arg, "8r" ))
82 {
83 api.sampling_mode = k_EMSAA_8R;
84 }
85 else
86 {
87 log_error( "Invalid sampling pattern '%s'\n", arg );
88 goto IL_CSR_EXIT;
89 }
90 }
91
92 if( (arg = csr_long_opt_arg( "extension" )) )
93 {
94 extension = arg;
95 }
96
97 if( (arg = csr_long_opt_arg( "min" )) )
98 api.min_z = atof( arg );
99 if( (arg = csr_long_opt_arg( "max" )) )
100 api.max_z = atof( arg );
101
102 if( csr_opt( 'v' ) || csr_long_opt( "version" ) )
103 {
104 printf( "csRadar build: %u, api_version: %u\n", csr_build, csr_api_version );
105 goto IL_CSR_EXIT;
106 }
107
108 if( csr_opt( 'h' ) || csr_long_opt( "help" ) )
109 {
110 // Display help
111 printf
112 (
113 "csRadar Copyright (C) 2021 Harry Godden (hgn)\n"
114 "\n"
115 "Usage: ./csRadar map.vmf -g \"/gamedir/gameinfo.txt\" layout cover\n"
116 " VMF file is first, then any other arguments (eg. layout, cover), will specify\n"
117 " visgroups to be rendered into individual files\n"
118 " No visgroups specified will simply draw everything\n"
119 "\n"
120 "Options:\n"
121 " -g <gameinfo.txt path> Required if you are loading models\n"
122 " -r 1024 Output resolution\n"
123 " -o <output> Specify output name/path (no extension, dir must exist)\n"
124 " -e <classname> Same as default arg, but instead filters for entity class\n"
125 " --padding=128 When cropping radar, add padding units to border\n"
126 " --no-txt Don't create matching radar txt\n"
127 " --multi-sample=rgss [ none, 2x, rgss, 8r ]\n"
128 " --extension=TAR Use an extension binary instead\n"
129 " --min=z Miniumum height to render\n"
130 " --max=z Maxiumum height to render\n"
131 "\n"
132 " -v --version Display program version\n"
133 " -h --help Display this help text\n"
134 );
135
136 goto IL_CSR_EXIT;
137 }
138 }
139
140 if( api.num_strings )
141 {
142 if( gameinfo )
143 {
144 fs_set_gameinfo( gameinfo );
145 }
146
147 // Path handling
148 if( !output_set )
149 {
150 strcpy( api.output_path, api.strings[0].str );
151 csr_stripext( api.output_path );
152 }
153
154 char *base_name;
155 if( !(base_name = csr_findext( api.output_path, '/' ) ))
156 {
157 base_name = api.output_path;
158 }
159
160 strcpy( api.vmf_name, base_name );
161
162 log_info( "output_path: '%s'\n", api.output_path );
163 log_info( "vmf_name: '%s'\n", api.vmf_name );
164
165 api.map = vmf_init( api.strings[0].str );
166 if( api.map )
167 {
168 // Update arg inferred types
169 api.strings[0].type = k_iftype_vmf;
170 for( int i = 1; i < api.num_strings; i ++ )
171 {
172 if( vmf_visgroup_id( api.map->root, api.strings[i].str ) != -1 )
173 api.strings[i].type = k_iftype_visgroup;
174 else
175 api.strings[i].type = k_iftype_classname;
176 }
177
178 if( !extension )
179 extension = "csr_substance";
180
181 csr_so ext = csr_libopen( extension );
182
183 if( ext )
184 {
185 void (*csr_ext_main)(csr_api *);
186 void (*csr_ext_exit)(csr_api *);
187
188 csr_ext_main = csr_get_proc( ext, "csr_ext_main" );
189 csr_ext_exit = csr_get_proc( ext, "csr_ext_exit" );
190
191 if( csr_ext_main && csr_ext_exit )
192 {
193 csr_ext_main( &api );
194
195 // Do other
196 if( api.write_txt )
197 {
198 char radar_path[512];
199 strcpy( radar_path, api.output_path );
200 strcat( radar_path, ".txt" );
201 csr_write_txt( radar_path, api.vmf_name, &api.target );
202 }
203
204 csr_ext_exit( &api );
205 }
206 else
207 {
208 csr_liberr();
209 }
210
211 csr_libclose( ext );
212 }
213 else
214 {
215 csr_liberr();
216 }
217
218 vmf_free( api.map );
219 }
220 else
221 {
222 log_error( "Could not load VMF\n" );
223 }
224 }
225 else
226 {
227 log_error( "Missing required argument: mapfile\n" );
228 }
229
230 IL_CSR_EXIT:
231 fs_exit();
232 return 0;
233 }