b05b6a6be3126ae06e7d385c4923f90bd7f99498
[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
8 // CSR lib
9 #include "csrOpt.h"
10 #include "csrTypes.h"
11 #include "csrMath.h"
12 #include "csrMem.h"
13 #include "csrIO.h"
14 #include "csrComb.h"
15
16 // Valve formats
17 #include "vdf.h"
18 #include "vpk.h"
19 #include "vfilesys.h"
20
21 #include "vmdl.h"
22 #include "vmf.h"
23
24 // CSR main
25 #include "csr32f.h"
26 #include "csrDraw.h"
27
28 #define CSR_VERSION "0.0.1"
29
30 // gcc -Wall -fsanitize=address csRadar.c -o csRadar -lm
31
32 int main( int argc, char *argv[] )
33 {
34 char *arg;
35 char *strings[ 20 ];
36 int num_strings = 0;
37
38 float padding = 128.f;
39 u32 resolution = 1024;
40 int standard_layers = 0;
41 int write_txt = 1;
42 int multi_sample = 1;
43 char output_path[ 512 ]; // Full path eg. /home/harry/my_map.vmf
44 char vmf_name[ 128 ]; // Just the base name eg. my_map
45 int output_set = 0;
46
47 while( csr_argp( argc, argv ) )
48 {
49 if( (arg = csr_arg()) )
50 {
51 if( num_strings == 20 )
52 {
53 fprintf( stderr, "Too many arguments! Max 20\n" );
54 fs_exit();
55 exit(0);
56 }
57
58 printf( "got: %s\n", arg );
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( csr_opt( 'v' ) || csr_long_opt( "version" ) )
87 {
88 printf( "csRadar version: " CSR_VERSION "\n" );
89 return 0;
90 }
91
92 if( csr_opt( 'h' ) || csr_long_opt( "help" ) )
93 {
94 // Display help
95 printf
96 (
97 "csRadar Copyright (C) 2021 Harry Godden (hgn)\n"
98 "\n"
99 "Usage: ./csRadar map.vmf -g \"/gamedir/gameinfo.txt\" layout cover\n"
100 " VMF file is first, then any other arguments (eg. layout, cover), will specify\n"
101 " visgroups to be rendered into individual files\n"
102 " No visgroups specified will simply draw everything\n"
103 "\n"
104 "Options:\n"
105 " -g <gameinfo.txt path> Required if you are loading models\n"
106 " -r 1024 Output resolution\n"
107 " -o <output> Specify output name/path\n"
108 " --padding=128 When cropping radar, add padding units to border\n"
109 " --standard-layers Use standard TAR layers/groups\n"
110 " --no-txt Don't create matching radar txt\n"
111 " --multi-sample= [ none, 2, 4, 4r, 8kn (default), 16c ]\n"
112 "\n"
113 " -v --version Display program version\n"
114 " -h --help Display this help text\n"
115 );
116
117 return 0;
118 }
119 }
120
121 if( num_strings )
122 {
123 vmf_map *map = vmf_init( strings[0], 1 );
124
125 if( map )
126 {
127 // Path handling
128 if( !output_set )
129 {
130 strcpy( output_path, strings[0] );
131 csr_stripext( output_path );
132 }
133
134 char *base_name;
135 if( !(base_name = csr_findext( output_path, '/' ) ))
136 {
137 base_name = output_path;
138 }
139
140 strcpy( vmf_name, base_name );
141
142 printf( "output_path: '%s'\nvmf_name: '%s'\n", output_path, vmf_name );
143
144
145 // Main
146
147 csr_target target;
148
149 csr_create_target( &target, resolution, resolution );
150 csr_rt_clear( &target );
151
152 // Compute bounds
153 csr_filter filter =
154 {
155 .classname = NULL,
156 .visgroup = NULL,
157 .compute_bounds_only = 1
158 };
159
160 // One pass for fitting, second pass for drawing
161 for( int i = 0; i < 2; i ++ )
162 {
163 if( num_strings == 1 )
164 {
165 // Draw everything
166 draw_vmf_group( &target, map, map->root, &filter, NULL, NULL );
167 csr_rt_save_buffers( &target, output_path, "all" );
168 }
169 else
170 {
171 // Draw groups
172 for( int i = 1; i < num_strings; i ++ )
173 {
174 filter.visgroup = strings[ i ];
175
176 draw_vmf_group( &target, map, map->root, &filter, NULL, NULL );
177 csr_rt_save_buffers( &target, output_path, strings[i] );
178
179 csr_rt_clear( &target );
180 }
181 }
182
183 filter.compute_bounds_only = 0;
184 csr_auto_fit( &target, padding );
185 }
186
187 if( write_txt )
188 {
189 char txt_path[ 512 ];
190
191 strcpy( txt_path, output_path );
192 strcat( txt_path, ".txt" );
193
194 csr_write_txt( txt_path, vmf_name, &target );
195 }
196
197 csr_rt_free( &target );
198 vmf_free( map );
199 }
200 else
201 {
202 fprintf( stderr, "Could not load VMF\n" );
203 }
204 }
205 else
206 {
207 fprintf( stderr, "Missing required argument: mapfile\n" );
208 }
209
210 fs_exit();
211
212 return 0;
213 }