]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/extra/qe4/map.c
Q2Tools source - didn't import this in initially
[xonotic/netradiant.git] / tools / quake2 / extra / qe4 / map.c
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
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
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
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
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 */
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 */
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 */
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 */
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 */
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
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
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 */
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
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 */
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 */
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 */
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 */
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