EditorMap.cpp 46 KB

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