1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4 
5 This file is part of Quake 2 Tools source code.
6 
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 // map.c
24 
25 #include "qe3.h"
26 
27 qboolean	modified;		// for quit confirmation (0 = clean, 1 = unsaved,
28 							// 2 = autosaved, but not regular saved)
29 
30 char		currentmap[1024];
31 
32 brush_t	active_brushes;		// brushes currently being displayed
33 brush_t	selected_brushes;	// highlighted
34 face_t	*selected_face;
35 brush_t	*selected_face_brush;
36 brush_t	filtered_brushes;	// brushes that have been filtered or regioned
37 
38 entity_t	entities;		// head/tail of doubly linked list
39 
40 entity_t	*world_entity;
41 
42 void AddRegionBrushes (void);
43 void RemoveRegionBrushes (void);
44 
45 /*
46 =============================================================
47 
48   Cross map selection saving
49 
50   this could fuck up if you have only part of a complex entity selected...
51 =============================================================
52 */
53 
54 brush_t		between_brushes;
55 entity_t	between_entities;
56 
57 
Map_SaveBetween(void)58 void Map_SaveBetween (void)
59 {
60 	brush_t		*b;
61 	entity_t	*e, *e2;
62 
63 	between_brushes.next = selected_brushes.next;
64 	between_brushes.prev = selected_brushes.prev;
65 	between_brushes.next->prev = &between_brushes;
66 	between_brushes.prev->next = &between_brushes;
67 
68 	between_entities.next = between_entities.prev = &between_entities;
69 	selected_brushes.next = selected_brushes.prev = &selected_brushes;
70 
71 	for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
72 	{
73 		e = b->owner;
74 		if (e == world_entity)
75 			b->owner = NULL;
76 		else
77 		{
78 			for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next)
79 				if (e2 == e)
80 					goto next;	// allready got the entity
81 			// move the entity over
82 			e->prev->next = e->next;
83 			e->next->prev = e->prev;
84 			e->next = between_entities.next;
85 			e->prev = &between_entities;
86 			e->next->prev = e;
87 			e->prev->next = e;
88 		}
89 next: ;
90 	}
91 }
92 
Map_RestoreBetween(void)93 void Map_RestoreBetween (void)
94 {
95 	entity_t	*head, *tail;
96 	brush_t		*b;
97 
98 	if (!between_brushes.next)
99 		return;
100 
101 	for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
102 	{
103 		if (!b->owner)
104 		{
105 			b->owner = world_entity;
106 			b->onext = world_entity->brushes.onext;
107 			b->oprev = &world_entity->brushes;
108 			b->onext->oprev = b;
109 			b->oprev->onext = b;
110 		}
111 	}
112 
113 	selected_brushes.next = between_brushes.next;
114 	selected_brushes.prev = between_brushes.prev;
115 	selected_brushes.next->prev = &selected_brushes;
116 	selected_brushes.prev->next = &selected_brushes;
117 
118 	head = between_entities.next;
119 	tail = between_entities.prev;
120 
121 	if (head != tail)
122 	{
123 		entities.prev->next = head;
124 		head->prev = entities.prev;
125 		tail->next = &entities;
126 		entities.prev = tail;
127 	}
128 
129 	between_brushes.next = NULL;
130 	between_entities.next = NULL;
131 }
132 
133 //============================================================================
134 
Map_BuildBrushData(void)135 void Map_BuildBrushData(void)
136 {
137 	brush_t	*b, *next;
138 
139 	if (active_brushes.next == NULL)
140 		return;
141 
142 	Sys_BeginWait ();	// this could take a while
143 
144 	for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next)
145 	{
146 		next = b->next;
147 		Brush_Build( b );
148 		if (!b->brush_faces)
149 		{
150 			Brush_Free (b);
151 			Sys_Printf ("Removed degenerate brush\n");
152 		}
153 	}
154 
155 	Sys_EndWait();
156 }
157 
Map_FindClass(char * cname)158 entity_t *Map_FindClass (char *cname)
159 {
160 	entity_t	*ent;
161 
162 	for (ent = entities.next ; ent != &entities ; ent=ent->next)
163 	{
164 		if (!strcmp(cname, ValueForKey (ent, "classname")))
165 			return ent;
166 	}
167 	return NULL;
168 }
169 
170 /*
171 ================
172 Map_Free
173 ================
174 */
Map_Free(void)175 void Map_Free (void)
176 {
177 	if (selected_brushes.next &&
178 		(selected_brushes.next != &selected_brushes) )
179 	{
180 	    if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES)
181 			Map_SaveBetween ();
182 	}
183 
184 	Texture_ClearInuse ();
185 	Pointfile_Clear ();
186 	strcpy (currentmap, "unnamed.map");
187 	Sys_SetTitle (currentmap);
188 	g_qeglobals.d_num_entities = 0;
189 
190 	if (!active_brushes.next)
191 	{	// first map
192 		active_brushes.prev = active_brushes.next = &active_brushes;
193 		selected_brushes.prev = selected_brushes.next = &selected_brushes;
194 		filtered_brushes.prev = filtered_brushes.next = &filtered_brushes;
195 
196 		entities.prev = entities.next = &entities;
197 	}
198 	else
199 	{
200 		while (active_brushes.next != &active_brushes)
201 			Brush_Free (active_brushes.next);
202 		while (selected_brushes.next != &selected_brushes)
203 			Brush_Free (selected_brushes.next);
204 		while (filtered_brushes.next != &filtered_brushes)
205 			Brush_Free (filtered_brushes.next);
206 
207 		while (entities.next != &entities)
208 			Entity_Free (entities.next);
209 	}
210 
211 	world_entity = NULL;
212 }
213 
214 /*
215 ================
216 Map_LoadFile
217 ================
218 */
Map_LoadFile(char * filename)219 void Map_LoadFile (char *filename)
220 {
221     char		*buf;
222 	entity_t	*ent;
223 	char         temp[1024];
224 
225 	Sys_BeginWait ();
226 
227 	SetInspectorMode(W_CONSOLE);
228 
229 	QE_ConvertDOSToUnixName( temp, filename );
230 	Sys_Printf ("Map_LoadFile: %s\n", temp );
231 
232 	Map_Free ();
233 
234 	g_qeglobals.d_parsed_brushes = 0;
235 	strcpy (currentmap, filename);
236     LoadFile (filename, (void **)&buf);
237 
238 	StartTokenParsing (buf);
239 
240 	g_qeglobals.d_num_entities = 0;
241 
242 	while (1)
243 	{
244 		ent = Entity_Parse (false);
245 		if (!ent)
246 			break;
247 		if (!strcmp(ValueForKey (ent, "classname"), "worldspawn"))
248 		{
249 			if (world_entity)
250 				Sys_Printf ("WARNING: multiple worldspawn\n");
251 			world_entity = ent;
252 		}
253 		else
254 		{
255 			// add the entity to the end of the entity list
256 			ent->next = &entities;
257 			ent->prev = entities.prev;
258 			entities.prev->next = ent;
259 			entities.prev = ent;
260 			g_qeglobals.d_num_entities++;
261 		}
262 	}
263 
264     free (buf);
265 
266 	if (!world_entity)
267 	{
268 		Sys_Printf ("No worldspawn in map.\n");
269 		Map_New ();
270 		return;
271 	}
272 
273     Sys_Printf ("--- LoadMapFile ---\n");
274     Sys_Printf ("%s\n", temp );
275 
276     Sys_Printf ("%5i brushes\n",  g_qeglobals.d_parsed_brushes );
277     Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities);
278 
279 	Map_RestoreBetween ();
280 
281 	Sys_Printf ("Map_BuildAllDisplayLists\n");
282     Map_BuildBrushData();
283 
284 	//
285 	// move the view to a start position
286 	//
287 	ent = Map_FindClass ("info_player_start");
288 	if (!ent)
289 		ent = Map_FindClass ("info_player_deathmatch");
290 	camera.angles[PITCH] = 0;
291 	if (ent)
292 	{
293 		GetVectorForKey (ent, "origin", camera.origin);
294 		GetVectorForKey (ent, "origin", g_qeglobals.d_xy.origin);
295 		camera.angles[YAW] = FloatForKey (ent, "angle");
296 	}
297 	else
298 	{
299 		camera.angles[YAW] = 0;
300 		VectorCopy (vec3_origin, camera.origin);
301 		VectorCopy (vec3_origin, g_qeglobals.d_xy.origin);
302 	}
303 
304 	Sys_UpdateWindows (W_ALL);
305 
306 	Map_RegionOff ();
307 
308 	modified = false;
309 	Sys_SetTitle (temp);
310 
311 	Texture_ShowInuse ();
312 
313 	Sys_EndWait();
314 
315 }
316 
317 /*
318 ===========
319 Map_SaveFile
320 ===========
321 */
Map_SaveFile(char * filename,qboolean use_region)322 void Map_SaveFile (char *filename, qboolean use_region )
323 {
324 	entity_t	*e, *next;
325 	FILE		*f;
326 	char         temp[1024];
327 	int			count;
328 
329 	QE_ConvertDOSToUnixName( temp, filename );
330 
331 	if (!use_region)
332 	{
333 		char	backup[1024];
334 
335 		// rename current to .bak
336 		strcpy (backup, filename);
337 		StripExtension (backup);
338 		strcat (backup, ".bak");
339 		_unlink (backup);
340 		rename (filename, backup);
341 	}
342 
343 	Sys_Printf ("Map_SaveFile: %s\n", filename);
344 
345 	f = fopen(filename, "w");
346 	if (!f)
347 	{
348 		Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename);
349 		return;
350 	}
351 
352 	if (use_region)
353 		AddRegionBrushes ();
354 
355 	// write world entity first
356 	Entity_Write (world_entity, f, use_region);
357 
358 	// then write all other ents
359 	count = 1;
360 	for (e=entities.next ; e != &entities ; e=next)
361 	{
362 		fprintf (f, "// entity %i\n", count);
363 		count++;
364 		next = e->next;
365 		if (e->brushes.onext == &e->brushes)
366 			Entity_Free (e);	// no brushes left, so remove it
367 		else
368 			Entity_Write (e, f, use_region);
369 	}
370 
371 	fclose (f);
372 
373 	if (use_region)
374 		RemoveRegionBrushes ();
375 
376 	Sys_Printf ("Saved.\n");
377 	modified = false;
378 
379 	if ( !strstr( temp, "autosave" ) )
380 		Sys_SetTitle (temp);
381 
382 	if (!use_region)
383 	{
384 		time_t	timer;
385 		FILE	*f;
386 
387 		time (&timer);
388 		MessageBeep (MB_ICONEXCLAMATION);
389 		f = fopen ("c:/tstamps.log", "a");
390 		if (f)
391 		{
392 			fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer));
393 			fclose (f);
394 			g_qeglobals.d_workcount = 0;
395 		}
396 		fclose (f);
397 		Sys_Status ("Saved.\n", 0);
398 	}
399 }
400 
401 /*
402 ===========
403 Map_New
404 ===========
405 */
Map_New(void)406 void Map_New (void)
407 {
408 	Sys_Printf ("Map_New\n");
409 	Map_Free ();
410 	world_entity = qmalloc(sizeof(*world_entity));
411 	world_entity->brushes.onext =
412 		world_entity->brushes.oprev = &world_entity->brushes;
413 	SetKeyValue (world_entity, "classname", "worldspawn");
414 	world_entity->eclass = Eclass_ForName ("worldspawn", true);
415 
416 	camera.angles[YAW] = 0;
417 	VectorCopy (vec3_origin, camera.origin);
418 	camera.origin[2] = 48;
419 	VectorCopy (vec3_origin, g_qeglobals.d_xy.origin);
420 
421 	Map_RestoreBetween ();
422 
423 	Sys_UpdateWindows (W_ALL);
424 	modified = false;
425 }
426 
427 
428 /*
429 ===========================================================
430 
431   REGION
432 
433 ===========================================================
434 */
435 
436 qboolean	region_active;
437 vec3_t	region_mins = {-4096, -4096, -4096};
438 vec3_t	region_maxs = {4096, 4096, 4096};
439 
440 brush_t	*region_sides[4];
441 
442 /*
443 ===========
444 AddRegionBrushes
445 
446 a regioned map will have temp walls put up at the region boundary
447 ===========
448 */
AddRegionBrushes(void)449 void AddRegionBrushes (void)
450 {
451 	vec3_t	mins, maxs;
452 	int		i;
453 	texdef_t	td;
454 
455 	if (!region_active)
456 		return;
457 
458 	memset (&td, 0, sizeof(td));
459 	strcpy (td.name, "REGION");
460 
461 	mins[0] = region_mins[0] - 16;
462 	maxs[0] = region_mins[0] + 1;
463 	mins[1] = region_mins[1] - 16;
464 	maxs[1] = region_maxs[1] + 16;
465 	mins[2] = -2048;
466 	maxs[2] = 2048;
467 	region_sides[0] = Brush_Create (mins, maxs, &td);
468 
469 	mins[0] = region_maxs[0] - 1;
470 	maxs[0] = region_maxs[0] + 16;
471 	region_sides[1] = Brush_Create (mins, maxs, &td);
472 
473 	mins[0] = region_mins[0] - 16;
474 	maxs[0] = region_maxs[0] + 16;
475 	mins[1] = region_mins[1] - 16;
476 	maxs[1] = region_mins[1] + 1;
477 	region_sides[2] = Brush_Create (mins, maxs, &td);
478 
479 	mins[1] = region_maxs[1] - 1;
480 	maxs[1] = region_maxs[1] + 16;
481 	region_sides[3] = Brush_Create (mins, maxs, &td);
482 
483 	for (i=0 ; i<4 ; i++)
484 	{
485 		Brush_AddToList (region_sides[i], &selected_brushes);
486 		Entity_LinkBrush (world_entity, region_sides[i]);
487 		Brush_Build( region_sides[i] );
488 	}
489 }
490 
RemoveRegionBrushes(void)491 void RemoveRegionBrushes (void)
492 {
493 	int		i;
494 
495 	if (!region_active)
496 		return;
497 	for (i=0 ; i<4 ; i++)
498 		Brush_Free (region_sides[i]);
499 }
500 
501 
Map_IsBrushFiltered(brush_t * b)502 qboolean Map_IsBrushFiltered (brush_t *b)
503 {
504 	int		i;
505 
506 	for (i=0 ; i<3 ; i++)
507 	{
508 		if (b->mins[i] > region_maxs[i])
509 			return true;
510 		if (b->maxs[i] < region_mins[i])
511 			return true;
512 	}
513 	return false;
514 }
515 
516 /*
517 ===========
518 Map_RegionOff
519 
520 Other filtering options may still be on
521 ===========
522 */
Map_RegionOff(void)523 void Map_RegionOff (void)
524 {
525 	brush_t	*b, *next;
526 	int			i;
527 
528 	region_active = false;
529 	for (i=0 ; i<3 ; i++)
530 	{
531 		region_maxs[i] = 4096;
532 		region_mins[i] = -4096;
533 	}
534 
535 	for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next)
536 	{
537 		next = b->next;
538 		if (Map_IsBrushFiltered (b))
539 			continue;		// still filtered
540 		Brush_RemoveFromList (b);
541 		Brush_AddToList (b, &active_brushes);
542 	}
543 
544 	Sys_UpdateWindows (W_ALL);
545 }
546 
Map_ApplyRegion(void)547 void Map_ApplyRegion (void)
548 {
549 	brush_t	*b, *next;
550 
551 	region_active = true;
552 	for (b=active_brushes.next ; b != &active_brushes ; b=next)
553 	{
554 		next = b->next;
555 		if (!Map_IsBrushFiltered (b))
556 			continue;		// still filtered
557 		Brush_RemoveFromList (b);
558 		Brush_AddToList (b, &filtered_brushes);
559 	}
560 
561 	Sys_UpdateWindows (W_ALL);
562 }
563 
564 
565 /*
566 ========================
567 Map_RegionSelectedBrushes
568 ========================
569 */
Map_RegionSelectedBrushes(void)570 void Map_RegionSelectedBrushes (void)
571 {
572 	Map_RegionOff ();
573 
574 	region_active = true;
575 	Select_GetBounds (region_mins, region_maxs);
576 
577 	// move the entire active_brushes list to filtered_brushes
578 	filtered_brushes.next = active_brushes.next;
579 	filtered_brushes.prev = active_brushes.prev;
580 	filtered_brushes.next->prev = &filtered_brushes;
581 	filtered_brushes.prev->next = &filtered_brushes;
582 
583 	// move the entire selected_brushes list to active_brushes
584 	active_brushes.next = selected_brushes.next;
585 	active_brushes.prev = selected_brushes.prev;
586 	active_brushes.next->prev = &active_brushes;
587 	active_brushes.prev->next = &active_brushes;
588 
589 	// clear selected_brushes
590 	selected_brushes.next = selected_brushes.prev = &selected_brushes;
591 
592 	Sys_UpdateWindows (W_ALL);
593 }
594 
595 
596 /*
597 ===========
598 Map_RegionXY
599 ===========
600 */
Map_RegionXY(void)601 void Map_RegionXY (void)
602 {
603 	Map_RegionOff ();
604 
605 	region_mins[0] = g_qeglobals.d_xy.origin[0] - 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale;
606 	region_maxs[0] = g_qeglobals.d_xy.origin[0] + 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale;
607 	region_mins[1] = g_qeglobals.d_xy.origin[1] - 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale;
608 	region_maxs[1] = g_qeglobals.d_xy.origin[1] + 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale;
609 	region_mins[2] = -4096;
610 	region_maxs[2] = 4096;
611 
612 	Map_ApplyRegion ();
613 }
614 
615 /*
616 ===========
617 Map_RegionTallBrush
618 ===========
619 */
Map_RegionTallBrush(void)620 void Map_RegionTallBrush (void)
621 {
622 	brush_t	*b;
623 
624 	if (!QE_SingleBrush ())
625 		return;
626 
627 	b = selected_brushes.next;
628 
629 	Map_RegionOff ();
630 
631 	VectorCopy (b->mins, region_mins);
632 	VectorCopy (b->maxs, region_maxs);
633 	region_mins[2] = -4096;
634 	region_maxs[2] = 4096;
635 
636 	Select_Delete ();
637 	Map_ApplyRegion ();
638 }
639 /*
640 ===========
641 Map_RegionBrush
642 ===========
643 */
Map_RegionBrush(void)644 void Map_RegionBrush (void)
645 {
646 	brush_t	*b;
647 
648 	if (!QE_SingleBrush ())
649 		return;
650 
651 	b = selected_brushes.next;
652 
653 	Map_RegionOff ();
654 
655 	VectorCopy (b->mins, region_mins);
656 	VectorCopy (b->maxs, region_maxs);
657 
658 	Select_Delete ();
659 	Map_ApplyRegion ();
660 }
661 
662