2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
34 int mapModified; // for quit confirmation (0 = clean, 1 = unsaved,
36 // 2 = autosaved, but not regular saved)
37 char currentmap[1024];
39 brush_t active_brushes; // brushes currently being displayed
40 brush_t selected_brushes; // highlighted
42 face_t *selected_face;
43 brush_t *selected_face_brush;
45 brush_t filtered_brushes; // brushes that have been filtered or regioned
47 entity_t entities; // head/tail of doubly linked list
49 entity_t *world_entity = NULL; // "classname" "worldspawn" !
51 void AddRegionBrushes(void);
52 void RemoveRegionBrushes(void);
55 =======================================================================================================================
56 =======================================================================================================================
59 DWORD dw = GetTickCount();
63 * Cross map selection saving this could mess this up if you have only part of a
64 * complex entity selected...
66 brush_t between_brushes;
67 entity_t between_entities;
69 bool g_bRestoreBetween = false;
72 =======================================================================================================================
73 =======================================================================================================================
75 void Map_SaveBetween(void) {
76 if (g_pParentWnd->ActiveXY()) {
77 g_bRestoreBetween = true;
78 g_pParentWnd->ActiveXY()->Copy();
86 =======================================================================================================================
87 =======================================================================================================================
89 void Map_RestoreBetween(void) {
90 if (g_pParentWnd->ActiveXY() && g_bRestoreBetween) {
91 g_pParentWnd->ActiveXY()->Paste();
99 =======================================================================================================================
100 =======================================================================================================================
102 bool CheckForTinyBrush(brush_t *b, int n, float fSize) {
104 for (int i = 0; i < 3; i++) {
105 if (b->maxs[i] - b->mins[i] < fSize) {
111 common->Printf("Possible problem brush (too small) #%i ", n);
118 =======================================================================================================================
119 =======================================================================================================================
121 void Map_BuildBrushData(void) {
124 if (active_brushes.next == NULL) {
128 Sys_BeginWait(); // this could take a while
131 for (b = active_brushes.next; b != NULL && b != &active_brushes; 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))) {
136 common->Printf("Removed degenerate brush\n");
144 =======================================================================================================================
145 =======================================================================================================================
147 entity_t *Map_FindClass(char *cname) {
150 for (ent = entities.next; ent != &entities; ent = ent->next) {
151 if (!strcmp(cname, ValueForKey(ent, "classname"))) {
160 =======================================================================================================================
161 =======================================================================================================================
163 int Map_GetUniqueEntityID(const char *prefix, const char *eclass) {
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]) {
171 if (prefix && *prefix) {
172 buf = va("%s_%s_", prefix, eclass);
174 buf = va("%s_", eclass);
176 int len = strlen(buf);
177 if ( idStr::Cmpn(name, buf, len) == 0 ) {
178 int j = atoi(name + len);
191 =======================================================================================================================
192 =======================================================================================================================
194 bool Entity_NameIsUnique(const char *name) {
200 for (ent = entities.next; ent != &entities; ent = ent->next) {
201 const char *testName = ValueForKey(ent, "name");
203 if ( idStr::Icmp(name, testName) == 0 ) {
213 =======================================================================================================================
215 =======================================================================================================================
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) {
225 // clear all the render and sound system data
226 g_qeglobals.rw->InitFromMap( NULL );
227 g_qeglobals.sw->ClearAllSoundEmitters();
229 Texture_ClearInuse();
231 strcpy(currentmap, "unnamed.map");
232 Sys_SetTitle(currentmap);
233 g_qeglobals.d_num_entities = 0;
235 if (!active_brushes.next) { // first map
236 active_brushes.prev = active_brushes.next = &active_brushes;
237 selected_brushes.prev = selected_brushes.next = &selected_brushes;
238 filtered_brushes.prev = filtered_brushes.next = &filtered_brushes;
240 entities.prev = entities.next = &entities;
243 while (active_brushes.next != &active_brushes) {
244 Brush_Free(active_brushes.next, false);
247 while (selected_brushes.next != &selected_brushes) {
248 Brush_Free(selected_brushes.next, false);
251 while (filtered_brushes.next != &filtered_brushes) {
252 Brush_Free(filtered_brushes.next, false);
255 while (entities.next != &entities) {
256 Entity_Free(entities.next);
261 Entity_Free(world_entity);
268 =======================================================================================================================
269 =======================================================================================================================
271 entity_t *AngledEntity() {
272 entity_t *ent = Map_FindClass("info_player_start");
274 ent = Map_FindClass("info_player_deathmatch");
278 ent = Map_FindClass("info_player_deathmatch");
282 ent = Map_FindClass("team_CTF_redplayer");
286 ent = Map_FindClass("team_CTF_blueplayer");
290 ent = Map_FindClass("team_CTF_redspawn");
294 ent = Map_FindClass("team_CTF_bluespawn");
301 brush_t *BrushFromMapPatch(idMapPatch *mappatch, idVec3 origin) {
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;
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;
317 brush_t *b = AddBrushForPatch(pm, false);
321 brush_t *BrushFromMapBrush(idMapBrush *mapbrush, idVec3 origin) {
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();
330 if (!b->brush_faces) {
335 for (scan = b->brush_faces; scan->next; scan = scan->next) {
340 f->plane = side->GetPlane();
341 f->originalPlane = f->plane;
345 w.BaseForPlane(f->plane);
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;
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];
362 f->texdef.SetName(side->GetMaterial());
368 entity_t *EntityFromMapEntity(idMapEntity *mapent, CWaitDlg *dlg) {
369 entity_t *ent = NULL;
372 ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
374 ent->epairs = mapent->epairs;
375 GetVectorForKey(ent, "origin", ent->origin);
376 int count = mapent->GetNumPrimitives();
379 for (int i = 0; i < count; i++) {
380 idMapPrimitive *prim = mapent->GetPrimitive(i);
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);
390 dlg->SetText(status, true);
392 if ( dlg->CancelPressed() ) {
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);
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;
418 extern entity_t *Entity_PostParse(entity_t *ent, brush_t *pList);
420 =======================================================================================================================
422 =======================================================================================================================
424 void Map_LoadFile(const char *filename) {
427 idStr fileStr, status;
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 );
440 // SetInspectorMode(W_CONSOLE);
442 fileStr.BackSlashesToSlashes();
444 common->Printf( "Map_LoadFile: %s\n", fileStr.c_str() );
448 g_qeglobals.d_parsed_brushes = 0;
449 strcpy( currentmap, filename );
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;
458 int count = mapfile.GetNumEntities();
459 for (int i = 0; i < count; i++) {
460 idMapEntity *mapent = mapfile.GetEntity(i);
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());
469 if ( dlg.CancelPressed() ) {
470 Sys_Status("Map load cancelled.\n");
474 if (classname == "worldspawn") {
475 world_entity = EntityFromMapEntity(mapent, &dlg);
476 Entity_PostParse(world_entity, &active_brushes);
478 ent = EntityFromMapEntity(mapent, &dlg);
479 Entity_PostParse(ent, &active_brushes);
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;
486 g_qeglobals.d_num_entities++;
493 Sys_Status("No worldspawn in map.\n");
498 common->Printf("--- LoadMapFile ---\n");
499 common->Printf("%s\n", fileStr.c_str());
501 common->Printf("%5i brushes\n", g_qeglobals.d_parsed_brushes);
502 common->Printf("%5i entities\n", g_qeglobals.d_num_entities);
504 dlg.SetText("Restoring Between");
505 Map_RestoreBetween();
507 dlg.SetText("Building Brush Data");
508 common->Printf("Map_BuildAllDisplayLists\n");
509 Map_BuildBrushData();
512 // reset the "need conversion" flag conversion to the good format done in
513 // Map_BuildBrushData
515 g_qeglobals.bNeedConvert = false;
517 // move the view to a start position
518 ent = AngledEntity();
520 g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0;
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");
528 g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0;
529 VectorCopy(vec3_origin, g_pParentWnd->GetCamera()->Camera().origin);
530 VectorCopy(vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin());
537 if (GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY) {
538 fileStr += " (read only) ";
540 Sys_SetTitle(fileStr);
544 if (g_pParentWnd->GetCamera()->GetRenderMode()) {
545 g_pParentWnd->GetCamera()->BuildRendererState();
549 Sys_UpdateWindows(W_ALL);
553 void Map_VerifyCurrentMap(const char *map) {
554 if ( idStr::Icmp( map, currentmap ) != 0 ) {
559 idMapPrimitive *BrushToMapPrimitive( const brush_t *b, const idVec3 &origin ) {
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;
569 patch->SetExplicitlySubdivided( b->pPatch->explicitSubdivisions );
570 if ( b->pPatch->explicitSubdivisions ) {
571 patch->SetHorzSubdivisions( b->pPatch->horzSubdivisions );
572 patch->SetVertSubdivisions( b->pPatch->vertSubdivisions );
574 patch->SetMaterial( b->pPatch->d_texture->GetName() );
575 if ( b->pPatch->epairs ) {
576 patch->epairs = *b->pPatch->epairs;
581 idMapBrush *mapbrush = new idMapBrush;
582 for ( face_t *f = b->brush_faces; f; f = f->next ) {
583 idMapBrushSide *side = new idMapBrushSide;
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;
595 plane = f->originalPlane;
597 side->SetPlane( plane );
598 side->SetMaterial( f->d_texture->GetName() );
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;
614 idMapEntity *EntityToMapEntity(entity_t *e, bool use_region, CWaitDlg *dlg) {
615 idMapEntity *mapent = new idMapEntity;
616 mapent->epairs = e->epairs;
620 if ( !EntityHasModel( e ) ) {
621 for ( brush_t *b = e->brushes.onext; b != &e->brushes; b = b->onext ) {
623 if ( e->eclass->fixedsize && !b->entityModel ) {
626 if ( !use_region || !Map_IsBrushFiltered( b ) ) {
627 // Update 20 times a second
628 if ( GetTickCount() - lastUpdate > 50 ) {
629 lastUpdate = GetTickCount();
631 sprintf( status, "Adding primitive %i (patch)", count );
632 dlg->SetText( status, true );
634 sprintf( status, "Adding primitive %i (brush)", count );
635 dlg->SetText( status, true );
638 idMapPrimitive *prim = BrushToMapPrimitive( b, e->origin );
640 mapent->AddPrimitive( prim );
649 =======================================================================================================================
651 =======================================================================================================================
653 bool Map_SaveFile(const char *filename, bool use_region, bool autosave) {
660 int len = strlen(filename);
661 WIN32_FIND_DATA FileData;
662 if (FindFirstFile(filename, &FileData) != INVALID_HANDLE_VALUE) {
664 if (len > 0 && GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY) {
665 g_pParentWnd->MessageBox("File is read only", "Read Only", MB_OK);
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);
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");
692 temp.BackSlashesToSlashes();
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" );
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" );
708 common->Printf("Map_SaveFile: %s\n", filename);
711 bool localFile = (strstr(filename, ":") != NULL);
712 if (autosave || localFile) {
715 mapFile = fileSystem->OSPathToRelativePath( filename );
723 world_entity->origin.Zero();
724 idMapEntity *mapentity = EntityToMapEntity(world_entity, use_region, &dlg);
725 dlg.SetText("Saving worldspawn...");
726 map.AddEntity(mapentity);
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],
732 (int)g_pParentWnd->GetCamera()->Camera().origin[1],
733 (int)g_pParentWnd->GetCamera()->Camera().origin[2],
734 (int)g_pParentWnd->GetCamera()->Camera().angles[YAW] );
735 idLexer src( LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
736 src.LoadMemory( buf, buf.Length(), "regionbuf" );
737 idMapEntity *playerstart = idMapEntity::Parse( src );
738 map.AddEntity( playerstart );
742 for ( e = entities.next; e != &entities; e = next ) {
745 if (e->brushes.onext == &e->brushes) {
746 Entity_Free(e); // no brushes left, so remove it
750 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
751 if (!Map_IsBrushFiltered(b)) {
756 if (b == &e->brushes) {
757 continue; // nothing visible
762 if (!GetVectorForKey(e, "origin", origin)) {
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);
769 if (use_region && !idStr::Icmp(ValueForKey(e, "classname"), "info_player_start")) {
773 idStr classname = e->epairs.GetString("classname");
774 sprintf(status, "Saving entity %i (%s)...", count, classname.c_str());
777 map.AddEntity(EntityToMapEntity(e, use_region, &dlg));
782 mapFile.StripFileExtension();
783 idStr mapExt = (use_region) ? ".reg" : ".map";
784 sprintf(status, "Writing file %s.%s...", mapFile.c_str(), mapExt.c_str());
786 map.Write(mapFile, mapExt, !(autosave || localFile));
790 RemoveRegionBrushes();
793 if (!strstr(temp, "autosave")) {
797 Sys_Status("Saved.\n", 0);
803 =======================================================================================================================
805 =======================================================================================================================
808 common->Printf("Map_New\n");
812 g_Inspectors->entityDlg.SetEditEntity ( NULL );
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);
819 g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0;
820 g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0;
821 VectorCopy(vec3_origin, g_pParentWnd->GetCamera()->Camera().origin);
822 g_pParentWnd->GetCamera()->Camera().origin[2] = 48;
823 VectorCopy(vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin());
825 Map_RestoreBetween();
827 Sys_UpdateWindows(W_ALL);
830 g_qeglobals.mapVersion = MAP_VERSION;
836 idVec3 region_mins(MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD);
837 idVec3 region_maxs(MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD);
839 brush_t *region_sides[6];
842 =======================================================================================================================
843 AddRegionBrushes a regioned map will have temp walls put up at the region boundary
844 =======================================================================================================================
846 void AddRegionBrushes(void) {
851 if (!region_active) {
855 memset(&td, 0, sizeof(td));
856 td = g_qeglobals.d_texturewin.texdef;
858 // strcpy (td.name, "REGION");
859 td.SetName("textures/REGION");
861 const int REGION_WIDTH = 1024;
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);
873 mins[0] = region_maxs[0] - 1;
874 maxs[0] = region_maxs[0] + REGION_WIDTH;
875 region_sides[1] = Brush_Create(mins, maxs, &td);
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);
883 mins[1] = region_maxs[1] - 1;
884 maxs[1] = region_maxs[1] + REGION_WIDTH;
885 region_sides[3] = Brush_Create(mins, maxs, &td);
889 maxs[2] = mins[2] + REGION_WIDTH;
890 region_sides[4] = Brush_Create(mins, maxs, &td);
894 mins[2] = maxs[2] - REGION_WIDTH;
895 region_sides[5] = Brush_Create(mins, maxs, &td);
897 for (i = 0; i < 6; i++) {
898 Brush_AddToList(region_sides[i], &selected_brushes);
899 Entity_LinkBrush(world_entity, region_sides[i]);
900 Brush_Build(region_sides[i]);
905 =======================================================================================================================
906 =======================================================================================================================
908 void RemoveRegionBrushes(void) {
911 if (!region_active) {
915 for (i = 0; i < 6; i++) {
916 Brush_Free(region_sides[i]);
921 =======================================================================================================================
922 =======================================================================================================================
924 bool Map_IsBrushFiltered(brush_t *b) {
927 if (!region_active) {
931 for (i = 0; i < 3; i++) {
932 if (b->mins[i] > region_maxs[i]) {
936 if (b->maxs[i] < region_mins[i]) {
945 =======================================================================================================================
946 Map_RegionOff Other filtering options may still be on
947 =======================================================================================================================
949 void Map_RegionOff(void) {
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;
959 for (b = filtered_brushes.next; b != &filtered_brushes; b = next) {
961 if (Map_IsBrushFiltered(b)) {
962 continue; // still filtered
965 Brush_RemoveFromList(b);
966 if (active_brushes.next == NULL || active_brushes.prev == NULL) {
967 active_brushes.next = &active_brushes;
968 active_brushes.prev = &active_brushes;
971 Brush_AddToList(b, &active_brushes);
974 Sys_UpdateWindows(W_ALL);
978 =======================================================================================================================
979 =======================================================================================================================
981 void Map_ApplyRegion(void) {
984 region_active = true;
985 for (b = active_brushes.next; b != &active_brushes; b = next) {
987 if (!Map_IsBrushFiltered(b)) {
988 continue; // still filtered
991 Brush_RemoveFromList(b);
992 Brush_AddToList(b, &filtered_brushes);
995 Sys_UpdateWindows(W_ALL);
999 =======================================================================================================================
1000 Map_RegionSelectedBrushes
1001 =======================================================================================================================
1003 void Map_RegionSelectedBrushes(void) {
1006 if (selected_brushes.next == &selected_brushes) { // nothing selected
1007 Sys_Status("Tried to region with no selection...\n");
1011 region_active = true;
1012 Select_GetBounds(region_mins, region_maxs);
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;
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;
1027 // clear selected_brushes
1028 selected_brushes.next = selected_brushes.prev = &selected_brushes;
1030 Sys_UpdateWindows(W_ALL);
1034 =======================================================================================================================
1036 =======================================================================================================================
1038 void Map_RegionXY(void) {
1041 region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] -
1043 g_pParentWnd->GetXYWnd()->Width() /
1044 g_pParentWnd->GetXYWnd()->Scale();
1045 region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] +
1047 g_pParentWnd->GetXYWnd()->Width() /
1048 g_pParentWnd->GetXYWnd()->Scale();
1049 region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] -
1051 g_pParentWnd->GetXYWnd()->Height() /
1052 g_pParentWnd->GetXYWnd()->Scale();
1053 region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] +
1055 g_pParentWnd->GetXYWnd()->Height() /
1056 g_pParentWnd->GetXYWnd()->Scale();
1057 region_mins[2] = MIN_WORLD_COORD;
1058 region_maxs[2] = MAX_WORLD_COORD;
1063 =======================================================================================================================
1065 =======================================================================================================================
1067 void Map_RegionTallBrush(void) {
1070 if (!QE_SingleBrush()) {
1074 b = selected_brushes.next;
1078 VectorCopy(b->mins, region_mins);
1079 VectorCopy(b->maxs, region_maxs);
1080 region_mins[2] = MIN_WORLD_COORD;
1081 region_maxs[2] = MAX_WORLD_COORD;
1088 =======================================================================================================================
1090 =======================================================================================================================
1092 void Map_RegionBrush(void) {
1095 if (!QE_SingleBrush()) {
1099 b = selected_brushes.next;
1103 VectorCopy(b->mins, region_mins);
1104 VectorCopy(b->maxs, region_maxs);
1111 =======================================================================================================================
1112 =======================================================================================================================
1114 void UniqueTargetName(idStr &rStr) {
1115 // make a unique target value
1117 for (entity_t * e = entities.next; e != &entities; e = e->next) {
1118 const char *tn = ValueForKey(e, "name");
1120 int targetnum = atoi(tn + 1);
1121 if (targetnum > maxtarg) {
1122 maxtarg = targetnum;
1126 tn = ValueForKey(e, "target");
1128 int targetnum = atoi(tn + 1);
1129 if (targetnum > maxtarg) {
1130 maxtarg = targetnum;
1136 sprintf(rStr, "t%i", maxtarg + 1);
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 // =======================================================================================================================
1145 void Map_ImportBuffer(char *buf, bool renameEntities) {
1152 Undo_Start("import buffer");
1154 g_qeglobals.d_parsed_brushes = 0;
1156 CMapStringToString mapStr;
1157 StartTokenParsing(buf);
1158 g_qeglobals.d_num_entities = 0;
1161 // Timo will be used in Entity_Parse to detect if a conversion between brush
1162 // formats is needed
1164 g_qeglobals.bNeedConvert = false;
1165 g_qeglobals.bOldBrushes = false;
1166 g_qeglobals.bPrimitBrushes = false;
1167 g_qeglobals.mapVersion = 1.0;
1169 if (GetToken(true)) {
1170 if (stricmp(token, "Version") == 0) {
1172 g_qeglobals.mapVersion = atof(token);
1173 common->Printf("Map version: %1.2f\n", g_qeglobals.mapVersion);
1179 idDict RemappedNames; // since I can't use "map <string, string>"... sigh. So much for STL...
1183 // use the selected brushes list as it's handy ent = Entity_Parse (false,
1184 // &selected_brushes);
1186 ent = Entity_Parse(false, &active_brushes);
1191 // end entity for undo
1192 Undo_EndEntity(ent);
1194 // end brushes for undo
1195 for (b = ent->brushes.onext; b && b != &ent->brushes; b = b->onext) {
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);
1211 // the following bit remaps conflicting target/targetname key/value pairs
1212 CString str = ValueForKey(ent, "target");
1214 CString strTarget("");
1215 if (str.GetLength() > 0) {
1216 if (FindEntity("target", str.GetBuffer(0))) {
1217 if (!mapStr.Lookup(str, strKey)) {
1219 UniqueTargetName(key);
1221 mapStr.SetAt(str, strKey);
1225 SetKeyValue(ent, "target", strTarget.GetBuffer(0));
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)); } }
1235 CString cstrNameOld = ValueForKey(ent, "name");
1236 Entity_Name(ent, renameEntities);
1237 CString cstrNameNew = ValueForKey(ent, "name");
1238 if (cstrNameOld != cstrNameNew)
1240 RemappedNames.Set(cstrNameOld, cstrNameNew);
1243 // if (strTarget.GetLength() > 0) SetKeyValue(ent, "target",
1244 // strTarget.GetBuffer(0));
1245 // add the entity to the end of the entity list
1247 ent->next = &entities;
1248 ent->prev = entities.prev;
1249 entities.prev->next = ent;
1250 entities.prev = ent;
1251 g_qeglobals.d_num_entities++;
1253 for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
1259 // now iterate through the remapped names, and see if there are any target-connections that need remaking...
1261 // (I could probably write this in half the size with STL, but WTF, work with what we have...)
1263 int iNumKeyVals = RemappedNames.GetNumKeyVals();
1264 for (int iKeyVal=0; iKeyVal < iNumKeyVals; iKeyVal++)
1266 const idKeyValue *pKeyVal = RemappedNames.GetKeyVal( iKeyVal );
1268 LPCSTR psOldName = pKeyVal->GetKey().c_str();
1269 LPCSTR psNewName = pKeyVal->GetValue().c_str();
1271 entity_t *pEntOld = FindEntity("name", psOldName); // original ent we cloned from
1272 entity_t *pEntNew = FindEntity("name", psNewName); // cloned ent
1274 if (pEntOld && pEntNew)
1276 CString cstrTargetNameOld = ValueForKey(pEntOld, "target");
1277 if (!cstrTargetNameOld.IsEmpty())
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...
1282 entity_t *pEntOldTarget = FindEntity("name", cstrTargetNameOld);
1283 if ( pEntOldTarget )
1285 LPCSTR psNewTargetName = RemappedNames.GetString( cstrTargetNameOld );
1286 if (psNewTargetName && psNewTargetName[0])
1288 SetKeyValue(pEntNew, "target", psNewTargetName);
1297 // ::ShowWindow(g_qeglobals.d_hwndEntity, FALSE);
1298 // ::LockWindowUpdate(g_qeglobals.d_hwndEntity);
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);
1306 // ::LockWindowUpdate(NULL);
1307 g_bScreenUpdates = true;
1312 // reset the "need conversion" flag conversion to the good format done in
1313 // Map_BuildBrushData
1315 g_qeglobals.bNeedConvert = false;
1317 Sys_UpdateWindows(W_ALL);
1319 // Sys_MarkMapModified();
1326 // =======================================================================================================================
1328 // =======================================================================================================================
1330 void Map_ImportFile(char *fileName) {
1335 temp.BackSlashesToSlashes();
1336 if (LoadFile( temp, (void **) &buf) != -1) {
1337 Map_ImportBuffer(buf);
1339 Map_BuildBrushData();
1342 Sys_UpdateWindows(W_ALL);
1348 // =======================================================================================================================
1349 // Map_SaveSelected Saves selected world brushes and whole entities with partial/full selections
1350 // =======================================================================================================================
1352 void Map_SaveSelected(char *fileName) {
1359 temp.BackSlashesToSlashes();
1360 f = fopen(temp, "w");
1363 common->Printf( "ERROR!!!! Couldn't open %s\n", temp.c_str() );
1368 g_qeglobals.mapVersion = MAP_VERSION;
1369 fprintf( f, "Version %1.2f\n", MAP_VERSION );
1371 // write world entity second
1372 world_entity->origin.Zero();
1373 Entity_WriteSelected( world_entity, f );
1375 // then write all other ents
1377 for ( e = entities.next; e != &entities; e = next ) {
1378 fprintf( f, "// entity %i\n", count );
1380 Entity_WriteSelected( e, f );
1388 // =======================================================================================================================
1389 // Map_SaveSelected Saves selected world brushes and whole entities with partial/full selections
1390 // =======================================================================================================================
1392 void Map_SaveSelected(CMemFile *pMemFile, CMemFile *pPatchFile) {
1398 g_qeglobals.mapVersion = MAP_VERSION;
1399 MemFile_fprintf(pMemFile, "Version %1.2f\n", MAP_VERSION);
1401 // write world entity first
1402 world_entity->origin.Zero();
1403 Entity_WriteSelected(world_entity, pMemFile);
1405 // then write all other ents
1407 for (e = entities.next; e != &entities; e = next) {
1408 MemFile_fprintf(pMemFile, "// entity %i\n", count);
1410 Entity_WriteSelected(e, pMemFile);
1414 // if (pPatchFile) Patch_WriteFile(pPatchFile);
1418 =======================================================================================================================
1419 =======================================================================================================================
1427 bool WriteFileString( FILE *fp, char *string, ... ) {
1435 va_start( argPtr, string );
1441 while ( (*string >= '0' && *string <= '9') ||
1442 *string == '.' || *string == '-' || *string == '+' || *string == '#') {
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() );
1459 i = va_arg( argPtr, long );
1460 fprintf( fp, "%d", i );
1463 u = va_arg( argPtr, unsigned long );
1464 fprintf( fp, "%u", u );
1467 u = va_arg( argPtr, unsigned long );
1468 fprintf( fp, "%o", u );
1471 u = va_arg( argPtr, unsigned long );
1472 fprintf( fp, "%x", u );
1475 u = va_arg( argPtr, unsigned long );
1476 fprintf( fp, "%X", u );
1479 i = va_arg( argPtr, long );
1480 fprintf( fp, "%c", (char) i );
1483 str = va_arg( argPtr, char * );
1484 fprintf( fp, "%s", str );
1487 fprintf( fp, "%%" );
1490 common->Error( "WriteFileString: invalid %%%c", *string );
1499 fprintf( fp, "\t" );
1502 fprintf( fp, "\n" );
1504 common->Error( "WriteFileString: unknown escape character \'%c\'", *string );
1510 fprintf( fp, "%c", *string );
1526 void MemFile_fprintf( CMemFile *pMemFile, const char *string, ... ) {
1535 char *buff = Buffer;
1537 va_start( argPtr, string );
1543 while ( (*string >= '0' && *string <= '9') ||
1544 *string == '.' || *string == '-' || *string == '+' || *string == '#') {
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() );
1561 i = va_arg( argPtr, long );
1562 sprintf( buff, "%d", i );
1565 u = va_arg( argPtr, unsigned long );
1566 sprintf( buff, "%u", u );
1569 u = va_arg( argPtr, unsigned long );
1570 sprintf( buff, "%o", u );
1573 u = va_arg( argPtr, unsigned long );
1574 sprintf( buff, "%x", u );
1577 u = va_arg( argPtr, unsigned long );
1578 sprintf( buff, "%X", u );
1581 i = va_arg( argPtr, long );
1582 sprintf( buff, "%c", (char) i );
1585 str = va_arg( argPtr, char * );
1586 sprintf( buff, "%s", str );
1589 sprintf( buff, "%%" );
1592 common->Error( "MemFile_fprintf: invalid %%%c", *string );
1601 sprintf( buff, "\t" );
1604 sprintf( buff, "\n" );
1606 common->Error( "MemFile_fprintf: unknown escape character \'%c\'", *string );
1612 sprintf( buff, "%c", *string );
1617 buff = Buffer + strlen(Buffer);
1623 pMemFile->Write( out.c_str(), out.Length() );