MAP.CPP (23091B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // map.c 23 24 #include "stdafx.h" 25 #include "qe3.h" 26 #include "PrefsDlg.h" 27 28 qboolean modified; // for quit confirmation (0 = clean, 1 = unsaved, 29 // 2 = autosaved, but not regular saved) 30 31 char currentmap[1024]; 32 33 34 brush_t active_brushes; // brushes currently being displayed 35 brush_t selected_brushes; // highlighted 36 37 face_t *selected_face; 38 brush_t *selected_face_brush; 39 40 brush_t filtered_brushes; // brushes that have been filtered or regioned 41 42 entity_t entities; // head/tail of doubly linked list 43 44 entity_t *world_entity = NULL; // "classname" "worldspawn" ! 45 46 void AddRegionBrushes (void); 47 void RemoveRegionBrushes (void); 48 49 50 void DupLists() 51 { 52 DWORD dw = GetTickCount(); 53 54 } 55 56 /* 57 ============================================================= 58 59 Cross map selection saving 60 61 this could fuck up if you have only part of a complex entity selected... 62 ============================================================= 63 */ 64 65 brush_t between_brushes; 66 entity_t between_entities; 67 68 bool g_bRestoreBetween = false; 69 70 void Map_SaveBetween (void) 71 { 72 73 if (g_pParentWnd->ActiveXY()) 74 { 75 g_bRestoreBetween = true; 76 g_pParentWnd->ActiveXY()->Copy(); 77 } 78 return; 79 80 #if 0 81 82 brush_t *b; 83 entity_t *e, *e2; 84 85 between_brushes.next = selected_brushes.next; 86 between_brushes.prev = selected_brushes.prev; 87 between_brushes.next->prev = &between_brushes; 88 between_brushes.prev->next = &between_brushes; 89 90 between_entities.next = between_entities.prev = &between_entities; 91 selected_brushes.next = selected_brushes.prev = &selected_brushes; 92 93 for (b=between_brushes.next ; b != &between_brushes ; b=b->next) 94 { 95 e = b->owner; 96 if (e == world_entity) 97 b->owner = NULL; 98 else 99 { 100 for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next) 101 if (e2 == e) 102 goto next; // allready got the entity 103 // move the entity over 104 e->prev->next = e->next; 105 e->next->prev = e->prev; 106 e->next = between_entities.next; 107 e->prev = &between_entities; 108 e->next->prev = e; 109 e->prev->next = e; 110 } 111 next: ; 112 } 113 #endif 114 } 115 116 void Map_RestoreBetween (void) 117 { 118 if (g_pParentWnd->ActiveXY() && g_bRestoreBetween) 119 g_pParentWnd->ActiveXY()->Paste(); 120 return; 121 122 #if 0 123 entity_t *head, *tail; 124 brush_t *b; 125 126 if (!between_brushes.next) 127 return; 128 129 for (b=between_brushes.next ; b != &between_brushes ; b=b->next) 130 { 131 if (!b->owner) 132 { 133 b->owner = world_entity; 134 b->onext = world_entity->brushes.onext; 135 b->oprev = &world_entity->brushes; 136 b->onext->oprev = b; 137 b->oprev->onext = b; 138 } 139 } 140 141 selected_brushes.next = between_brushes.next; 142 selected_brushes.prev = between_brushes.prev; 143 selected_brushes.next->prev = &selected_brushes; 144 selected_brushes.prev->next = &selected_brushes; 145 146 head = between_entities.next; 147 tail = between_entities.prev; 148 149 if (head != tail) 150 { 151 entities.prev->next = head; 152 head->prev = entities.prev; 153 tail->next = &entities; 154 entities.prev = tail; 155 } 156 157 between_brushes.next = NULL; 158 between_entities.next = NULL; 159 #endif 160 } 161 162 //============================================================================ 163 164 bool CheckForTinyBrush(brush_t* b, int n, float fSize) 165 { 166 bool bTiny = false; 167 for (int i=0 ; i<3 ; i++) 168 { 169 if (b->maxs[i] - b->mins[i] < fSize) 170 bTiny = true; 171 } 172 if (bTiny) 173 Sys_Printf("Possible problem brush (too small) #%i ", n); 174 return bTiny; 175 } 176 177 void Map_BuildBrushData(void) 178 { 179 brush_t *b, *next; 180 181 if (active_brushes.next == NULL) 182 return; 183 184 Sys_BeginWait (); // this could take a while 185 186 int n = 0; 187 for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next) 188 { 189 next = b->next; 190 Brush_Build( b, true, false, false ); 191 if (!b->brush_faces || (g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush(b, n++, g_PrefsDlg.m_fTinySize))) 192 { 193 Brush_Free (b); 194 Sys_Printf ("Removed degenerate brush\n"); 195 } 196 } 197 Sys_EndWait(); 198 } 199 200 entity_t *Map_FindClass (char *cname) 201 { 202 entity_t *ent; 203 204 for (ent = entities.next ; ent != &entities ; ent=ent->next) 205 { 206 if (!strcmp(cname, ValueForKey (ent, "classname"))) 207 return ent; 208 } 209 return NULL; 210 } 211 212 /* 213 ================ 214 Map_Free 215 ================ 216 */ 217 void Map_Free (void) 218 { 219 g_bRestoreBetween = false; 220 if (selected_brushes.next && 221 (selected_brushes.next != &selected_brushes) ) 222 { 223 if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES) 224 Map_SaveBetween (); 225 } 226 227 Texture_ClearInuse (); 228 Pointfile_Clear (); 229 strcpy (currentmap, "unnamed.map"); 230 Sys_SetTitle (currentmap); 231 g_qeglobals.d_num_entities = 0; 232 g_qeglobals.d_numterrapoints = 0; 233 234 if (!active_brushes.next) 235 { // 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; 239 240 entities.prev = entities.next = &entities; 241 } 242 else 243 { 244 while (active_brushes.next != &active_brushes) 245 Brush_Free (active_brushes.next); 246 while (selected_brushes.next != &selected_brushes) 247 Brush_Free (selected_brushes.next); 248 while (filtered_brushes.next != &filtered_brushes) 249 Brush_Free (filtered_brushes.next); 250 251 while (entities.next != &entities) 252 Entity_Free (entities.next); 253 } 254 255 if (world_entity) 256 Entity_Free(world_entity); 257 world_entity = NULL; 258 } 259 260 entity_t *AngledEntity() 261 { 262 entity_t *ent = Map_FindClass ("info_player_start"); 263 if (!ent) 264 { 265 ent = Map_FindClass ("info_player_deathmatch"); 266 } 267 if (!ent) 268 { 269 ent = Map_FindClass ("info_player_deathmatch"); 270 } 271 if (!ent) 272 { 273 ent = Map_FindClass ("team_CTF_redplayer"); 274 } 275 if (!ent) 276 { 277 ent = Map_FindClass ("team_CTF_blueplayer"); 278 } 279 if (!ent) 280 { 281 ent = Map_FindClass ("team_CTF_redspawn"); 282 } 283 if (!ent) 284 { 285 ent = Map_FindClass ("team_CTF_bluespawn"); 286 } 287 return ent; 288 } 289 290 291 292 /* 293 ================ 294 Map_LoadFile 295 ================ 296 */ 297 void Map_LoadFile (char *filename) 298 { 299 char *buf; 300 entity_t *ent; 301 char temp[1024]; 302 303 Sys_BeginWait (); 304 Select_Deselect(); 305 //SetInspectorMode(W_CONSOLE); 306 307 QE_ConvertDOSToUnixName( temp, filename ); 308 Sys_Printf ("Map_LoadFile: %s\n", temp ); 309 310 Map_Free (); 311 //++timo FIXME: maybe even easier to have Group_Init called from Map_Free? 312 Group_Init(); 313 314 g_qeglobals.d_parsed_brushes = 0; 315 strcpy (currentmap, filename); 316 317 if (LoadFile (filename, (void **)&buf) != -1) 318 { 319 320 StartTokenParsing (buf); 321 g_qeglobals.d_num_entities = 0; 322 323 // Timo 324 // will be used in Entity_Parse to detect if a conversion between brush formats is needed 325 g_qeglobals.bNeedConvert = false; 326 g_qeglobals.bOldBrushes = false; 327 g_qeglobals.bPrimitBrushes = false; 328 329 while (1) 330 { 331 ent = Entity_Parse (false, &active_brushes); 332 if (!ent) 333 break; 334 if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) 335 { 336 if (world_entity) 337 Sys_Printf ("WARNING: multiple worldspawn\n"); 338 world_entity = ent; 339 } 340 else if (!strcmp(ValueForKey (ent, "classname"), "group_info")) 341 { 342 // it's a group thing! 343 Group_Add(ent); 344 Entity_Free(ent); 345 } 346 else 347 { 348 // add the entity to the end of the entity list 349 ent->next = &entities; 350 ent->prev = entities.prev; 351 entities.prev->next = ent; 352 entities.prev = ent; 353 g_qeglobals.d_num_entities++; 354 } 355 } 356 } 357 358 free (buf); 359 360 if (!world_entity) 361 { 362 Sys_Printf ("No worldspawn in map.\n"); 363 Map_New (); 364 return; 365 } 366 367 Sys_Printf ("--- LoadMapFile ---\n"); 368 Sys_Printf ("%s\n", temp ); 369 370 Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); 371 Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); 372 373 Map_RestoreBetween (); 374 375 Sys_Printf ("Map_BuildAllDisplayLists\n"); 376 Map_BuildBrushData(); 377 378 // reset the "need conversion" flag 379 // conversion to the good format done in Map_BuildBrushData 380 g_qeglobals.bNeedConvert=false; 381 382 // 383 // move the view to a start position 384 // 385 ent = AngledEntity(); 386 387 g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0; 388 if (ent) 389 { 390 GetVectorForKey (ent, "origin", g_pParentWnd->GetCamera()->Camera().origin); 391 GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); 392 g_pParentWnd->GetCamera()->Camera().angles[YAW] = FloatForKey (ent, "angle"); 393 } 394 else 395 { 396 g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0; 397 VectorCopy (vec3_origin, g_pParentWnd->GetCamera()->Camera().origin); 398 VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); 399 } 400 401 Map_RegionOff (); 402 403 404 modified = false; 405 Sys_SetTitle (temp); 406 407 Texture_ShowInuse (); 408 409 Sys_EndWait(); 410 Sys_UpdateWindows (W_ALL); 411 412 } 413 414 /* 415 =========== 416 Map_SaveFile 417 =========== 418 */ 419 void Map_SaveFile (char *filename, qboolean use_region ) 420 { 421 entity_t *e, *next; 422 FILE *f; 423 char temp[1024]; 424 int count; 425 426 if (filename == NULL || strlen(filename) == 0) 427 { 428 CFileDialog dlgSave(FALSE, "map", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Map Files (*.map)|*.map||", AfxGetMainWnd()); 429 if (dlgSave.DoModal() == IDOK) 430 filename = strdup(dlgSave.m_ofn.lpstrFile); 431 else 432 return; 433 } 434 435 Pointfile_Clear (); 436 QE_ConvertDOSToUnixName( temp, filename ); 437 438 if (!use_region) 439 { 440 char backup[1024]; 441 442 // rename current to .bak 443 strcpy (backup, filename); 444 StripExtension (backup); 445 strcat (backup, ".bak"); 446 _unlink (backup); 447 rename (filename, backup); 448 } 449 450 Sys_Printf ("Map_SaveFile: %s\n", filename); 451 452 f = fopen(filename, "w"); 453 454 if (!f) 455 { 456 Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename); 457 return; 458 } 459 460 if (use_region) 461 { 462 AddRegionBrushes (); 463 } 464 465 // write world entity first 466 Entity_Write (world_entity, f, use_region); 467 468 // then write all other ents 469 count = 1; 470 for (e=entities.next ; e != &entities ; e=next) 471 { 472 next = e->next; 473 if (e->brushes.onext == &e->brushes) 474 { 475 Entity_Free (e); // no brushes left, so remove it 476 } 477 else 478 { 479 fprintf (f, "// entity %i\n", count); 480 count++; 481 Entity_Write (e, f, use_region); 482 } 483 } 484 485 // save the group info stuff 486 Group_Save(f); 487 488 fclose (f); 489 490 if (use_region) 491 RemoveRegionBrushes (); 492 493 Sys_Printf ("Saved.\n"); 494 modified = false; 495 496 if ( !strstr( temp, "autosave" ) ) 497 Sys_SetTitle (temp); 498 499 if (!use_region) 500 { 501 time_t timer; 502 FILE *f; 503 504 time (&timer); 505 MessageBeep (MB_ICONEXCLAMATION); 506 f = fopen ("c:/tstamps.log", "a"); 507 if (f) 508 { 509 fprintf (f, "%s", filename); 510 //fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer)); 511 fclose (f); 512 g_qeglobals.d_workcount = 0; 513 } 514 fclose (f); 515 Sys_Status ("Saved.\n", 0); 516 } 517 518 //Curve_WriteFile (filename); //.trinity 519 //Patch_WriteFile (filename); 520 } 521 522 /* 523 =========== 524 Map_New 525 =========== 526 */ 527 void Map_New (void) 528 { 529 Sys_Printf ("Map_New\n"); 530 Map_Free (); 531 532 Patch_Cleanup(); 533 534 world_entity = (entity_s*)qmalloc(sizeof(*world_entity)); 535 world_entity->brushes.onext = 536 world_entity->brushes.oprev = &world_entity->brushes; 537 SetKeyValue (world_entity, "classname", "worldspawn"); 538 world_entity->eclass = Eclass_ForName ("worldspawn", true); 539 540 g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0; 541 g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0; 542 VectorCopy (vec3_origin, g_pParentWnd->GetCamera()->Camera().origin); 543 g_pParentWnd->GetCamera()->Camera().origin[2] = 48; 544 VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); 545 546 Map_RestoreBetween (); 547 548 Group_Init(); 549 550 Sys_UpdateWindows (W_ALL); 551 modified = false; 552 } 553 554 /* 555 =========================================================== 556 557 REGION 558 559 =========================================================== 560 */ 561 562 qboolean region_active; 563 vec3_t region_mins = {MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD}; 564 vec3_t region_maxs = {MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD}; 565 566 brush_t *region_sides[4]; 567 /* 568 =========== 569 AddRegionBrushes 570 571 a regioned map will have temp walls put up at the region boundary 572 =========== 573 */ 574 void AddRegionBrushes (void) 575 { 576 vec3_t mins, maxs; 577 int i; 578 texdef_t td; 579 580 if (!region_active) 581 return; 582 583 memset (&td, 0, sizeof(td)); 584 //strcpy (td.name, "REGION"); 585 td.SetName("REGION"); 586 587 mins[0] = region_mins[0] - 16; 588 maxs[0] = region_mins[0] + 1; 589 mins[1] = region_mins[1] - 16; 590 maxs[1] = region_maxs[1] + 16; 591 mins[2] = MIN_WORLD_COORD; 592 maxs[2] = MAX_WORLD_COORD; 593 region_sides[0] = Brush_Create (mins, maxs, &td); 594 595 mins[0] = region_maxs[0] - 1; 596 maxs[0] = region_maxs[0] + 16; 597 region_sides[1] = Brush_Create (mins, maxs, &td); 598 599 mins[0] = region_mins[0] - 16; 600 maxs[0] = region_maxs[0] + 16; 601 mins[1] = region_mins[1] - 16; 602 maxs[1] = region_mins[1] + 1; 603 region_sides[2] = Brush_Create (mins, maxs, &td); 604 605 mins[1] = region_maxs[1] - 1; 606 maxs[1] = region_maxs[1] + 16; 607 region_sides[3] = Brush_Create (mins, maxs, &td); 608 609 for (i=0 ; i<4 ; i++) 610 { 611 Brush_AddToList (region_sides[i], &selected_brushes); 612 Entity_LinkBrush (world_entity, region_sides[i]); 613 Brush_Build( region_sides[i] ); 614 } 615 } 616 617 void RemoveRegionBrushes (void) 618 { 619 int i; 620 621 if (!region_active) 622 return; 623 for (i=0 ; i<4 ; i++) 624 Brush_Free (region_sides[i]); 625 } 626 627 628 qboolean Map_IsBrushFiltered (brush_t *b) 629 { 630 int i; 631 632 for (i=0 ; i<3 ; i++) 633 { 634 if (b->mins[i] > region_maxs[i]) 635 return true; 636 if (b->maxs[i] < region_mins[i]) 637 return true; 638 } 639 return false; 640 } 641 642 /* 643 =========== 644 Map_RegionOff 645 646 Other filtering options may still be on 647 =========== 648 */ 649 void Map_RegionOff (void) 650 { 651 brush_t *b, *next; 652 int i; 653 654 region_active = false; 655 for (i=0 ; i<3 ; i++) 656 { 657 region_maxs[i] = MAX_WORLD_COORD;//4096; 658 region_mins[i] = MIN_WORLD_COORD;//-4096; 659 } 660 661 for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next) 662 { 663 next = b->next; 664 if (Map_IsBrushFiltered (b)) 665 continue; // still filtered 666 Brush_RemoveFromList (b); 667 if (active_brushes.next == NULL || active_brushes.prev == NULL) 668 { 669 active_brushes.next = &active_brushes; 670 active_brushes.prev = &active_brushes; 671 } 672 Brush_AddToList (b, &active_brushes); 673 } 674 675 Sys_UpdateWindows (W_ALL); 676 } 677 678 void Map_ApplyRegion (void) 679 { 680 brush_t *b, *next; 681 682 region_active = true; 683 for (b=active_brushes.next ; b != &active_brushes ; b=next) 684 { 685 next = b->next; 686 if (!Map_IsBrushFiltered (b)) 687 continue; // still filtered 688 Brush_RemoveFromList (b); 689 Brush_AddToList (b, &filtered_brushes); 690 } 691 692 Sys_UpdateWindows (W_ALL); 693 } 694 695 696 /* 697 ======================== 698 Map_RegionSelectedBrushes 699 ======================== 700 */ 701 void Map_RegionSelectedBrushes (void) 702 { 703 Map_RegionOff (); 704 705 if (selected_brushes.next == &selected_brushes) // nothing selected 706 { 707 Sys_Printf("Tried to region with no selection...\n"); 708 return; 709 } 710 region_active = true; 711 Select_GetBounds (region_mins, region_maxs); 712 713 // move the entire active_brushes list to filtered_brushes 714 filtered_brushes.next = active_brushes.next; 715 filtered_brushes.prev = active_brushes.prev; 716 filtered_brushes.next->prev = &filtered_brushes; 717 filtered_brushes.prev->next = &filtered_brushes; 718 719 // move the entire selected_brushes list to active_brushes 720 active_brushes.next = selected_brushes.next; 721 active_brushes.prev = selected_brushes.prev; 722 active_brushes.next->prev = &active_brushes; 723 active_brushes.prev->next = &active_brushes; 724 725 // clear selected_brushes 726 selected_brushes.next = selected_brushes.prev = &selected_brushes; 727 728 Sys_UpdateWindows (W_ALL); 729 } 730 731 732 /* 733 =========== 734 Map_RegionXY 735 =========== 736 */ 737 void Map_RegionXY (void) 738 { 739 Map_RegionOff (); 740 741 region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); 742 region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); 743 region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); 744 region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); 745 region_mins[2] = -MIN_WORLD_COORD; 746 region_maxs[2] = MAX_WORLD_COORD; 747 Map_ApplyRegion (); 748 } 749 750 /* 751 =========== 752 Map_RegionTallBrush 753 =========== 754 */ 755 void Map_RegionTallBrush (void) 756 { 757 brush_t *b; 758 759 if (!QE_SingleBrush ()) 760 return; 761 762 b = selected_brushes.next; 763 764 Map_RegionOff (); 765 766 VectorCopy (b->mins, region_mins); 767 VectorCopy (b->maxs, region_maxs); 768 region_mins[2] = MIN_WORLD_COORD; 769 region_maxs[2] = MAX_WORLD_COORD; 770 771 772 Select_Delete (); 773 Map_ApplyRegion (); 774 } 775 /* 776 =========== 777 Map_RegionBrush 778 =========== 779 */ 780 void Map_RegionBrush (void) 781 { 782 brush_t *b; 783 784 if (!QE_SingleBrush ()) 785 return; 786 787 b = selected_brushes.next; 788 789 Map_RegionOff (); 790 791 VectorCopy (b->mins, region_mins); 792 VectorCopy (b->maxs, region_maxs); 793 794 Select_Delete (); 795 Map_ApplyRegion (); 796 } 797 798 799 800 void UniqueTargetName(CString& rStr) 801 { 802 // make a unique target value 803 int maxtarg = 0; 804 for (entity_t* e=entities.next ; e != &entities ; e=e->next) 805 { 806 char* tn = ValueForKey (e, "targetname"); 807 if (tn && tn[0]) 808 { 809 int targetnum = atoi(tn+1); 810 if (targetnum > maxtarg) 811 maxtarg = targetnum; 812 } 813 else 814 { 815 tn = ValueForKey (e, "target"); 816 if (tn && tn[0]) 817 { 818 int targetnum = atoi(tn+1); 819 if (targetnum > maxtarg) 820 maxtarg = targetnum; 821 } 822 } 823 } 824 rStr.Format("t%i", maxtarg+1); 825 } 826 827 // 828 //================ 829 //Map_ImportFile 830 // Timo 09/01/99 : called by CXYWnd::Paste & Map_ImportFile 831 // if Map_ImportFile ( prefab ), the buffer may contain brushes in old format ( conversion needed ) 832 //================ 833 // 834 void Map_ImportBuffer (char* buf) 835 { 836 entity_t* ent; 837 brush_t* b = NULL; 838 CPtrArray ptrs; 839 840 Select_Deselect(); 841 842 Undo_Start("import buffer"); 843 844 g_qeglobals.d_parsed_brushes = 0; 845 if (buf) 846 { 847 CMapStringToString mapStr; 848 StartTokenParsing (buf); 849 g_qeglobals.d_num_entities = 0; 850 851 // Timo 852 // will be used in Entity_Parse to detect if a conversion between brush formats is needed 853 g_qeglobals.bNeedConvert = false; 854 g_qeglobals.bOldBrushes = false; 855 g_qeglobals.bPrimitBrushes = false; 856 857 while (1) 858 { 859 860 // use the selected brushes list as it's handy 861 //ent = Entity_Parse (false, &selected_brushes); 862 ent = Entity_Parse (false, &active_brushes); 863 if (!ent) 864 break; 865 //end entity for undo 866 Undo_EndEntity(ent); 867 //end brushes for undo 868 for(b = ent->brushes.onext; b && b != &ent->brushes; b = b->onext) 869 { 870 Undo_EndBrush(b); 871 } 872 873 if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) 874 { 875 // world brushes need to be added to the current world entity 876 877 b=ent->brushes.onext; 878 while (b && b != &ent->brushes) 879 { 880 brush_t* bNext = b->onext; 881 Entity_UnlinkBrush(b); 882 Entity_LinkBrush(world_entity, b); 883 ptrs.Add(b); 884 b = bNext; 885 } 886 } 887 else 888 { 889 // the following bit remaps conflicting target/targetname key/value pairs 890 CString str = ValueForKey(ent, "target"); 891 CString strKey; 892 CString strTarget(""); 893 if (str.GetLength() > 0) 894 { 895 if (FindEntity("target", str.GetBuffer(0))) 896 { 897 if (!mapStr.Lookup(str, strKey)) 898 { 899 UniqueTargetName(strKey); 900 mapStr.SetAt(str, strKey); 901 } 902 strTarget = strKey; 903 SetKeyValue(ent, "target", strTarget.GetBuffer(0)); 904 } 905 } 906 str = ValueForKey(ent, "targetname"); 907 if (str.GetLength() > 0) 908 { 909 if (FindEntity("targetname", str.GetBuffer(0))) 910 { 911 if (!mapStr.Lookup(str, strKey)) 912 { 913 UniqueTargetName(strKey); 914 mapStr.SetAt(str, strKey); 915 } 916 SetKeyValue(ent, "targetname", strKey.GetBuffer(0)); 917 } 918 } 919 //if (strTarget.GetLength() > 0) 920 // SetKeyValue(ent, "target", strTarget.GetBuffer(0)); 921 922 // add the entity to the end of the entity list 923 ent->next = &entities; 924 ent->prev = entities.prev; 925 entities.prev->next = ent; 926 entities.prev = ent; 927 g_qeglobals.d_num_entities++; 928 929 for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) 930 { 931 ptrs.Add(b); 932 } 933 } 934 } 935 } 936 937 //::ShowWindow(g_qeglobals.d_hwndEntity, FALSE); 938 //::LockWindowUpdate(g_qeglobals.d_hwndEntity); 939 g_bScreenUpdates = false; 940 for (int i = 0; i < ptrs.GetSize(); i++) 941 { 942 Brush_Build(reinterpret_cast<brush_t*>(ptrs[i]), true, false); 943 Select_Brush(reinterpret_cast<brush_t*>(ptrs[i]), true, false); 944 } 945 //::LockWindowUpdate(NULL); 946 g_bScreenUpdates = true; 947 948 ptrs.RemoveAll(); 949 950 // reset the "need conversion" flag 951 // conversion to the good format done in Map_BuildBrushData 952 g_qeglobals.bNeedConvert=false; 953 954 Sys_UpdateWindows (W_ALL); 955 //Sys_MarkMapModified(); 956 modified = true; 957 958 Undo_End(); 959 960 } 961 962 963 // 964 //================ 965 //Map_ImportFile 966 //================ 967 // 968 void Map_ImportFile (char *filename) 969 { 970 char* buf; 971 char temp[1024]; 972 Sys_BeginWait (); 973 QE_ConvertDOSToUnixName( temp, filename ); 974 if (LoadFile (filename, (void **)&buf) != -1) 975 { 976 Map_ImportBuffer(buf); 977 free(buf); 978 Map_BuildBrushData(); 979 } 980 Sys_UpdateWindows (W_ALL); 981 modified = true; 982 Sys_EndWait(); 983 } 984 985 // 986 //=========== 987 //Map_SaveSelected 988 //=========== 989 // 990 // Saves selected world brushes and whole entities with partial/full selections 991 // 992 void Map_SaveSelected(char* pFilename) 993 { 994 entity_t *e, *next; 995 FILE *f; 996 char temp[1024]; 997 int count; 998 999 QE_ConvertDOSToUnixName(temp, pFilename); 1000 f = fopen(pFilename, "w"); 1001 1002 if (!f) 1003 { 1004 Sys_Printf ("ERROR!!!! Couldn't open %s\n", pFilename); 1005 return; 1006 } 1007 1008 // write world entity first 1009 Entity_WriteSelected(world_entity, f); 1010 1011 // then write all other ents 1012 count = 1; 1013 for (e=entities.next ; e != &entities ; e=next) 1014 { 1015 fprintf (f, "// entity %i\n", count); 1016 count++; 1017 Entity_WriteSelected(e, f); 1018 next = e->next; 1019 } 1020 fclose (f); 1021 } 1022 1023 1024 // 1025 //=========== 1026 //Map_SaveSelected 1027 //=========== 1028 // 1029 // Saves selected world brushes and whole entities with partial/full selections 1030 // 1031 void Map_SaveSelected(CMemFile* pMemFile, CMemFile* pPatchFile) 1032 { 1033 entity_t *e, *next; 1034 int count; 1035 CString strTemp; 1036 1037 // write world entity first 1038 Entity_WriteSelected(world_entity, pMemFile); 1039 1040 // then write all other ents 1041 count = 1; 1042 for (e=entities.next ; e != &entities ; e=next) 1043 { 1044 MemFile_fprintf(pMemFile, "// entity %i\n", count); 1045 count++; 1046 Entity_WriteSelected(e, pMemFile); 1047 next = e->next; 1048 } 1049 1050 //if (pPatchFile) 1051 // Patch_WriteFile(pPatchFile); 1052 } 1053 1054 1055 void MemFile_fprintf(CMemFile* pMemFile, const char* pText, ...) 1056 { 1057 char Buffer[4096]; 1058 va_list args; 1059 va_start (args,pText); 1060 vsprintf(Buffer, pText, args); 1061 pMemFile->Write(Buffer, strlen(Buffer)); 1062 }