doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
EditorMap.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "qe3.h"
33 
34 int mapModified; // for quit confirmation (0 = clean, 1 = unsaved,
35 
36 // 2 = autosaved, but not regular saved)
37 char currentmap[1024];
38 
39 brush_t active_brushes; // brushes currently being displayed
40 brush_t selected_brushes; // highlighted
41 
42 face_t *selected_face;
44 
45 brush_t filtered_brushes; // brushes that have been filtered or regioned
46 
47 entity_t entities; // head/tail of doubly linked list
48 
49 entity_t *world_entity = NULL; // "classname" "worldspawn" !
50 
51 void AddRegionBrushes(void);
52 void RemoveRegionBrushes(void);
53 
54 /*
55  =======================================================================================================================
56  =======================================================================================================================
57  */
58 void DupLists() {
59  DWORD dw = GetTickCount();
60 }
61 
62 /*
63  * Cross map selection saving this could mess this up if you have only part of a
64  * complex entity selected...
65  */
68 
69 bool g_bRestoreBetween = false;
70 
71 /*
72  =======================================================================================================================
73  =======================================================================================================================
74  */
75 void Map_SaveBetween(void) {
76  if (g_pParentWnd->ActiveXY()) {
77  g_bRestoreBetween = true;
79  }
80 
81  return;
82 
83 }
84 
85 /*
86  =======================================================================================================================
87  =======================================================================================================================
88  */
89 void Map_RestoreBetween(void) {
92  }
93 
94  return;
95 
96 }
97 
98 /*
99  =======================================================================================================================
100  =======================================================================================================================
101  */
102 bool CheckForTinyBrush(brush_t *b, int n, float fSize) {
103  bool bTiny = false;
104  for (int i = 0; i < 3; i++) {
105  if (b->maxs[i] - b->mins[i] < fSize) {
106  bTiny = true;
107  }
108  }
109 
110  if (bTiny) {
111  common->Printf("Possible problem brush (too small) #%i ", n);
112  }
113 
114  return bTiny;
115 }
116 
117 /*
118  =======================================================================================================================
119  =======================================================================================================================
120  */
121 void Map_BuildBrushData(void) {
122  brush_t *b, *next;
123 
124  if (active_brushes.next == NULL) {
125  return;
126  }
127 
128  Sys_BeginWait(); // this could take a while
129 
130  int n = 0;
131  for (b = active_brushes.next; b != NULL && b != &active_brushes; b = next) {
132  next = b->next;
133  Brush_Build(b, true, false, false);
134  if (!b->brush_faces || (g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush(b, n++, g_PrefsDlg.m_fTinySize))) {
135  Brush_Free(b);
136  common->Printf("Removed degenerate brush\n");
137  }
138  }
139 
140  Sys_EndWait();
141 }
142 
143 /*
144  =======================================================================================================================
145  =======================================================================================================================
146  */
147 entity_t *Map_FindClass(char *cname) {
148  entity_t *ent;
149 
150  for (ent = entities.next; ent != &entities; ent = ent->next) {
151  if (!strcmp(cname, ValueForKey(ent, "classname"))) {
152  return ent;
153  }
154  }
155 
156  return NULL;
157 }
158 
159 /*
160  =======================================================================================================================
161  =======================================================================================================================
162  */
163 int Map_GetUniqueEntityID(const char *prefix, const char *eclass) {
164  entity_t *ent;
165  int id = 0;
166  for (ent = entities.next; ent != &entities; ent = ent->next) {
167  if (!strcmp(eclass, ValueForKey(ent, "classname"))) {
168  const char *name = ValueForKey(ent, "name");
169  if (name && name[0]) {
170  const char *buf;
171  if (prefix && *prefix) {
172  buf = va("%s_%s_", prefix, eclass);
173  } else {
174  buf = va("%s_", eclass);
175  }
176  int len = strlen(buf);
177  if ( idStr::Cmpn(name, buf, len) == 0 ) {
178  int j = atoi(name + len);
179  if (j > id) {
180  id = j;
181  }
182  }
183  }
184  }
185  }
186 
187  return id + 1;
188 }
189 
190 /*
191  =======================================================================================================================
192  =======================================================================================================================
193  */
194 bool Entity_NameIsUnique(const char *name) {
195  entity_t *ent;
196  if (name == NULL) {
197  return false;
198  }
199 
200  for (ent = entities.next; ent != &entities; ent = ent->next) {
201  const char *testName = ValueForKey(ent, "name");
202  if (testName) {
203  if ( idStr::Icmp(name, testName) == 0 ) {
204  return false;
205  }
206  }
207  }
208 
209  return true;
210 }
211 
212 /*
213  =======================================================================================================================
214  Map_Free
215  =======================================================================================================================
216  */
217 void Map_Free(void) {
218  g_bRestoreBetween = false;
219  if (selected_brushes.next && (selected_brushes.next != &selected_brushes)) {
220  if (g_pParentWnd->MessageBox("Copy selection?", "", MB_YESNO) == IDYES) {
221  Map_SaveBetween();
222  }
223  }
224 
225  // clear all the render and sound system data
226  g_qeglobals.rw->InitFromMap( NULL );
227  g_qeglobals.sw->ClearAllSoundEmitters();
228 
230  Pointfile_Clear();
231  strcpy(currentmap, "unnamed.map");
232  Sys_SetTitle(currentmap);
233  g_qeglobals.d_num_entities = 0;
234 
235  if (!active_brushes.next) { // first map
239 
240  entities.prev = entities.next = &entities;
241  }
242  else {
243  while (active_brushes.next != &active_brushes) {
244  Brush_Free(active_brushes.next, false);
245  }
246 
247  while (selected_brushes.next != &selected_brushes) {
248  Brush_Free(selected_brushes.next, false);
249  }
250 
251  while (filtered_brushes.next != &filtered_brushes) {
252  Brush_Free(filtered_brushes.next, false);
253  }
254 
255  while (entities.next != &entities) {
256  Entity_Free(entities.next);
257  }
258  }
259 
260  if (world_entity) {
261  Entity_Free(world_entity);
262  }
263 
264  world_entity = NULL;
265 }
266 
267 /*
268  =======================================================================================================================
269  =======================================================================================================================
270  */
272  entity_t *ent = Map_FindClass("info_player_start");
273  if (!ent) {
274  ent = Map_FindClass("info_player_deathmatch");
275  }
276 
277  if (!ent) {
278  ent = Map_FindClass("info_player_deathmatch");
279  }
280 
281  if (!ent) {
282  ent = Map_FindClass("team_CTF_redplayer");
283  }
284 
285  if (!ent) {
286  ent = Map_FindClass("team_CTF_blueplayer");
287  }
288 
289  if (!ent) {
290  ent = Map_FindClass("team_CTF_redspawn");
291  }
292 
293  if (!ent) {
294  ent = Map_FindClass("team_CTF_bluespawn");
295  }
296 
297  return ent;
298 }
299 
300 
302  patchMesh_t *pm = MakeNewPatch(mappatch->GetWidth(), mappatch->GetHeight());
303  pm->d_texture = Texture_ForName(mappatch->GetMaterial());
304  for (int i = 0; i < mappatch->GetWidth(); i++) {
305  for (int j = 0; j < mappatch->GetHeight(); j++) {
306  pm->ctrl(i, j).xyz = (*mappatch)[j * mappatch->GetWidth() + i].xyz + origin;
307  pm->ctrl(i, j).st = (*mappatch)[j * mappatch->GetWidth() + i].st;
308  }
309  }
310  pm->horzSubdivisions = mappatch->GetHorzSubdivisions();
311  pm->vertSubdivisions = mappatch->GetVertSubdivisions();
312  pm->explicitSubdivisions = mappatch->GetExplicitlySubdivided();
313  if (mappatch->epairs.GetNumKeyVals()) {
314  pm->epairs = new idDict;
315  *pm->epairs = mappatch->epairs;
316  }
317  brush_t *b = AddBrushForPatch(pm, false);
318  return b;
319 }
320 
322  brush_t *b = NULL;
323  if (mapbrush) {
324  b = Brush_Alloc();
325  int count = mapbrush->GetNumSides();
326  for (int i = 0; i < count; i++) {
327  idMapBrushSide *side = mapbrush->GetSide(i);
328  face_t *f = Face_Alloc();
329  f->next = NULL;
330  if (!b->brush_faces) {
331  b->brush_faces = f;
332  }
333  else {
334  face_t *scan;
335  for (scan = b->brush_faces; scan->next; scan = scan->next) {
336  ;
337  }
338  scan->next = f;
339  }
340  f->plane = side->GetPlane();
341  f->originalPlane = f->plane;
342  f->dirty = false;
343 
344  idWinding w;
345  w.BaseForPlane(f->plane);
346 
347  for (int j = 0; j < 3; j++) {
348  f->planepts[j].x = w[j].x + origin.x;
349  f->planepts[j].y = w[j].y + origin.y;
350  f->planepts[j].z = w[j].z + origin.z;
351  }
352 
353  idVec3 mat[2];
354  side->GetTextureMatrix(mat[0], mat[1]);
355  f->brushprimit_texdef.coords[0][0] = mat[0][0];
356  f->brushprimit_texdef.coords[0][1] = mat[0][1];
357  f->brushprimit_texdef.coords[0][2] = mat[0][2];
358  f->brushprimit_texdef.coords[1][0] = mat[1][0];
359  f->brushprimit_texdef.coords[1][1] = mat[1][1];
360  f->brushprimit_texdef.coords[1][2] = mat[1][2];
361 
362  f->texdef.SetName(side->GetMaterial());
363  }
364  }
365  return b;
366 }
367 
369  entity_t *ent = NULL;
370  if (mapent) {
371  ent = Entity_New();
372  ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
373  ent->origin.Zero();
374  ent->epairs = mapent->epairs;
375  GetVectorForKey(ent, "origin", ent->origin);
376  int count = mapent->GetNumPrimitives();
377  long lastUpdate = 0;
378  idStr status;
379  for (int i = 0; i < count; i++) {
380  idMapPrimitive *prim = mapent->GetPrimitive(i);
381  if (prim) {
382  // update 20 times a second
383  if ( (GetTickCount() - lastUpdate) > 50 ) {
384  lastUpdate = GetTickCount();
385  if (prim->GetType() == idMapPrimitive::TYPE_BRUSH) {
386  sprintf(status, "Reading primitive %i (brush)", i);
387  } else if (prim->GetType() == idMapPrimitive::TYPE_PATCH) {
388  sprintf(status, "Reading primitive %i (patch)", i);
389  }
390  dlg->SetText(status, true);
391  }
392  if ( dlg->CancelPressed() ) {
393  return ent;
394  }
395 
396  brush_t *b = NULL;
397  if (prim->GetType() == idMapPrimitive::TYPE_BRUSH) {
398  idMapBrush *mapbrush = reinterpret_cast<idMapBrush*>(prim);
399  b = BrushFromMapBrush(mapbrush, ent->origin);
400  } else if (prim->GetType() == idMapPrimitive::TYPE_PATCH) {
401  idMapPatch *mappatch = reinterpret_cast<idMapPatch*>(prim);
402  b = BrushFromMapPatch(mappatch, ent->origin);
403  }
404  if (b) {
405  b->owner = ent;
406  // add to the end of the entity chain
407  b->onext = &ent->brushes;
408  b->oprev = ent->brushes.oprev;
409  ent->brushes.oprev->onext = b;
410  ent->brushes.oprev = b;
411  }
412  }
413  }
414  }
415  return ent;
416 }
417 
418 extern entity_t *Entity_PostParse(entity_t *ent, brush_t *pList);
419  /*
420  =======================================================================================================================
421  Map_LoadFile
422  =======================================================================================================================
423  */
424 void Map_LoadFile(const char *filename) {
425  entity_t *ent;
426  CWaitDlg dlg;
427  idStr fileStr, status;
428  idMapFile mapfile;
429 
430  Sys_BeginWait();
431  Select_Deselect();
432 
433  dlg.AllowCancel( true );
434  idStr( filename ).ExtractFileName( fileStr );
435  sprintf( status, "Loading %s...", fileStr.c_str() );
436  dlg.SetWindowText( status );
437  sprintf( status, "Reading file %s...", fileStr.c_str() );
438  dlg.SetText( status );
439 
440  // SetInspectorMode(W_CONSOLE);
441  fileStr = filename;
442  fileStr.BackSlashesToSlashes();
443 
444  common->Printf( "Map_LoadFile: %s\n", fileStr.c_str() );
445 
446  Map_Free();
447 
448  g_qeglobals.d_parsed_brushes = 0;
449  strcpy( currentmap, filename );
450 
451  if(mapfile.Parse(filename, true, true)) {
452  g_qeglobals.bNeedConvert = false;
453  g_qeglobals.bOldBrushes = false;
454  g_qeglobals.bPrimitBrushes = false;
455  g_qeglobals.mapVersion = 1.0;
456 
457  long lastUpdate = 0;
458  int count = mapfile.GetNumEntities();
459  for (int i = 0; i < count; i++) {
460  idMapEntity *mapent = mapfile.GetEntity(i);
461  if (mapent) {
462  idStr classname = mapent->epairs.GetString("classname");
463  // Update 20 times a second
464  if ( (GetTickCount() - lastUpdate) > 50 ) {
465  lastUpdate = GetTickCount();
466  sprintf(status, "Loading entity %i (%s)...", i, classname.c_str());
467  dlg.SetText(status);
468  }
469  if ( dlg.CancelPressed() ) {
470  Sys_Status("Map load cancelled.\n");
471  Map_New();
472  return;
473  }
474  if (classname == "worldspawn") {
475  world_entity = EntityFromMapEntity(mapent, &dlg);
476  Entity_PostParse(world_entity, &active_brushes);
477  } else {
478  ent = EntityFromMapEntity(mapent, &dlg);
480  Entity_Name(ent, true);
481  // add the entity to the end of the entity list
482  ent->next = &entities;
483  ent->prev = entities.prev;
484  entities.prev->next = ent;
485  entities.prev = ent;
486  g_qeglobals.d_num_entities++;
487  }
488  }
489  }
490  }
491 
492  if (!world_entity) {
493  Sys_Status("No worldspawn in map.\n");
494  Map_New();
495  return;
496  }
497 
498  common->Printf("--- LoadMapFile ---\n");
499  common->Printf("%s\n", fileStr.c_str());
500 
501  common->Printf("%5i brushes\n", g_qeglobals.d_parsed_brushes);
502  common->Printf("%5i entities\n", g_qeglobals.d_num_entities);
503 
504  dlg.SetText("Restoring Between");
506 
507  dlg.SetText("Building Brush Data");
508  common->Printf("Map_BuildAllDisplayLists\n");
510 
511  //
512  // reset the "need conversion" flag conversion to the good format done in
513  // Map_BuildBrushData
514  //
515  g_qeglobals.bNeedConvert = false;
516 
517  // move the view to a start position
518  ent = AngledEntity();
519 
521 
522  if (ent) {
523  GetVectorForKey(ent, "origin", g_pParentWnd->GetCamera()->Camera().origin);
524  GetVectorForKey(ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin());
525  g_pParentWnd->GetCamera()->Camera().angles[YAW] = FloatForKey(ent, "angle");
526  }
527  else {
531  }
532 
533  Map_RegionOff();
534 
535  mapModified = 0;
536 
537  if (GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY) {
538  fileStr += " (read only) ";
539  }
540  Sys_SetTitle(fileStr);
541 
543 
546  }
547 
548  Sys_EndWait();
549  Sys_UpdateWindows(W_ALL);
550 }
551 
552 
553 void Map_VerifyCurrentMap(const char *map) {
554  if ( idStr::Icmp( map, currentmap ) != 0 ) {
555  Map_LoadFile( map );
556  }
557 }
558 
559 idMapPrimitive *BrushToMapPrimitive( const brush_t *b, const idVec3 &origin ) {
560  if ( b->pPatch ) {
561  idMapPatch *patch = new idMapPatch( b->pPatch->width * 6, b->pPatch->height * 6 );
562  patch->SetSize( b->pPatch->width, b->pPatch->height );
563  for ( int i = 0; i < b->pPatch->width; i++ ) {
564  for ( int j = 0; j < b->pPatch->height; j++ ) {
565  (*patch)[j*patch->GetWidth()+i].xyz = b->pPatch->ctrl(i, j).xyz - origin;
566  (*patch)[j*patch->GetWidth()+i].st = b->pPatch->ctrl(i, j).st;
567  }
568  }
569  patch->SetExplicitlySubdivided( b->pPatch->explicitSubdivisions );
570  if ( b->pPatch->explicitSubdivisions ) {
571  patch->SetHorzSubdivisions( b->pPatch->horzSubdivisions );
572  patch->SetVertSubdivisions( b->pPatch->vertSubdivisions );
573  }
574  patch->SetMaterial( b->pPatch->d_texture->GetName() );
575  if ( b->pPatch->epairs ) {
576  patch->epairs = *b->pPatch->epairs;
577  }
578  return patch;
579  }
580  else {
581  idMapBrush *mapbrush = new idMapBrush;
582  for ( face_t *f = b->brush_faces; f; f = f->next ) {
583  idMapBrushSide *side = new idMapBrushSide;
584 
585  idPlane plane;
586  if ( f->dirty ) {
587  f->planepts[0] -= origin;
588  f->planepts[1] -= origin;
589  f->planepts[2] -= origin;
590  plane.FromPoints( f->planepts[0], f->planepts[1], f->planepts[2], false );
591  f->planepts[0] += origin;
592  f->planepts[1] += origin;
593  f->planepts[2] += origin;
594  } else {
595  plane = f->originalPlane;
596  }
597  side->SetPlane( plane );
598  side->SetMaterial( f->d_texture->GetName() );
599  idVec3 mat[2];
600  mat[0][0] = f->brushprimit_texdef.coords[0][0];
601  mat[0][1] = f->brushprimit_texdef.coords[0][1];
602  mat[0][2] = f->brushprimit_texdef.coords[0][2];
603  mat[1][0] = f->brushprimit_texdef.coords[1][0];
604  mat[1][1] = f->brushprimit_texdef.coords[1][1];
605  mat[1][2] = f->brushprimit_texdef.coords[1][2];
606  side->SetTextureMatrix(mat);
607  mapbrush->AddSide(side);
608  mapbrush->epairs = b->epairs;
609  }
610  return mapbrush;
611  }
612 }
613 
614 idMapEntity *EntityToMapEntity(entity_t *e, bool use_region, CWaitDlg *dlg) {
615  idMapEntity *mapent = new idMapEntity;
616  mapent->epairs = e->epairs;
617  idStr status;
618  int count = 0;
619  long lastUpdate = 0;
620  if ( !EntityHasModel( e ) ) {
621  for ( brush_t *b = e->brushes.onext; b != &e->brushes; b = b->onext ) {
622  count++;
623  if ( e->eclass->fixedsize && !b->entityModel ) {
624  continue;
625  }
626  if ( !use_region || !Map_IsBrushFiltered( b ) ) {
627  // Update 20 times a second
628  if ( GetTickCount() - lastUpdate > 50 ) {
629  lastUpdate = GetTickCount();
630  if ( b->pPatch ) {
631  sprintf( status, "Adding primitive %i (patch)", count );
632  dlg->SetText( status, true );
633  } else {
634  sprintf( status, "Adding primitive %i (brush)", count );
635  dlg->SetText( status, true );
636  }
637  }
639  if ( prim ) {
640  mapent->AddPrimitive( prim );
641  }
642  }
643  }
644  }
645  return mapent;
646 }
647 
648 /*
649  =======================================================================================================================
650  Map_SaveFile
651  =======================================================================================================================
652  */
653 bool Map_SaveFile(const char *filename, bool use_region, bool autosave) {
654  entity_t *e, *next;
655  idStr temp;
656  int count;
657  brush_t *b;
658  idStr status;
659 
660  int len = strlen(filename);
661  WIN32_FIND_DATA FileData;
662  if (FindFirstFile(filename, &FileData) != INVALID_HANDLE_VALUE) {
663  // the file exists;
664  if (len > 0 && GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY) {
665  g_pParentWnd->MessageBox("File is read only", "Read Only", MB_OK);
666  return false;
667  }
668  }
669 
670  if (filename == NULL || len == 0 || (filename && stricmp(filename, "unnamed.map") == 0)) {
671  CFileDialog dlgSave(FALSE,"map",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"Map Files (*.map)|*.map||",AfxGetMainWnd());
672  if (dlgSave.DoModal() == IDOK) {
673  filename = dlgSave.m_ofn.lpstrFile;
674  strcpy(currentmap, filename);
675  }
676  else {
677  return false;
678  }
679  }
680 
681  MEMORYSTATUSEX statex;
682  statex.dwLength = sizeof (statex);
683  GlobalMemoryStatusEx (&statex);
684  if ( statex.dwMemoryLoad > 95 ) {
685  g_pParentWnd->MessageBox("Physical memory is over 95% utilized. Consider saving and restarting", "Memory");
686  }
687 
688  CWaitDlg dlg;
689  Pointfile_Clear();
690 
691  temp = filename;
692  temp.BackSlashesToSlashes();
693 
694  if ( !use_region ) {
695  idStr backup;
696  backup = temp;
697  backup.StripFileExtension();
698  backup.SetFileExtension( ".bak" );
699  if ( _unlink(backup) != 0 && errno != 2 ) { // errno 2 means the file doesn't exist, which we don't care about
700  g_pParentWnd->MessageBox( va("Unable to delete %s: %s", backup.c_str(), strerror(errno) ), "File Error" );
701  }
702 
703  if ( rename(filename, backup) != 0 ) {
704  g_pParentWnd->MessageBox( va("Unable to rename %s to %s: %s", filename, backup.c_str(), strerror(errno) ), "File Error" );
705  }
706  }
707 
708  common->Printf("Map_SaveFile: %s\n", filename);
709 
710  idStr mapFile;
711  bool localFile = (strstr(filename, ":") != NULL);
712  if (autosave || localFile) {
713  mapFile = filename;
714  } else {
715  mapFile = fileSystem->OSPathToRelativePath( filename );
716  }
717 
718  if (use_region) {
720  }
721 
722  idMapFile map;
723  world_entity->origin.Zero();
724  idMapEntity *mapentity = EntityToMapEntity(world_entity, use_region, &dlg);
725  dlg.SetText("Saving worldspawn...");
726  map.AddEntity(mapentity);
727 
728  if ( use_region ) {
729  idStr buf;
730  sprintf( buf, "{\n\"classname\" \"info_player_start\"\n\"origin\"\t \"%i %i %i\"\n\"angle\"\t \"%i\"\n}\n",
731  (int)g_pParentWnd->GetCamera()->Camera().origin[0],
736  src.LoadMemory( buf, buf.Length(), "regionbuf" );
737  idMapEntity *playerstart = idMapEntity::Parse( src );
738  map.AddEntity( playerstart );
739  }
740 
741  count = -1;
742  for ( e = entities.next; e != &entities; e = next ) {
743  count++;
744  next = e->next;
745  if (e->brushes.onext == &e->brushes) {
746  Entity_Free(e); // no brushes left, so remove it
747  }
748  else {
749  if (use_region) {
750  for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
751  if (!Map_IsBrushFiltered(b)) {
752  break; // got one
753  }
754  }
755 
756  if (b == &e->brushes) {
757  continue; // nothing visible
758  }
759 
760  }
761  idVec3 origin;
762  if (!GetVectorForKey(e, "origin", origin)) {
763  idStr text;
764  VectorSubtract(e->brushes.onext->mins, e->eclass->mins, origin);
765  sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
766  SetKeyValue(e, "origin", text);
767  }
768 
769  if (use_region && !idStr::Icmp(ValueForKey(e, "classname"), "info_player_start")) {
770  continue;
771  }
772 
773  idStr classname = e->epairs.GetString("classname");
774  sprintf(status, "Saving entity %i (%s)...", count, classname.c_str());
775  dlg.SetText(status);
776 
777  map.AddEntity(EntityToMapEntity(e, use_region, &dlg));
778  count++;
779  }
780  }
781 
782  mapFile.StripFileExtension();
783  idStr mapExt = (use_region) ? ".reg" : ".map";
784  sprintf(status, "Writing file %s.%s...", mapFile.c_str(), mapExt.c_str());
785  dlg.SetText(status);
786  map.Write(mapFile, mapExt, !(autosave || localFile));
787  mapModified = 0;
788 
789  if (use_region) {
791  }
792 
793  if (!strstr(temp, "autosave")) {
794  Sys_SetTitle(temp);
795  }
796 
797  Sys_Status("Saved.\n", 0);
798 
799  return true;
800 }
801 
802 /*
803  =======================================================================================================================
804  Map_New
805  =======================================================================================================================
806  */
807 void Map_New(void) {
808  common->Printf("Map_New\n");
809  Map_Free();
810 
811  Patch_Cleanup();
813 
814  world_entity = Entity_New();
815  world_entity->brushes.onext = world_entity->brushes.oprev = &world_entity->brushes;
816  SetKeyValue(world_entity, "classname", "worldspawn");
817  world_entity->eclass = Eclass_ForName("worldspawn", true);
818 
822  g_pParentWnd->GetCamera()->Camera().origin[2] = 48;
824 
826 
827  Sys_UpdateWindows(W_ALL);
828  mapModified = 0;
829 
830  g_qeglobals.mapVersion = MAP_VERSION;
831 
832 }
833 
834 
838 
839 brush_t *region_sides[6];
840 
841 /*
842  =======================================================================================================================
843  AddRegionBrushes a regioned map will have temp walls put up at the region boundary
844  =======================================================================================================================
845  */
846 void AddRegionBrushes(void) {
847  idVec3 mins, maxs;
848  int i;
849  texdef_t td;
850 
851  if (!region_active) {
852  return;
853  }
854 
855  memset(&td, 0, sizeof(td));
856  td = g_qeglobals.d_texturewin.texdef;
857 
858  // strcpy (td.name, "REGION");
859  td.SetName("textures/REGION");
860 
861 const int REGION_WIDTH = 1024;
862 
863 
864  mins[0] = region_mins[0] - REGION_WIDTH;
865  maxs[0] = region_mins[0] + 1;
866  mins[1] = region_mins[1] - REGION_WIDTH;
867  maxs[1] = region_maxs[1] + REGION_WIDTH;
868  mins[2] = MIN_WORLD_COORD;
869  maxs[2] = MAX_WORLD_COORD;
870  region_sides[0] = Brush_Create(mins, maxs, &td);
871 
872 
873  mins[0] = region_maxs[0] - 1;
874  maxs[0] = region_maxs[0] + REGION_WIDTH;
875  region_sides[1] = Brush_Create(mins, maxs, &td);
876 
877  mins[0] = region_mins[0] - REGION_WIDTH;
878  maxs[0] = region_maxs[0] + REGION_WIDTH;
879  mins[1] = region_mins[1] - REGION_WIDTH;
880  maxs[1] = region_mins[1] + 1;
881  region_sides[2] = Brush_Create(mins, maxs, &td);
882 
883  mins[1] = region_maxs[1] - 1;
884  maxs[1] = region_maxs[1] + REGION_WIDTH;
885  region_sides[3] = Brush_Create(mins, maxs, &td);
886 
887  mins = region_mins;
888  maxs = region_maxs;
889  maxs[2] = mins[2] + REGION_WIDTH;
890  region_sides[4] = Brush_Create(mins, maxs, &td);
891 
892  mins = region_mins;
893  maxs = region_maxs;
894  mins[2] = maxs[2] - REGION_WIDTH;
895  region_sides[5] = Brush_Create(mins, maxs, &td);
896 
897  for (i = 0; i < 6; i++) {
899  Entity_LinkBrush(world_entity, region_sides[i]);
901  }
902 }
903 
904 /*
905  =======================================================================================================================
906  =======================================================================================================================
907  */
909  int i;
910 
911  if (!region_active) {
912  return;
913  }
914 
915  for (i = 0; i < 6; i++) {
917  }
918 }
919 
920 /*
921  =======================================================================================================================
922  =======================================================================================================================
923  */
924 bool Map_IsBrushFiltered(brush_t *b) {
925  int i;
926 
927  if (!region_active) {
928  return false;
929  }
930 
931  for (i = 0; i < 3; i++) {
932  if (b->mins[i] > region_maxs[i]) {
933  return true;
934  }
935 
936  if (b->maxs[i] < region_mins[i]) {
937  return true;
938  }
939  }
940 
941  return false;
942 }
943 
944 /*
945  =======================================================================================================================
946  Map_RegionOff Other filtering options may still be on
947  =======================================================================================================================
948  */
949 void Map_RegionOff(void) {
950  brush_t *b, *next;
951  int i;
952 
953  region_active = false;
954  for (i = 0; i < 3; i++) {
955  region_maxs[i] = MAX_WORLD_COORD; // 4096;
956  region_mins[i] = MIN_WORLD_COORD; // -4096;
957  }
958 
959  for (b = filtered_brushes.next; b != &filtered_brushes; b = next) {
960  next = b->next;
961  if (Map_IsBrushFiltered(b)) {
962  continue; // still filtered
963  }
964 
966  if (active_brushes.next == NULL || active_brushes.prev == NULL) {
969  }
970 
972  }
973 
974  Sys_UpdateWindows(W_ALL);
975 }
976 
977 /*
978  =======================================================================================================================
979  =======================================================================================================================
980  */
981 void Map_ApplyRegion(void) {
982  brush_t *b, *next;
983 
984  region_active = true;
985  for (b = active_brushes.next; b != &active_brushes; b = next) {
986  next = b->next;
987  if (!Map_IsBrushFiltered(b)) {
988  continue; // still filtered
989  }
990 
993  }
994 
995  Sys_UpdateWindows(W_ALL);
996 }
997 
998 /*
999  =======================================================================================================================
1000  Map_RegionSelectedBrushes
1001  =======================================================================================================================
1002  */
1004  Map_RegionOff();
1005 
1006  if (selected_brushes.next == &selected_brushes) { // nothing selected
1007  Sys_Status("Tried to region with no selection...\n");
1008  return;
1009  }
1010 
1011  region_active = true;
1012  Select_GetBounds(region_mins, region_maxs);
1013 
1014  // move the entire active_brushes list to filtered_brushes
1015  filtered_brushes.next = active_brushes.next;
1016  filtered_brushes.prev = active_brushes.prev;
1017  filtered_brushes.next->prev = &filtered_brushes;
1018  filtered_brushes.prev->next = &filtered_brushes;
1019 
1020  Patch_Deselect();
1021  // move the entire selected_brushes list to active_brushes
1022  active_brushes.next = selected_brushes.next;
1023  active_brushes.prev = selected_brushes.prev;
1024  active_brushes.next->prev = &active_brushes;
1025  active_brushes.prev->next = &active_brushes;
1026 
1027  // clear selected_brushes
1029 
1030  Sys_UpdateWindows(W_ALL);
1031 }
1032 
1033 /*
1034  =======================================================================================================================
1035  Map_RegionXY
1036  =======================================================================================================================
1037  */
1038 void Map_RegionXY(void) {
1039  Map_RegionOff();
1040 
1041  region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] -
1042  0.5 *
1043  g_pParentWnd->GetXYWnd()->Width() /
1044  g_pParentWnd->GetXYWnd()->Scale();
1045  region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] +
1046  0.5 *
1047  g_pParentWnd->GetXYWnd()->Width() /
1048  g_pParentWnd->GetXYWnd()->Scale();
1049  region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] -
1050  0.5 *
1051  g_pParentWnd->GetXYWnd()->Height() /
1052  g_pParentWnd->GetXYWnd()->Scale();
1053  region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] +
1054  0.5 *
1055  g_pParentWnd->GetXYWnd()->Height() /
1056  g_pParentWnd->GetXYWnd()->Scale();
1059  Map_ApplyRegion();
1060 }
1061 
1062 /*
1063  =======================================================================================================================
1064  Map_RegionTallBrush
1065  =======================================================================================================================
1066  */
1068  brush_t *b;
1069 
1070  if (!QE_SingleBrush()) {
1071  return;
1072  }
1073 
1074  b = selected_brushes.next;
1075 
1076  Map_RegionOff();
1077 
1078  VectorCopy(b->mins, region_mins);
1079  VectorCopy(b->maxs, region_maxs);
1082 
1083  Select_Delete();
1084  Map_ApplyRegion();
1085 }
1086 
1087 /*
1088  =======================================================================================================================
1089  Map_RegionBrush
1090  =======================================================================================================================
1091  */
1092 void Map_RegionBrush(void) {
1093  brush_t *b;
1094 
1095  if (!QE_SingleBrush()) {
1096  return;
1097  }
1098 
1099  b = selected_brushes.next;
1100 
1101  Map_RegionOff();
1102 
1103  VectorCopy(b->mins, region_mins);
1104  VectorCopy(b->maxs, region_maxs);
1105 
1106  Select_Delete();
1107  Map_ApplyRegion();
1108 }
1109 
1110 /*
1111  =======================================================================================================================
1112  =======================================================================================================================
1113  */
1115  // make a unique target value
1116  int maxtarg = 0;
1117  for (entity_t * e = entities.next; e != &entities; e = e->next) {
1118  const char *tn = ValueForKey(e, "name");
1119  if (tn && tn[0]) {
1120  int targetnum = atoi(tn + 1);
1121  if (targetnum > maxtarg) {
1122  maxtarg = targetnum;
1123  }
1124  }
1125  else {
1126  tn = ValueForKey(e, "target");
1127  if (tn && tn[0]) {
1128  int targetnum = atoi(tn + 1);
1129  if (targetnum > maxtarg) {
1130  maxtarg = targetnum;
1131  }
1132  }
1133  }
1134  }
1135 
1136  sprintf(rStr, "t%i", maxtarg + 1);
1137 }
1138 
1139 //
1140 // =======================================================================================================================
1141 // Map_ImportFile Timo 09/01/99:: called by CXYWnd::Paste & Map_ImportFile if Map_ImportFile ( prefab ), the buffer
1142 // may contain brushes in old format ( conversion needed )
1143 // =======================================================================================================================
1144 //
1145 void Map_ImportBuffer(char *buf, bool renameEntities) {
1146  entity_t *ent;
1147  brush_t *b = NULL;
1148  CPtrArray ptrs;
1149 
1150  Select_Deselect();
1151 
1152  Undo_Start("import buffer");
1153 
1154  g_qeglobals.d_parsed_brushes = 0;
1155  if (buf) {
1156  CMapStringToString mapStr;
1157  StartTokenParsing(buf);
1158  g_qeglobals.d_num_entities = 0;
1159 
1160  //
1161  // Timo will be used in Entity_Parse to detect if a conversion between brush
1162  // formats is needed
1163  //
1164  g_qeglobals.bNeedConvert = false;
1165  g_qeglobals.bOldBrushes = false;
1166  g_qeglobals.bPrimitBrushes = false;
1167  g_qeglobals.mapVersion = 1.0;
1168 
1169  if (GetToken(true)) {
1170  if (stricmp(token, "Version") == 0) {
1171  GetToken(false);
1172  g_qeglobals.mapVersion = atof(token);
1173  common->Printf("Map version: %1.2f\n", g_qeglobals.mapVersion);
1174  } else {
1175  UngetToken();
1176  }
1177  }
1178 
1179  idDict RemappedNames; // since I can't use "map <string, string>"... sigh. So much for STL...
1180 
1181  while (1) {
1182  //
1183  // use the selected brushes list as it's handy ent = Entity_Parse (false,
1184  // &selected_brushes);
1185  //
1186  ent = Entity_Parse(false, &active_brushes);
1187  if (!ent) {
1188  break;
1189  }
1190 
1191  // end entity for undo
1192  Undo_EndEntity(ent);
1193 
1194  // end brushes for undo
1195  for (b = ent->brushes.onext; b && b != &ent->brushes; b = b->onext) {
1196  Undo_EndBrush(b);
1197  }
1198 
1199  if (!strcmp(ValueForKey(ent, "classname"), "worldspawn")) {
1200  // world brushes need to be added to the current world entity
1201  b = ent->brushes.onext;
1202  while (b && b != &ent->brushes) {
1203  brush_t *bNext = b->onext;
1204  Entity_UnlinkBrush(b);
1205  Entity_LinkBrush(world_entity, b);
1206  ptrs.Add(b);
1207  b = bNext;
1208  }
1209  }
1210  else {
1211  // the following bit remaps conflicting target/targetname key/value pairs
1212  CString str = ValueForKey(ent, "target");
1213  CString strKey;
1214  CString strTarget("");
1215  if (str.GetLength() > 0) {
1216  if (FindEntity("target", str.GetBuffer(0))) {
1217  if (!mapStr.Lookup(str, strKey)) {
1218  idStr key;
1219  UniqueTargetName(key);
1220  strKey = key;
1221  mapStr.SetAt(str, strKey);
1222  }
1223 
1224  strTarget = strKey;
1225  SetKeyValue(ent, "target", strTarget.GetBuffer(0));
1226  }
1227  }
1228 
1229  /*
1230  * str = ValueForKey(ent, "name"); if (str.GetLength() > 0) { if
1231  * (FindEntity("name", str.GetBuffer(0))) { if (!mapStr.Lookup(str, strKey)) {
1232  * UniqueTargetName(strKey); mapStr.SetAt(str, strKey); } Entity_SetName(ent,
1233  * strKey.GetBuffer(0)); } }
1234  */
1235  CString cstrNameOld = ValueForKey(ent, "name");
1236  Entity_Name(ent, renameEntities);
1237  CString cstrNameNew = ValueForKey(ent, "name");
1238  if (cstrNameOld != cstrNameNew)
1239  {
1240  RemappedNames.Set(cstrNameOld, cstrNameNew);
1241  }
1242  //
1243  // if (strTarget.GetLength() > 0) SetKeyValue(ent, "target",
1244  // strTarget.GetBuffer(0));
1245  // add the entity to the end of the entity list
1246  //
1247  ent->next = &entities;
1248  ent->prev = entities.prev;
1249  entities.prev->next = ent;
1250  entities.prev = ent;
1251  g_qeglobals.d_num_entities++;
1252 
1253  for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
1254  ptrs.Add(b);
1255  }
1256  }
1257  }
1258 
1259  // now iterate through the remapped names, and see if there are any target-connections that need remaking...
1260  //
1261  // (I could probably write this in half the size with STL, but WTF, work with what we have...)
1262  //
1263  int iNumKeyVals = RemappedNames.GetNumKeyVals();
1264  for (int iKeyVal=0; iKeyVal < iNumKeyVals; iKeyVal++)
1265  {
1266  const idKeyValue *pKeyVal = RemappedNames.GetKeyVal( iKeyVal );
1267 
1268  LPCSTR psOldName = pKeyVal->GetKey().c_str();
1269  LPCSTR psNewName = pKeyVal->GetValue().c_str();
1270 
1271  entity_t *pEntOld = FindEntity("name", psOldName); // original ent we cloned from
1272  entity_t *pEntNew = FindEntity("name", psNewName); // cloned ent
1273 
1274  if (pEntOld && pEntNew)
1275  {
1276  CString cstrTargetNameOld = ValueForKey(pEntOld, "target");
1277  if (!cstrTargetNameOld.IsEmpty())
1278  {
1279  // ok, this ent was targeted at another ent, so it's clone needs updating to point to
1280  // the clone of that target, so...
1281  //
1282  entity_t *pEntOldTarget = FindEntity("name", cstrTargetNameOld);
1283  if ( pEntOldTarget )
1284  {
1285  LPCSTR psNewTargetName = RemappedNames.GetString( cstrTargetNameOld );
1286  if (psNewTargetName && psNewTargetName[0])
1287  {
1288  SetKeyValue(pEntNew, "target", psNewTargetName);
1289  }
1290  }
1291  }
1292  }
1293  }
1294  }
1295 
1296  //
1297  // ::ShowWindow(g_qeglobals.d_hwndEntity, FALSE);
1298  // ::LockWindowUpdate(g_qeglobals.d_hwndEntity);
1299  //
1300  g_bScreenUpdates = false;
1301  for (int i = 0; i < ptrs.GetSize(); i++) {
1302  Brush_Build(reinterpret_cast < brush_t * > (ptrs[i]), true, false);
1303  Select_Brush(reinterpret_cast < brush_t * > (ptrs[i]), true, false);
1304  }
1305 
1306  // ::LockWindowUpdate(NULL);
1307  g_bScreenUpdates = true;
1308 
1309  ptrs.RemoveAll();
1310 
1311  //
1312  // reset the "need conversion" flag conversion to the good format done in
1313  // Map_BuildBrushData
1314  //
1315  g_qeglobals.bNeedConvert = false;
1316 
1317  Sys_UpdateWindows(W_ALL);
1318 
1319  // Sys_MarkMapModified();
1320  mapModified = 1;
1321 
1322  Undo_End();
1323 }
1324 
1325 //
1326 // =======================================================================================================================
1327 // Map_ImportFile
1328 // =======================================================================================================================
1329 //
1330 void Map_ImportFile(char *fileName) {
1331  char *buf;
1332  idStr temp;
1333  Sys_BeginWait();
1334  temp = fileName;
1335  temp.BackSlashesToSlashes();
1336  if (LoadFile( temp, (void **) &buf) != -1) {
1337  Map_ImportBuffer(buf);
1338  Mem_Free( buf );
1340  }
1341 
1342  Sys_UpdateWindows(W_ALL);
1343  mapModified = 1;
1344  Sys_EndWait();
1345 }
1346 
1347 //
1348 // =======================================================================================================================
1349 // Map_SaveSelected Saves selected world brushes and whole entities with partial/full selections
1350 // =======================================================================================================================
1351 //
1352 void Map_SaveSelected(char *fileName) {
1353  entity_t *e, *next;
1354  FILE *f;
1355  idStr temp;
1356  int count;
1357 
1358  temp = fileName;
1359  temp.BackSlashesToSlashes();
1360  f = fopen(temp, "w");
1361 
1362  if ( !f ) {
1363  common->Printf( "ERROR!!!! Couldn't open %s\n", temp.c_str() );
1364  return;
1365  }
1366 
1367  // write version
1368  g_qeglobals.mapVersion = MAP_VERSION;
1369  fprintf( f, "Version %1.2f\n", MAP_VERSION );
1370 
1371  // write world entity second
1372  world_entity->origin.Zero();
1373  Entity_WriteSelected( world_entity, f );
1374 
1375  // then write all other ents
1376  count = 1;
1377  for ( e = entities.next; e != &entities; e = next ) {
1378  fprintf( f, "// entity %i\n", count );
1379  count++;
1380  Entity_WriteSelected( e, f );
1381  next = e->next;
1382  }
1383 
1384  fclose( f );
1385 }
1386 
1387 //
1388 // =======================================================================================================================
1389 // Map_SaveSelected Saves selected world brushes and whole entities with partial/full selections
1390 // =======================================================================================================================
1391 //
1392 void Map_SaveSelected(CMemFile *pMemFile, CMemFile *pPatchFile) {
1393  entity_t *e, *next;
1394  int count;
1395  CString strTemp;
1396 
1397  // write version
1398  g_qeglobals.mapVersion = MAP_VERSION;
1399  MemFile_fprintf(pMemFile, "Version %1.2f\n", MAP_VERSION);
1400 
1401  // write world entity first
1402  world_entity->origin.Zero();
1403  Entity_WriteSelected(world_entity, pMemFile);
1404 
1405  // then write all other ents
1406  count = 1;
1407  for (e = entities.next; e != &entities; e = next) {
1408  MemFile_fprintf(pMemFile, "// entity %i\n", count);
1409  count++;
1410  Entity_WriteSelected(e, pMemFile);
1411  next = e->next;
1412  }
1413 
1414  // if (pPatchFile) Patch_WriteFile(pPatchFile);
1415 }
1416 
1417 /*
1418  =======================================================================================================================
1419  =======================================================================================================================
1420  */
1421 
1422 /*
1423 ================
1424 WriteFileString
1425 ================
1426 */
1427 bool WriteFileString( FILE *fp, char *string, ... ) {
1428  long i;
1429  unsigned long u;
1430  double f;
1431  char *str;
1432  idStr buf;
1433  va_list argPtr;
1434 
1435  va_start( argPtr, string );
1436 
1437  while( *string ) {
1438  switch( *string ) {
1439  case '%':
1440  string++;
1441  while ( (*string >= '0' && *string <= '9') ||
1442  *string == '.' || *string == '-' || *string == '+' || *string == '#') {
1443  string++;
1444  }
1445  switch( *string ) {
1446  case 'f':
1447  case 'e':
1448  case 'E':
1449  case 'g':
1450  case 'G':
1451  f = va_arg( argPtr, double );
1452  sprintf( buf, "%1.10f", f );
1453  buf.StripTrailing( '0' );
1454  buf.StripTrailing( '.' );
1455  fprintf( fp, "%s", buf.c_str() );
1456  break;
1457  case 'd':
1458  case 'i':
1459  i = va_arg( argPtr, long );
1460  fprintf( fp, "%d", i );
1461  break;
1462  case 'u':
1463  u = va_arg( argPtr, unsigned long );
1464  fprintf( fp, "%u", u );
1465  break;
1466  case 'o':
1467  u = va_arg( argPtr, unsigned long );
1468  fprintf( fp, "%o", u );
1469  break;
1470  case 'x':
1471  u = va_arg( argPtr, unsigned long );
1472  fprintf( fp, "%x", u );
1473  break;
1474  case 'X':
1475  u = va_arg( argPtr, unsigned long );
1476  fprintf( fp, "%X", u );
1477  break;
1478  case 'c':
1479  i = va_arg( argPtr, long );
1480  fprintf( fp, "%c", (char) i );
1481  break;
1482  case 's':
1483  str = va_arg( argPtr, char * );
1484  fprintf( fp, "%s", str );
1485  break;
1486  case '%':
1487  fprintf( fp, "%%" );
1488  break;
1489  default:
1490  common->Error( "WriteFileString: invalid %%%c", *string );
1491  break;
1492  }
1493  string++;
1494  break;
1495  case '\\':
1496  string++;
1497  switch( *string ) {
1498  case 't':
1499  fprintf( fp, "\t" );
1500  break;
1501  case 'n':
1502  fprintf( fp, "\n" );
1503  default:
1504  common->Error( "WriteFileString: unknown escape character \'%c\'", *string );
1505  break;
1506  }
1507  string++;
1508  break;
1509  default:
1510  fprintf( fp, "%c", *string );
1511  string++;
1512  break;
1513  }
1514  }
1515 
1516  va_end( argPtr );
1517 
1518  return true;
1519 }
1520 
1521 /*
1522 ================
1523 MemFile_fprintf
1524 ================
1525 */
1526 void MemFile_fprintf( CMemFile *pMemFile, const char *string, ... ) {
1527  char Buffer[4096];
1528  long i;
1529  unsigned long u;
1530  double f;
1531  char *str;
1532  idStr buf, out;
1533  va_list argPtr;
1534 
1535  char *buff = Buffer;
1536 
1537  va_start( argPtr, string );
1538 
1539  while( *string ) {
1540  switch( *string ) {
1541  case '%':
1542  string++;
1543  while ( (*string >= '0' && *string <= '9') ||
1544  *string == '.' || *string == '-' || *string == '+' || *string == '#') {
1545  string++;
1546  }
1547  switch( *string ) {
1548  case 'f':
1549  case 'e':
1550  case 'E':
1551  case 'g':
1552  case 'G':
1553  f = va_arg( argPtr, double );
1554  sprintf( buf, "%1.10f", f );
1555  buf.StripTrailing( '0' );
1556  buf.StripTrailing( '.' );
1557  sprintf( buff, "%s", buf.c_str() );
1558  break;
1559  case 'd':
1560  case 'i':
1561  i = va_arg( argPtr, long );
1562  sprintf( buff, "%d", i );
1563  break;
1564  case 'u':
1565  u = va_arg( argPtr, unsigned long );
1566  sprintf( buff, "%u", u );
1567  break;
1568  case 'o':
1569  u = va_arg( argPtr, unsigned long );
1570  sprintf( buff, "%o", u );
1571  break;
1572  case 'x':
1573  u = va_arg( argPtr, unsigned long );
1574  sprintf( buff, "%x", u );
1575  break;
1576  case 'X':
1577  u = va_arg( argPtr, unsigned long );
1578  sprintf( buff, "%X", u );
1579  break;
1580  case 'c':
1581  i = va_arg( argPtr, long );
1582  sprintf( buff, "%c", (char) i );
1583  break;
1584  case 's':
1585  str = va_arg( argPtr, char * );
1586  sprintf( buff, "%s", str );
1587  break;
1588  case '%':
1589  sprintf( buff, "%%" );
1590  break;
1591  default:
1592  common->Error( "MemFile_fprintf: invalid %%%c", *string );
1593  break;
1594  }
1595  string++;
1596  break;
1597  case '\\':
1598  string++;
1599  switch( *string ) {
1600  case 't':
1601  sprintf( buff, "\t" );
1602  break;
1603  case 'n':
1604  sprintf( buff, "\n" );
1605  default:
1606  common->Error( "MemFile_fprintf: unknown escape character \'%c\'", *string );
1607  break;
1608  }
1609  string++;
1610  break;
1611  default:
1612  sprintf( buff, "%c", *string );
1613  string++;
1614  break;
1615  }
1616 
1617  buff = Buffer + strlen(Buffer);
1618  }
1619 
1620  va_end( argPtr );
1621 
1622  out = Buffer;
1623  pMemFile->Write( out.c_str(), out.Length() );
1624 }
CMainFrame * g_pParentWnd
Definition: MainFrm.cpp:73
int GetNumSides(void) const
Definition: MapFile.h:106
CEntityDlg entityDlg
const idPlane & GetPlane(void) const
Definition: MapFile.h:78
#define strcmp
Definition: Str.h:41
bool Entity_NameIsUnique(const char *name)
Definition: EditorMap.cpp:194
int GetType(void) const
Definition: MapFile.h:63
int Height()
Definition: XYWnd.h:158
#define stricmp
Definition: Str.h:64
void WINAPI Sys_UpdateWindows(int nBits)
Definition: MainFrm.cpp:3974
idMapEntity * GetEntity(int i) const
Definition: MapFile.h:198
entity_t * world_entity
Definition: EditorMap.cpp:49
face_t * Face_Alloc(void)
idStr & SetFileExtension(const char *extension)
Definition: Str.cpp:743
int mapModified
Definition: EditorMap.cpp:34
void AddPrimitive(idMapPrimitive *p)
Definition: MapFile.h:175
bool FromPoints(const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate=true)
Definition: Plane.h:279
brush_t * Brush_Alloc(void)
idMapBrushSide * GetSide(int i) const
Definition: MapFile.h:108
int GetVertSubdivisions(void) const
Definition: MapFile.h:127
void Map_BuildBrushData(void)
Definition: EditorMap.cpp:121
void Paste()
Definition: XYWnd.cpp:4260
float m_fTinySize
Definition: PrefsDlg.h:75
bool CheckForTinyBrush(brush_t *b, int n, float fSize)
Definition: EditorMap.cpp:102
brush_t selected_brushes
Definition: EditorMap.cpp:40
bool WriteFileString(FILE *fp, char *string,...)
Definition: EditorMap.cpp:1427
void Entity_Free(entity_t *e)
brush_t active_brushes
Definition: EditorMap.cpp:39
int AddSide(idMapBrushSide *side)
Definition: MapFile.h:107
const idStr & GetKey(void) const
Definition: Dict.h:52
void Entity_UnlinkBrush(brush_t *b)
entity_t between_entities
Definition: EditorMap.cpp:67
#define VectorSubtract(a, b, c)
Definition: Vector.h:1995
void SetExplicitlySubdivided(bool b)
Definition: MapFile.h:131
int Length(void) const
Definition: Str.h:702
DWORD
Definition: win_qgl.cpp:61
void Undo_EndBrush(brush_t *pBrush)
Definition: Undo.cpp:450
bool Map_SaveFile(const char *filename, bool use_region, bool autosave)
Definition: EditorMap.cpp:653
GLenum GLsizei n
Definition: glext.h:3705
float z
Definition: Vector.h:320
void StripTrailing(const char c)
Definition: Str.cpp:515
void Map_ImportBuffer(char *buf, bool renameEntities)
Definition: EditorMap.cpp:1145
case const int
Definition: Callbacks.cpp:52
void AllowCancel(bool enable)
Definition: WaitDlg.cpp:109
#define VectorCopy(a, b)
Definition: Vector.h:1999
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
brush_t * BrushFromMapBrush(idMapBrush *mapbrush, idVec3 origin)
Definition: EditorMap.cpp:321
void Map_RegionBrush(void)
Definition: EditorMap.cpp:1092
#define MAX_WORLD_COORD
Definition: Lib.h:98
idVec3 origin
Definition: EditorEntity.h:37
void Sys_Status(const char *psz, int part)
Definition: Radiant.cpp:465
CXYWnd * ActiveXY()
Definition: MainFrm.cpp:4034
camera_t & Camera()
Definition: CamWnd.h:90
int GetHorzSubdivisions(void) const
Definition: MapFile.h:126
const char * ValueForKey(entity_t *ent, const char *key)
Definition: Vector.h:316
void Map_ImportFile(char *fileName)
Definition: EditorMap.cpp:1330
void Brush_Free(brush_t *b, bool bRemoveNode)
void Map_ApplyRegion(void)
Definition: EditorMap.cpp:981
entity_t * Map_FindClass(char *cname)
Definition: EditorMap.cpp:147
const char * GetMaterial(void) const
Definition: MapFile.h:124
brush_t * selected_face_brush
Definition: EditorMap.cpp:43
idAngles angles
Definition: CamWnd.h:49
void MemFile_fprintf(CMemFile *pMemFile, const char *string,...)
Definition: EditorMap.cpp:1526
GLuint src
Definition: glext.h:5390
GLenum GLsizei len
Definition: glext.h:3472
void Set(const char *key, const char *value)
Definition: Dict.cpp:275
CXYWnd * GetXYWnd()
Definition: MainFrm.h:120
void Texture_ClearInuse(void)
Definition: NewTexWnd.cpp:673
void UniqueTargetName(idStr &rStr)
Definition: EditorMap.cpp:1114
float x
Definition: Vector.h:318
int i
Definition: process.py:33
void Undo_Start(char *operation)
Definition: Undo.cpp:362
int Cmpn(const char *text, int n) const
Definition: Str.h:657
entity_t * Entity_Parse(bool onlypairs, brush_t *pList)
brush_t brushes
Definition: EditorEntity.h:35
void Brush_Build(brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool updateLights)
void Undo_EndEntity(entity_t *entity)
Definition: Undo.cpp:525
int Icmp(const char *text) const
Definition: Str.h:667
void Map_RegionXY(void)
Definition: EditorMap.cpp:1038
idStr & BackSlashesToSlashes(void)
Definition: Str.cpp:727
#define MIN_WORLD_COORD
Definition: Lib.h:99
idDict epairs
Definition: MapFile.h:166
void SetKeyValue(entity_t *ent, const char *key, const char *value, bool trackAngles)
entity_t * Entity_New()
bool g_bRestoreBetween
Definition: EditorMap.cpp:69
int GetHeight(void) const
idVec3 region_maxs(MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD)
bool CancelPressed(void)
Definition: WaitDlg.cpp:120
brush_t * region_sides[6]
Definition: EditorMap.cpp:839
Definition: Lexer.h:137
void BuildRendererState()
Definition: CamWnd.cpp:1707
void ExtractFileName(idStr &dest) const
Definition: Str.cpp:921
GLuint GLuint GLsizei count
Definition: glext.h:2845
void SetPlane(const idPlane &p)
Definition: MapFile.h:79
CCamWnd * GetCamera()
Definition: MainFrm.h:123
void SetMaterial(const char *p)
Definition: MapFile.h:77
bool region_active
Definition: EditorMap.cpp:835
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
bool EntityHasModel(entity_t *ent)
idStr & StripFileExtension(void)
Definition: Str.cpp:757
const idMaterial * Texture_ForName(const char *name)
Definition: NewTexWnd.cpp:700
static idMapEntity * Parse(idLexer &src, bool worldSpawn=false, float version=CURRENT_MAP_VERSION)
Definition: MapFile.cpp:538
void Brush_AddToList(brush_t *b, brush_t *list)
int GetNumEntities(void) const
Definition: MapFile.h:196
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
bool Parse(const char *filename, bool ignoreRegion=false, bool osPath=false)
Definition: MapFile.cpp:720
idMapPrimitive * BrushToMapPrimitive(const brush_t *b, const idVec3 &origin)
Definition: EditorMap.cpp:559
void SetEditEntity(entity_t *ent)
Definition: EntityDlg.h:47
void Pointfile_Clear(void)
Definition: PointFile.cpp:154
idCommon * common
Definition: Common.cpp:206
void Copy()
Definition: XYWnd.cpp:4142
Definition: Dict.h:65
struct entity_s * prev
Definition: EditorEntity.h:34
#define NULL
Definition: Lib.h:88
entity_t * EntityFromMapEntity(idMapEntity *mapent, CWaitDlg *dlg)
Definition: EditorMap.cpp:368
bool GetRenderMode()
Definition: CamWnd.h:104
bool Write(const char *fileName, const char *ext, bool fromBasePath=true)
Definition: MapFile.cpp:833
float y
Definition: Vector.h:319
void GetTextureMatrix(idVec3 &mat1, idVec3 &mat2)
Definition: MapFile.h:81
idDict epairs
Definition: MapFile.h:59
struct entity_s * next
Definition: EditorEntity.h:34
Definition: Plane.h:71
void RemoveRegionBrushes(void)
Definition: EditorMap.cpp:908
void SetText(const char *msg, bool append=false)
Definition: WaitDlg.cpp:94
bool GetExplicitlySubdivided(void) const
Definition: MapFile.h:128
brush_t filtered_brushes
Definition: EditorMap.cpp:45
const idStr & GetValue(void) const
Definition: Dict.h:53
void SetVertSubdivisions(int n)
Definition: MapFile.h:130
brush_t between_brushes
Definition: EditorMap.cpp:66
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
void SetMaterial(const char *p)
Definition: MapFile.h:125
void Brush_RemoveFromList(brush_t *b)
int Map_GetUniqueEntityID(const char *prefix, const char *eclass)
Definition: EditorMap.cpp:163
idVec3 origin
Definition: CamWnd.h:48
void Map_Free(void)
Definition: EditorMap.cpp:217
brush_t * BrushFromMapPatch(idMapPatch *mappatch, idVec3 origin)
Definition: EditorMap.cpp:301
virtual void Printf(const char *fmt,...) id_attribute((format(printf
CInspectorDialog * g_Inspectors
idMapEntity * EntityToMapEntity(entity_t *e, bool use_region, CWaitDlg *dlg)
Definition: EditorMap.cpp:614
#define YAW
Definition: Angles.h:42
GLubyte GLubyte b
Definition: glext.h:4662
void Map_SaveBetween(void)
Definition: EditorMap.cpp:75
void Map_RestoreBetween(void)
Definition: EditorMap.cpp:89
void Map_RegionSelectedBrushes(void)
Definition: EditorMap.cpp:1003
bool GetVectorForKey(entity_t *ent, const char *key, idVec3 &vec)
void Entity_LinkBrush(entity_t *e, brush_t *b)
idMapPrimitive * GetPrimitive(int i) const
Definition: MapFile.h:174
void AddRegionBrushes(void)
Definition: EditorMap.cpp:846
void Texture_ShowInuse(void)
Definition: NewTexWnd.cpp:710
tuple f
Definition: idal.py:89
int LoadFile(const char *filename, void **bufferptr)
Definition: cmdlib.cpp:133
entity_t * AngledEntity()
Definition: EditorMap.cpp:271
void Map_LoadFile(const char *filename)
Definition: EditorMap.cpp:424
const GLcharARB * name
Definition: glext.h:3629
entity_t * FindEntity(const char *pszKey, const char *pszValue)
CPrefsDlg & g_PrefsDlg
Definition: MainFrm.cpp:75
entity_t entities
Definition: EditorMap.cpp:47
void BaseForPlane(const idVec3 &normal, const float dist)
Definition: Winding.cpp:66
Definition: Str.h:116
brush_t * Brush_Create(idVec3 mins, idVec3 maxs, texdef_t *texdef)
void Undo_End(void)
Definition: Undo.cpp:552
idDict epairs
Definition: EditorEntity.h:42
void SetTextureMatrix(const idVec3 mat[2])
Definition: MapFile.h:80
face_t * selected_face
Definition: EditorMap.cpp:42
const char * GetMaterial(void) const
Definition: MapFile.h:76
const char * c_str(void) const
Definition: Str.h:487
#define FALSE
Definition: mprintf.c:70
idVec3 region_mins(MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD)
bool g_bScreenUpdates
Definition: MainFrm.cpp:77
void Map_RegionTallBrush(void)
Definition: EditorMap.cpp:1067
void SetHorzSubdivisions(int n)
Definition: MapFile.h:129
const idKeyValue * GetKeyVal(int index) const
Definition: Dict.h:294
char currentmap[1024]
Definition: EditorMap.cpp:37
GLint j
Definition: qgl.h:264
void Map_RegionOff(void)
Definition: EditorMap.cpp:949
void DupLists()
Definition: EditorMap.cpp:58
char * va(const char *fmt,...)
Definition: Str.cpp:1568
int AddEntity(idMapEntity *mapentity)
Definition: MapFile.cpp:885
virtual const char * OSPathToRelativePath(const char *OSPath)=0
virtual void Error(const char *fmt,...) id_attribute((format(printf
int GetNumPrimitives(void) const
Definition: MapFile.h:173
float Scale()
Definition: XYWnd.h:156
void Map_SaveSelected(char *fileName)
Definition: EditorMap.cpp:1352
int Width()
Definition: XYWnd.h:157
float FloatForKey(entity_t *ent, const char *key)
void Entity_WriteSelected(entity_t *e, FILE *f)
int GetNumKeyVals(void) const
Definition: Dict.h:290
void Zero(void)
Definition: Vector.h:415
void SetSize(int patchWidth, int patchHeight)
entity_t * Entity_PostParse(entity_t *ent, brush_t *pList)
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
idVec3 & GetOrigin()
Definition: XYWnd.cpp:3840
void Map_New(void)
Definition: EditorMap.cpp:807
eclass_t * eclass
Definition: EditorEntity.h:41
#define PITCH
Definition: Angles.h:41
int GetWidth(void) const
void Entity_Name(entity_t *e, bool force)
eclass_t * Eclass_ForName(const char *name, bool has_brushes)
bool Map_IsBrushFiltered(brush_t *b)
Definition: EditorMap.cpp:924
void Map_VerifyCurrentMap(const char *map)
Definition: EditorMap.cpp:553
BOOL m_bCleanTiny
Definition: PrefsDlg.h:76