1 /*
2 	Copyright (C) 1996-1997  Id Software, Inc.
3 
4 	This program is free software; you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation; either version 2 of the License, or
7 	(at your option) any later version.
8 
9 	This program is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with this program; if not, write to the Free Software
16 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 	See file, 'COPYING', for details.
19 */
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #ifdef HAVE_STRING_H
25 # include <string.h>
26 #endif
27 #ifdef HAVE_STRINGS_H
28 # include <strings.h>
29 #endif
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <ctype.h>
33 
34 #include "QF/dstring.h"
35 #include "QF/hash.h"
36 #include "QF/quakefs.h"
37 #include "QF/script.h"
38 #include "QF/sys.h"
39 #include "QF/va.h"
40 
41 #include "compat.h"
42 
43 #include "map.h"
44 
45 /**	\addtogroup qfbsp_map
46 */
47 //@{
48 
49 int         nummapbrushfaces;
50 int         nummapbrushes;
51 
52 #define ENTITIES_CHUNK 16
53 int         num_entities;
54 int         max_entities;
55 entity_t   *entities;
56 
57 #define MIPTEXNAME_CHUNK 16
58 int         nummiptexnames;
59 int         maxmiptexnames;
60 const char **miptexnames;
61 hashtab_t  *miptex_hash;
62 
63 int         numdetailbrushes;
64 
65 script_t   *map_script;
66 
67 static void __attribute__ ((format (printf, 1, 2), noreturn))
map_error(const char * fmt,...)68 map_error (const char *fmt, ...)
69 {
70 	va_list     args;
71 
72 	va_start (args, fmt);
73 	fprintf (stderr, "%s:%d: ", map_script->file, map_script->line);
74 	vfprintf (stderr, fmt, args);
75 	fprintf (stderr, "\n");
76 	va_end (args);
77 	exit (1);
78 }
79 
80 static const char *
miptex_getkey(const void * key,void * unused)81 miptex_getkey (const void *key, void *unused)
82 {
83 	intptr_t    index = (intptr_t) key;
84 	return miptexnames[index - 1];
85 }
86 
87 int
FindMiptex(const char * name)88 FindMiptex (const char *name)
89 {
90 	intptr_t    index;
91 	char        mpname[MIPTEXNAME];
92 
93 	strncpy (mpname, name, MIPTEXNAME - 1);
94 	mpname[MIPTEXNAME - 1] = 0;
95 	if (strcmp (name, "hint") == 0)
96 		return TEX_HINT;
97 	if (strcmp (name, "skip") == 0)
98 		return TEX_SKIP;
99 	if (!miptex_hash)
100 		miptex_hash = Hash_NewTable (1023, miptex_getkey, 0, 0);
101 	if (miptexnames) {
102 		index = (intptr_t) Hash_Find (miptex_hash, mpname);
103 		if (index)
104 			return index - 1;
105 	}
106 	if (nummiptexnames == maxmiptexnames) {
107 		maxmiptexnames += MIPTEXNAME_CHUNK;
108 		miptexnames = realloc (miptexnames,
109 							   maxmiptexnames * sizeof (const char *));
110 	}
111 	index = nummiptexnames++;
112 	miptexnames[index] = strdup (mpname);
113 	Hash_Add (miptex_hash, (void *) (index + 1));
114 	return index;
115 }
116 
117 /*
118 	FindTexinfo
119 
120 	Returns a global texinfo number
121 */
122 static int
FindTexinfo(texinfo_t * t)123 FindTexinfo (texinfo_t *t)
124 {
125 	int         i, j;
126 	texinfo_t  *tex;
127 
128 	if (t->miptex < 0)
129 		return t->miptex;		// it's HINT or SKIP
130 
131 	// set the special flag
132 	if (miptexnames[t->miptex][0] == '*'
133 		|| !strncasecmp (miptexnames[t->miptex], "sky", 3))
134 		t->flags |= TEX_SPECIAL;
135 
136 	tex = bsp->texinfo;
137 	for (i = 0; i < bsp->numtexinfo; i++, tex++) {
138 		if (t->miptex != tex->miptex)
139 			continue;
140 		if (t->flags != tex->flags)
141 			continue;
142 
143 		for (j = 0; j < 8; j++)
144 			if (t->vecs[j / 4][j % 4] != tex->vecs[j / 4][j % 4])
145 				break;
146 		if (j != 8)
147 			continue;
148 
149 		return i;
150 	}
151 
152 	// allocate a new texture
153 	BSP_AddTexinfo (bsp, t);
154 
155 	return i;
156 }
157 
158 entity_t   *mapent;
159 
160 static void
ParseEpair(void)161 ParseEpair (void)
162 {
163 	epair_t    *e;
164 
165 	e = malloc (sizeof (epair_t));
166 	memset (e, 0, sizeof (epair_t));
167 	e->next = mapent->epairs;
168 	mapent->epairs = e;
169 
170 	e->key = strdup (map_script->token->str);
171 	Script_GetToken (map_script, false);
172 	e->value = strdup (map_script->token->str);
173 }
174 
175 vec3_t      baseaxis[18] = {
176 	{0, 0, 1}, {1, 0, 0}, {0, -1, 0},	// floor
177 	{0, 0, -1}, {1, 0, 0}, {0, -1, 0},	// ceiling
178 	{1, 0, 0}, {0, 1, 0}, {0, 0, -1},	// west wall
179 	{-1, 0, 0}, {0, 1, 0}, {0, 0, -1},	// east wall
180 	{0, 1, 0}, {1, 0, 0}, {0, 0, -1},	// south wall
181 	{0, -1, 0}, {1, 0, 0}, {0, 0, -1}	// north wall
182 };
183 
184 static void
TextureAxisFromPlane(plane_t * pln,vec3_t xv,vec3_t yv)185 TextureAxisFromPlane (plane_t *pln, vec3_t xv, vec3_t yv)
186 {
187 	float       dot, best;
188 	int         bestaxis, i;
189 
190 	best = 0;
191 	bestaxis = 0;
192 
193 	for (i = 0; i < 6; i++) {
194 		dot = DotProduct (pln->normal, baseaxis[i * 3]);
195 		if (dot > best) {
196 			best = dot;
197 			bestaxis = i;
198 		}
199 	}
200 
201 	VectorCopy (baseaxis[bestaxis * 3 + 1], xv);
202 	VectorCopy (baseaxis[bestaxis * 3 + 2], yv);
203 }
204 
205 static vec3_t *
ParseVerts(int * n_verts)206 ParseVerts (int *n_verts)
207 {
208 	vec3_t     *verts;
209 	int         i;
210 	const char *token;
211 
212 	token = Script_Token (map_script);
213 	if (token[0] != ':')
214 		map_error ("parsing brush");
215 	// It's normally ":count", but somebody might have done ": count"
216 	if (!token[1]) {
217 		Script_GetToken (map_script, false);
218 		token = Script_Token (map_script);
219 	} else {
220 		token++;
221 	}
222 	*n_verts = atoi (token);
223 	verts = malloc (sizeof (vec3_t) * *n_verts);
224 
225 	for (i = 0; i < *n_verts; i++) {
226 		Script_GetToken (map_script, true);
227 		verts[i][0] = atof (map_script->token->str);
228 		Script_GetToken (map_script, true);
229 		verts[i][1] = atof (map_script->token->str);
230 		Script_GetToken (map_script, true);
231 		verts[i][2] = atof (map_script->token->str);
232 	}
233 
234 	return verts;
235 }
236 
237 static void
ParseBrush(void)238 ParseBrush (void)
239 {
240 	float       rotate, scale[2];
241 	float       ang, sinv, cosv, ns, nt;
242 	int         sv, tv;
243 	int         i, j, n_verts = 0, hltexdef;
244 	mbrush_t   *b;
245 	mface_t    *f, *f2;
246 	plane_t     plane;
247 	texinfo_t   tx;
248 	vec3_t      planepts[3];
249 	vec3_t      t1, t2, *verts = 0;
250 	vec_t       d, vecs[2][4];
251 
252 	nummapbrushes++;
253 	b = calloc (1, sizeof (mbrush_t));
254 	b->next = mapent->brushes;
255 	mapent->brushes = b;
256 
257 	Script_GetToken (map_script, true);
258 	if (strcmp (map_script->token->str, "(") != 0) {
259 		verts = ParseVerts (&n_verts);
260 	} else {
261 		Script_UngetToken (map_script);
262 	}
263 
264 	do {
265 		if (!Script_GetToken (map_script, true))
266 			break;
267 		if (!strcmp (map_script->token->str, "}"))
268 			break;
269 
270 		if (verts) {
271 			int         n_v, v;
272 			n_v = atoi (map_script->token->str);
273 			Script_GetToken (map_script, false);
274 			for (i = 0; i < n_v; i++) {
275 				Script_GetToken (map_script, false);
276 				v = atof (map_script->token->str);
277 				if (i < 3)
278 					VectorCopy (verts[v], planepts[i]);
279 			}
280 			Script_GetToken (map_script, false);
281 		} else {
282 			// read the three point plane definition
283 			for (i = 0; i < 3; i++) {
284 				if (i != 0)
285 					Script_GetToken (map_script, true);
286 				if (strcmp (map_script->token->str, "("))
287 					map_error ("parsing brush");
288 
289 				for (j = 0; j < 3; j++) {
290 					Script_GetToken (map_script, false);
291 					planepts[i][j] = atof (map_script->token->str);
292 				}
293 
294 				Script_GetToken (map_script, false);
295 				if (strcmp (map_script->token->str, ")"))
296 					map_error ("parsing brush");
297 			}
298 		}
299 
300 		// convert points to a plane
301 		VectorSubtract (planepts[0], planepts[1], t1);
302 		VectorSubtract (planepts[2], planepts[1], t2);
303 		CrossProduct(t1, t2, plane.normal);
304 		VectorNormalize (plane.normal);
305 		plane.dist = DotProduct(planepts[1], plane.normal);
306 
307 		// read the texturedef
308 		memset (&tx, 0, sizeof (tx));
309 		Script_GetToken (map_script, false);
310 		tx.miptex = FindMiptex (map_script->token->str);
311 		Script_GetToken (map_script, false);
312 		if ((hltexdef = !strcmp (map_script->token->str, "["))) {
313 			// S vector
314 			Script_GetToken (map_script, false);
315 			vecs[0][0] = atof (map_script->token->str);
316 			Script_GetToken (map_script, false);
317 			vecs[0][1] = atof (map_script->token->str);
318 			Script_GetToken (map_script, false);
319 			vecs[0][2] = atof (map_script->token->str);
320 			Script_GetToken (map_script, false);
321 			vecs[0][3] = atof (map_script->token->str);
322 			Script_GetToken (map_script, false);
323 			if (strcmp (map_script->token->str, "]"))
324 				map_error ("missing ]");
325 			Script_GetToken (map_script, false);
326 			if (strcmp (map_script->token->str, "["))
327 				map_error ("missing [");
328 			// T vector
329 			Script_GetToken (map_script, false);
330 			vecs[1][0] = atof (map_script->token->str);
331 			Script_GetToken (map_script, false);
332 			vecs[1][1] = atof (map_script->token->str);
333 			Script_GetToken (map_script, false);
334 			vecs[1][2] = atof (map_script->token->str);
335 			Script_GetToken (map_script, false);
336 			vecs[1][3] = atof (map_script->token->str);
337 			Script_GetToken (map_script, false);
338 			if (strcmp (map_script->token->str, "]"))
339 				map_error ("missing ]");
340 		} else {
341 			vecs[0][3] = atof (map_script->token->str);
342 			Script_GetToken (map_script, false);
343 			vecs[1][3] = atof (map_script->token->str);
344 		}
345 
346 		Script_GetToken (map_script, false);
347 		rotate = atof (map_script->token->str);
348 		Script_GetToken (map_script, false);
349 		scale[0] = atof (map_script->token->str);
350 		Script_GetToken (map_script, false);
351 		scale[1] = atof (map_script->token->str);
352 
353 		while (Script_TokenAvailable (map_script, false)) {
354 			Script_GetToken (map_script, false);
355 			if (!strcmp (map_script->token->str, "detail"))
356 				b->detail = 1;
357 			else
358 				map_error ("parse error");
359 		}
360 
361 		// if the three points are all on a previous plane, it is a duplicate
362 		// plane
363 		for (f2 = b->faces; f2; f2 = f2->next) {
364 			for (i = 0; i < 3; i++) {
365 				d = DotProduct (planepts[i], f2->plane.normal)
366 					- f2->plane.dist;
367 				if (d < -ON_EPSILON || d > ON_EPSILON)
368 					break;
369 			}
370 			if (i == 3)
371 				break;
372 		}
373 		if (f2) {
374 			printf ("WARNING: brush with duplicate plane\n");
375 			continue;
376 		}
377 
378 		if (DotProduct (plane.normal, plane.normal) < 0.1) {
379 			printf ("WARNING: brush plane with no normal on line %d\n",
380 					map_script->line);
381 			continue;
382 		}
383 
384 		if (!hltexdef) {
385 			// fake proper texture vectors from QuakeEd style
386 			TextureAxisFromPlane (&plane, vecs[0], vecs[1]);
387 		}
388 
389 		if (!scale[0])
390 			scale[0] = 1;
391 		if (!scale[1])
392 			scale[1] = 1;
393 
394 		// rotate axis
395 		if (rotate == 0) {
396 			sinv = 0;
397 			cosv = 1;
398 		} else if (rotate == 90) {
399 			sinv = 1;
400 			cosv = 0;
401 		} else if (rotate == 180) {
402 			sinv = 0;
403 			cosv = -1;
404 		} else if (rotate == 270) {
405 			sinv = -1;
406 			cosv = 0;
407 		} else {
408 			ang = rotate / 180 * M_PI;
409 			sinv = sin (ang);
410 			cosv = cos (ang);
411 		}
412 
413 		if (vecs[0][0])
414 			sv = 0;
415 		else if (vecs[0][1])
416 			sv = 1;
417 		else
418 			sv = 2;
419 
420 		if (vecs[1][0])
421 			tv = 0;
422 		else if (vecs[1][1])
423 			tv = 1;
424 		else
425 			tv = 2;
426 
427 		for (i = 0; i < 2; i++) {
428 			// rotate
429 			ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
430 			nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
431 			vecs[i][sv] = ns;
432 			vecs[i][tv] = nt;
433 			// scale and store into texinfo
434 			for (j = 0; j < 3; j++)
435 				tx.vecs[i][j] = vecs[i][j] / scale[i];
436 			tx.vecs[i][3] = vecs[i][3];
437 		}
438 
439 		f = calloc (1, sizeof (mface_t));
440 		f->next = b->faces;
441 		b->faces = f;
442 		f->plane = plane;
443 		// unique the texinfo
444 		f->texinfo = FindTexinfo (&tx);
445 		nummapbrushfaces++;
446 	} while (1);
447 	if (verts)
448 		free (verts);
449 }
450 
451 static qboolean
ParseEntity(void)452 ParseEntity (void)
453 {
454 	if (!Script_GetToken (map_script, true))
455 		return false;
456 
457 	if (strcmp (map_script->token->str, "{"))
458 		map_error ("ParseEntity: { not found");
459 
460 	if (num_entities == max_entities) {
461 		max_entities += ENTITIES_CHUNK;
462 		entities = realloc (entities, max_entities * sizeof (entity_t));
463 	}
464 
465 	mapent = &entities[num_entities];
466 	num_entities++;
467 	memset (mapent, 0, sizeof (entity_t));
468 	mapent->line = map_script->line;
469 
470 	do {
471 		if (!Script_GetToken (map_script, true))
472 			map_error ("ParseEntity: EOF without closing brace");
473 		if (!strcmp (map_script->token->str, "}"))
474 			break;
475 		if (!strcmp (map_script->token->str, "{"))
476 			ParseBrush ();
477 		else
478 			ParseEpair ();
479 	} while (1);
480 
481 	if (!strcmp ("am_detail", ValueForKey (mapent, "classname"))) {
482 		mbrush_t   *b, *lb;
483 		// set detail flag
484 		for (lb = b = mapent->brushes; b; lb = b, b = b->next) {
485 			b->detail = 1;
486 			numdetailbrushes++;
487 		}
488 		// add to worldspawn
489 		lb->next = entities->brushes;
490 		entities->brushes = mapent->brushes;
491 		num_entities--;
492 		memset (mapent, 0, sizeof (entity_t));
493 		return true;
494 	} else {
495 		mbrush_t   *b;
496 		for (b = mapent->brushes; b; b = b->next)
497 			if (b->detail)
498 				numdetailbrushes++;
499 	}
500 
501 	GetVectorForKey (mapent, "origin", mapent->origin);
502 	return true;
503 }
504 
505 void
LoadMapFile(const char * filename)506 LoadMapFile (const char *filename)
507 {
508 	char       *buf;
509 	QFile      *file;
510 	int         bytes;
511 
512 	file = Qopen (filename, "rt");
513 	if (!file)
514 		Sys_Error ("couldn't open %s. %s", filename, strerror(errno));
515 	bytes = Qfilesize (file);
516 	buf = malloc (bytes + 1);
517 	bytes = Qread (file, buf, bytes);
518 	buf[bytes] = 0;
519 	Qclose (file);
520 
521 	map_script = Script_New ();
522 	map_script->single = "";
523 	Script_Start (map_script, filename, buf);
524 
525 	num_entities = 0;
526 
527 	if (Script_GetToken (map_script, 1)) {
528 		if (strequal (map_script->token->str, "QuakeForge-map")) {
529 			if (!Script_TokenAvailable (map_script, 1))
530 				map_error ("Unexpected EOF reading %s\n", filename);
531 		} else {
532 			Script_UngetToken (map_script);
533 			while (ParseEntity ())
534 				;
535 		}
536 	}
537 
538 	Script_Delete (map_script);
539 	map_script = 0;
540 	free (buf);
541 
542 	qprintf ("--- LoadMapFile ---\n");
543 	qprintf ("%s\n", filename);
544 	qprintf ("%5i faces\n", nummapbrushfaces);
545 	qprintf ("%5i brushes (%i detail)\n", nummapbrushes, numdetailbrushes);
546 	qprintf ("%5i entities\n", num_entities);
547 	qprintf ("%5i textures\n", nummiptexnames);
548 	qprintf ("%5i texinfo\n", bsp->numtexinfo);
549 }
550 
551 void
PrintEntity(const entity_t * ent)552 PrintEntity (const entity_t *ent)
553 {
554 	const epair_t *ep;
555 
556 	printf ("%20s : %d\n", "map source line", ent->line);
557 	for (ep = ent->epairs; ep; ep = ep->next)
558 		printf ("%20s : %s\n", ep->key, ep->value);
559 }
560 
561 
562 const char *
ValueForKey(const entity_t * ent,const char * key)563 ValueForKey (const entity_t *ent, const char *key)
564 {
565 	const epair_t *ep;
566 
567 	for (ep = ent->epairs; ep; ep = ep->next)
568 		if (!strcmp (ep->key, key))
569 			return ep->value;
570 	return "";
571 }
572 
573 void
SetKeyValue(entity_t * ent,const char * key,const char * value)574 SetKeyValue (entity_t *ent, const char *key, const char *value)
575 {
576 	epair_t    *ep;
577 
578 	for (ep = ent->epairs; ep; ep = ep->next)
579 		if (!strcmp (ep->key, key)) {
580 			free (ep->value);
581 			ep->value = strdup (value);
582 			return;
583 		}
584 	ep = malloc (sizeof (*ep));
585 	ep->next = ent->epairs;
586 	ent->epairs = ep;
587 	ep->key = strdup (key);
588 	ep->value = strdup (value);
589 }
590 
591 void
GetVectorForKey(const entity_t * ent,const char * key,vec3_t vec)592 GetVectorForKey (const entity_t *ent, const char *key, vec3_t vec)
593 {
594 	const char *k;
595 	double      v1, v2, v3;
596 
597 	k = ValueForKey (ent, key);
598 	v1 = v2 = v3 = 0;
599 	// scanf into doubles, then assign, so it is vec_t size independent
600 	sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
601 	vec[0] = v1;
602 	vec[1] = v2;
603 	vec[2] = v3;
604 }
605 
606 void
WriteEntitiesToString(void)607 WriteEntitiesToString (void)
608 {
609 	dstring_t  *buf;
610 	const epair_t *ep;
611 	int         i;
612 
613 	buf = dstring_newstr ();
614 
615 	for (i = 0; i < num_entities; i++) {
616 		ep = entities[i].epairs;
617 		if (!ep)
618 			continue;					// ent got removed
619 
620 		dstring_appendstr (buf, "{\n");
621 
622 		for (ep = entities[i].epairs; ep; ep = ep->next) {
623 			dstring_appendstr (buf, va ("\"%s\" \"%s\"\n",
624 										ep->key, ep->value));
625 		}
626 		dstring_appendstr (buf, "}\n");
627 	}
628 	BSP_AddEntities (bsp, buf->str, buf->size);
629 }
630 
631 //@}
632