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