1 /*
2 idstuff.c
3
4 qcc compatable output stuff
5
6 Copyright (C) 2002 Bill Currie <bill@taniwha.org>
7 Copyright (C) 1996-1997 Id Software, Inc.
8
9 Author: Bill Currie <bill@taniwha.org>
10 Date: 2002/06/04
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
21 See the GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to:
25
26 Free Software Foundation, Inc.
27 59 Temple Place - Suite 330
28 Boston, MA 02111-1307, USA
29
30 */
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41
42 #include <QF/crc.h>
43 #include <QF/dstring.h>
44 #include <QF/quakeio.h>
45
46 #include "def.h"
47 #include "defspace.h"
48 #include "diagnostic.h"
49 #include "qfcc.h"
50 #include "expr.h"
51 #include "idstuff.h"
52 #include "options.h"
53 #include "strpool.h"
54 #include "symtab.h"
55 #include "type.h"
56
57 #define MAX_SOUNDS 1024
58 #define MAX_MODELS 1024
59 #define MAX_FILES 1024
60 #define MAX_DATA_PATH 64
61
62 static char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
63 static int precache_sounds_block[MAX_SOUNDS];
64 static int numsounds;
65
66 static char precache_models[MAX_MODELS][MAX_DATA_PATH];
67 static int precache_models_block[MAX_SOUNDS];
68 static int nummodels;
69
70 static char precache_files[MAX_FILES][MAX_DATA_PATH];
71 static int precache_files_block[MAX_SOUNDS];
72 static int numfiles;
73
74 void
PrecacheSound(const char * n,int ch)75 PrecacheSound (const char *n, int ch)
76 {
77 int i;
78
79 for (i = 0; i < numsounds; i++) {
80 if (!strcmp (n, precache_sounds[i])) {
81 return;
82 }
83 }
84
85 if (numsounds == MAX_SOUNDS) {
86 error (0, "PrecacheSound: numsounds == MAX_SOUNDS");
87 return;
88 }
89
90 strcpy (precache_sounds[i], n);
91 if (ch >= '1' && ch <= '9')
92 precache_sounds_block[i] = ch - '0';
93 else
94 precache_sounds_block[i] = 1;
95
96 numsounds++;
97 }
98
99 void
PrecacheModel(const char * n,int ch)100 PrecacheModel (const char *n, int ch)
101 {
102 int i;
103
104 for (i = 0; i < nummodels; i++) {
105 if (!strcmp (n, precache_models[i])) {
106 return;
107 }
108 }
109
110 if (nummodels == MAX_MODELS) {
111 error (0, "PrecacheModels: nummodels == MAX_MODELS");
112 return;
113 }
114
115 strcpy (precache_models[i], n);
116 if (ch >= '1' && ch <= '9')
117 precache_models_block[i] = ch - '0';
118 else
119 precache_models_block[i] = 1;
120
121 nummodels++;
122 }
123
124 void
PrecacheFile(const char * n,int ch)125 PrecacheFile (const char *n, int ch)
126 {
127 int i;
128
129 for (i = 0; i < numfiles; i++) {
130 if (!strcmp (n, precache_files[i])) {
131 return;
132 }
133 }
134
135 if (numfiles == MAX_FILES) {
136 error (0, "PrecacheFile: numfiles == MAX_FILES");
137 return;
138 }
139
140 strcpy (precache_files[i], n);
141 if (ch >= '1' && ch <= '9')
142 precache_files_block[i] = ch - '0';
143 else
144 precache_files_block[i] = 1;
145
146 numfiles++;
147 }
148
149 /*
150 WriteFiles
151
152 Generates files.dat, which contains all of the data files actually used by
153 the game, to be processed by qfiles
154 */
155 int
WriteFiles(const char * sourcedir)156 WriteFiles (const char *sourcedir)
157 {
158 FILE *f;
159 int i;
160 dstring_t *filename = dstring_newstr ();
161
162 dsprintf (filename, "%s%cfiles.dat", sourcedir, PATH_SEPARATOR);
163 f = fopen (filename->str, "wb");
164 if (!f) {
165 fprintf (stderr, "Couldn't open %s", filename->str);
166 return 1;
167 }
168
169 fprintf (f, "%i\n", numsounds);
170 for (i = 0; i < numsounds; i++)
171 fprintf (f, "%i %s\n", precache_sounds_block[i], precache_sounds[i]);
172
173 fprintf (f, "%i\n", nummodels);
174 for (i = 0; i < nummodels; i++)
175 fprintf (f, "%i %s\n", precache_models_block[i], precache_models[i]);
176
177 fprintf (f, "%i\n", numfiles);
178 for (i = 0; i < numfiles; i++)
179 fprintf (f, "%i %s\n", precache_files_block[i], precache_files[i]);
180
181 fclose (f);
182 dstring_delete (filename);
183 return 0;
184 }
185
186 /*
187 WriteProgdefs
188
189 Writes the global and entity structures out.
190 Returns a crc of the header, to be stored in the progs file for comparison
191 at load time.
192 */
193 int
WriteProgdefs(dprograms_t * progs,const char * filename)194 WriteProgdefs (dprograms_t *progs, const char *filename)
195 {
196 ddef_t *def;
197 ddef_t *fdef;
198 dstring_t *dstr;
199 QFile *f;
200 unsigned short crc;
201 unsigned i, j;
202 const char *strings;
203 const char *name;
204
205 if (options.verbosity >= 1)
206 printf ("Calculating CRC\n");
207
208 dstr = dstring_newstr();
209
210 // print global vars until the first field is defined
211 dasprintf (dstr, "\n/* file generated by qcc, do not modify */"
212 "\n\ntypedef struct\n{\tint\tpad[%i];\n",
213 RESERVED_OFS);
214
215 strings = (char *) progs + progs->ofs_strings;
216 for (i = 0; i < progs->numglobaldefs; i++) {
217 def = (ddef_t *) ((char *) progs + progs->ofs_globaldefs) + i;
218 name = strings + def->s_name;
219 if (!strcmp (name, "end_sys_globals"))
220 break;
221 if (!def->ofs)
222 continue;
223 if (*name == '.' || !*name)
224 continue;
225
226 switch (def->type & ~DEF_SAVEGLOBAL) {
227 case ev_float:
228 dasprintf (dstr, "\tfloat\t%s;\n", name);
229 break;
230 case ev_vector:
231 dasprintf (dstr, "\tvec3_t\t%s;\n", name);
232 break;
233 case ev_quat:
234 dasprintf (dstr, "\tquat_t\t%s;\n", name);
235 break;
236 case ev_string:
237 dasprintf (dstr, "\tstring_t\t%s;\n", name);
238 break;
239 case ev_func:
240 dasprintf (dstr, "\tfunc_t\t%s;\n", name);
241 break;
242 case ev_entity:
243 dasprintf (dstr, "\tint\t%s;\n", name);
244 break;
245 default:
246 dasprintf (dstr, "\tint\t%s;\n", name);
247 break;
248 }
249 }
250 dasprintf (dstr, "} globalvars_t;\n\n");
251
252 // print all fields
253 dasprintf (dstr, "typedef struct\n{\n");
254 for (i = 0, j = 0; i < progs->numglobaldefs; i++) {
255 def = (ddef_t *) ((char *) progs + progs->ofs_globaldefs) + i;
256 name = strings + def->s_name;
257 if (!strcmp (name, "end_sys_fields"))
258 break;
259
260 if (!def->ofs)
261 continue;
262 if (def->type != ev_field)
263 continue;
264 if (!strcmp (name, ".imm"))
265 continue;
266
267 fdef = (ddef_t *) ((char *) progs + progs->ofs_fielddefs) + j++;
268 if (fdef->s_name != def->s_name)
269 internal_error (0, "def and field order messup");
270
271 switch (fdef->type) {
272 case ev_float:
273 dasprintf (dstr, "\tfloat\t%s;\n", name);
274 break;
275 case ev_vector:
276 dasprintf (dstr, "\tvec3_t\t%s;\n", name);
277 break;
278 case ev_string:
279 dasprintf (dstr, "\tstring_t\t%s;\n", name);
280 break;
281 case ev_func:
282 dasprintf (dstr, "\tfunc_t\t%s;\n", name);
283 break;
284 case ev_entity:
285 dasprintf (dstr, "\tint\t%s;\n", name);
286 break;
287 default:
288 dasprintf (dstr, "\tint\t%s;\n", name);
289 break;
290 }
291 }
292 dasprintf (dstr, "} entvars_t;\n\n");
293
294 // do a crc of the structs
295 crc = CRC_Block ((byte *) dstr->str, dstr->size - 1);
296
297 dasprintf (dstr, "#define PROGHEADER_CRC %u\n", crc);
298 dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, be one must "
299 "maintain formalities */");
300
301 if (filename) {
302 if (options.verbosity >= 1)
303 printf ("writing %s\n", filename);
304 f = Qopen (filename, "wt");
305 Qwrite (f, dstr->str, dstr->size - 1);
306 Qclose (f);
307 }
308
309 return crc;
310 }
311