2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
5 This file is part of Quake 2 Tools source code.
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.
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.
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 ===========================================================================
27 qboolean modified; // for quit confirmation (0 = clean, 1 = unsaved,
28 // 2 = autosaved, but not regular saved)
30 char currentmap[1024];
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
38 entity_t entities; // head/tail of doubly linked list
40 entity_t *world_entity;
42 void AddRegionBrushes (void);
43 void RemoveRegionBrushes (void);
46 =============================================================
48 Cross map selection saving
50 this could fuck up if you have only part of a complex entity selected...
51 =============================================================
54 brush_t between_brushes;
55 entity_t between_entities;
58 void Map_SaveBetween (void)
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;
68 between_entities.next = between_entities.prev = &between_entities;
69 selected_brushes.next = selected_brushes.prev = &selected_brushes;
71 for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
74 if (e == world_entity)
78 for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next)
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;
93 void Map_RestoreBetween (void)
95 entity_t *head, *tail;
98 if (!between_brushes.next)
101 for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
105 b->owner = world_entity;
106 b->onext = world_entity->brushes.onext;
107 b->oprev = &world_entity->brushes;
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;
118 head = between_entities.next;
119 tail = between_entities.prev;
123 entities.prev->next = head;
124 head->prev = entities.prev;
125 tail->next = &entities;
126 entities.prev = tail;
129 between_brushes.next = NULL;
130 between_entities.next = NULL;
133 //============================================================================
135 void Map_BuildBrushData(void)
139 if (active_brushes.next == NULL)
142 Sys_BeginWait (); // this could take a while
144 for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next)
151 Sys_Printf ("Removed degenerate brush\n");
158 entity_t *Map_FindClass (char *cname)
162 for (ent = entities.next ; ent != &entities ; ent=ent->next)
164 if (!strcmp(cname, ValueForKey (ent, "classname")))
177 if (selected_brushes.next &&
178 (selected_brushes.next != &selected_brushes) )
180 if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES)
184 Texture_ClearInuse ();
186 strcpy (currentmap, "unnamed.map");
187 Sys_SetTitle (currentmap);
188 g_qeglobals.d_num_entities = 0;
190 if (!active_brushes.next)
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;
196 entities.prev = entities.next = &entities;
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);
207 while (entities.next != &entities)
208 Entity_Free (entities.next);
219 void Map_LoadFile (char *filename)
227 SetInspectorMode(W_CONSOLE);
229 QE_ConvertDOSToUnixName( temp, filename );
230 Sys_Printf ("Map_LoadFile: %s\n", temp );
234 g_qeglobals.d_parsed_brushes = 0;
235 strcpy (currentmap, filename);
236 LoadFile (filename, (void **)&buf);
238 StartTokenParsing (buf);
240 g_qeglobals.d_num_entities = 0;
244 ent = Entity_Parse (false);
247 if (!strcmp(ValueForKey (ent, "classname"), "worldspawn"))
250 Sys_Printf ("WARNING: multiple worldspawn\n");
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;
260 g_qeglobals.d_num_entities++;
268 Sys_Printf ("No worldspawn in map.\n");
273 Sys_Printf ("--- LoadMapFile ---\n");
274 Sys_Printf ("%s\n", temp );
276 Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes );
277 Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities);
279 Map_RestoreBetween ();
281 Sys_Printf ("Map_BuildAllDisplayLists\n");
282 Map_BuildBrushData();
285 // move the view to a start position
287 ent = Map_FindClass ("info_player_start");
289 ent = Map_FindClass ("info_player_deathmatch");
290 camera.angles[PITCH] = 0;
293 GetVectorForKey (ent, "origin", camera.origin);
294 GetVectorForKey (ent, "origin", g_qeglobals.d_xy.origin);
295 camera.angles[YAW] = FloatForKey (ent, "angle");
299 camera.angles[YAW] = 0;
300 VectorCopy (vec3_origin, camera.origin);
301 VectorCopy (vec3_origin, g_qeglobals.d_xy.origin);
304 Sys_UpdateWindows (W_ALL);
311 Texture_ShowInuse ();
322 void Map_SaveFile (char *filename, qboolean use_region )
329 QE_ConvertDOSToUnixName( temp, filename );
335 // rename current to .bak
336 strcpy (backup, filename);
337 StripExtension (backup);
338 strcat (backup, ".bak");
340 rename (filename, backup);
343 Sys_Printf ("Map_SaveFile: %s\n", filename);
345 f = fopen(filename, "w");
348 Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename);
355 // write world entity first
356 Entity_Write (world_entity, f, use_region);
358 // then write all other ents
360 for (e=entities.next ; e != &entities ; e=next)
362 fprintf (f, "// entity %i\n", count);
365 if (e->brushes.onext == &e->brushes)
366 Entity_Free (e); // no brushes left, so remove it
368 Entity_Write (e, f, use_region);
374 RemoveRegionBrushes ();
376 Sys_Printf ("Saved.\n");
379 if ( !strstr( temp, "autosave" ) )
388 MessageBeep (MB_ICONEXCLAMATION);
389 f = fopen ("c:/tstamps.log", "a");
392 fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer));
394 g_qeglobals.d_workcount = 0;
397 Sys_Status ("Saved.\n", 0);
408 Sys_Printf ("Map_New\n");
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);
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);
421 Map_RestoreBetween ();
423 Sys_UpdateWindows (W_ALL);
429 ===========================================================
433 ===========================================================
436 qboolean region_active;
437 vec3_t region_mins = {-4096, -4096, -4096};
438 vec3_t region_maxs = {4096, 4096, 4096};
440 brush_t *region_sides[4];
446 a regioned map will have temp walls put up at the region boundary
449 void AddRegionBrushes (void)
458 memset (&td, 0, sizeof(td));
459 strcpy (td.name, "REGION");
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;
467 region_sides[0] = Brush_Create (mins, maxs, &td);
469 mins[0] = region_maxs[0] - 1;
470 maxs[0] = region_maxs[0] + 16;
471 region_sides[1] = Brush_Create (mins, maxs, &td);
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);
479 mins[1] = region_maxs[1] - 1;
480 maxs[1] = region_maxs[1] + 16;
481 region_sides[3] = Brush_Create (mins, maxs, &td);
483 for (i=0 ; i<4 ; i++)
485 Brush_AddToList (region_sides[i], &selected_brushes);
486 Entity_LinkBrush (world_entity, region_sides[i]);
487 Brush_Build( region_sides[i] );
491 void RemoveRegionBrushes (void)
497 for (i=0 ; i<4 ; i++)
498 Brush_Free (region_sides[i]);
502 qboolean Map_IsBrushFiltered (brush_t *b)
506 for (i=0 ; i<3 ; i++)
508 if (b->mins[i] > region_maxs[i])
510 if (b->maxs[i] < region_mins[i])
520 Other filtering options may still be on
523 void Map_RegionOff (void)
528 region_active = false;
529 for (i=0 ; i<3 ; i++)
531 region_maxs[i] = 4096;
532 region_mins[i] = -4096;
535 for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next)
538 if (Map_IsBrushFiltered (b))
539 continue; // still filtered
540 Brush_RemoveFromList (b);
541 Brush_AddToList (b, &active_brushes);
544 Sys_UpdateWindows (W_ALL);
547 void Map_ApplyRegion (void)
551 region_active = true;
552 for (b=active_brushes.next ; b != &active_brushes ; b=next)
555 if (!Map_IsBrushFiltered (b))
556 continue; // still filtered
557 Brush_RemoveFromList (b);
558 Brush_AddToList (b, &filtered_brushes);
561 Sys_UpdateWindows (W_ALL);
566 ========================
567 Map_RegionSelectedBrushes
568 ========================
570 void Map_RegionSelectedBrushes (void)
574 region_active = true;
575 Select_GetBounds (region_mins, region_maxs);
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;
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;
589 // clear selected_brushes
590 selected_brushes.next = selected_brushes.prev = &selected_brushes;
592 Sys_UpdateWindows (W_ALL);
601 void Map_RegionXY (void)
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;
620 void Map_RegionTallBrush (void)
624 if (!QE_SingleBrush ())
627 b = selected_brushes.next;
631 VectorCopy (b->mins, region_mins);
632 VectorCopy (b->maxs, region_maxs);
633 region_mins[2] = -4096;
634 region_maxs[2] = 4096;
644 void Map_RegionBrush (void)
648 if (!QE_SingleBrush ())
651 b = selected_brushes.next;
655 VectorCopy (b->mins, region_mins);
656 VectorCopy (b->maxs, region_maxs);