height filtering
[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\n"
124 " -e <classname> Same as default arg, but instead filters for entity class\n"
125 //" -s <height> Add a vertical split at this height\n"
126 " --padding=128 When cropping radar, add padding units to border\n"
127 //" --standard-layers Use standard TAR layers/groups\n"
128 " --no-txt Don't create matching radar txt\n"
129 " --multi-sample=RGSS [ none, 2x, rgss, 8r ]\n"
130 " --extension=TAR Use an extension binary instead\n"
131 " --min=z Miniumum height to render\n"
132 " --max=z Maxiumum height to render\n"
133 "\n"
134 " -v --version Display program version\n"
135 " -h --help Display this help text\n"
136 );
137
138 goto IL_CSR_EXIT;
139 }
140 }
141
142 if( api.num_strings )
143 {
144 if( gameinfo )
145 {
146 fs_set_gameinfo( gameinfo );
147 }
148
149 // Path handling
150 if( !output_set )
151 {
152 strcpy( api.output_path, api.strings[0].str );
153 csr_stripext( api.output_path );
154 }
155
156 char *base_name;
157 if( !(base_name = csr_findext( api.output_path, '/' ) ))
158 {
159 base_name = api.output_path;
160 }
161
162 strcpy( api.vmf_name, base_name );
163
164 log_info( "output_path: '%s'\n", api.output_path );
165 log_info( "vmf_name: '%s'\n", api.vmf_name );
166
167 api.map = vmf_init( api.strings[0].str );
168 if( api.map )
169 {
170 // Update arg inferred types
171 api.strings[0].type = k_iftype_vmf;
172 for( int i = 1; i < api.num_strings; i ++ )
173 {
174 if( vmf_visgroup_id( api.map->root, api.strings[i].str ) != -1 )
175 api.strings[i].type = k_iftype_visgroup;
176 else
177 api.strings[i].type = k_iftype_classname;
178 }
179
180 if( !extension )
181 extension = "csr_substance";
182
183 csr_so ext = csr_libopen( extension );
184
185 if( ext )
186 {
187 void (*csr_ext_main)(csr_api *);
188 void (*csr_ext_exit)(csr_api *);
189
190 csr_ext_main = csr_get_proc( ext, "csr_ext_main" );
191 csr_ext_exit = csr_get_proc( ext, "csr_ext_exit" );
192
193 if( csr_ext_main && csr_ext_exit )
194 {
195 csr_ext_main( &api );
196
197 // Do other
198
199 csr_ext_exit( &api );
200 }
201 else
202 {
203 csr_liberr();
204 }
205
206 csr_libclose( ext );
207 }
208 else
209 {
210 csr_liberr();
211 }
212
213 vmf_free( api.map );
214 }
215 else
216 {
217 log_error( "Could not load VMF\n" );
218 }
219 }
220 else
221 {
222 log_error( "Missing required argument: mapfile\n" );
223 }
224
225 IL_CSR_EXIT:
226 fs_exit();
227 return 0;
228 }