1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "tools/edit_gui_common.h"
30 
31 
32 #include "qe3.h"
33 #include <direct.h>
34 #include <sys/stat.h>
35 #include "WaitDlg.h"
36 
37 QEGlobals_t g_qeglobals;
38 
39 /*
40  =======================================================================================================================
41  =======================================================================================================================
42  */
QE_CheckOpenGLForErrors(void)43 void WINAPI QE_CheckOpenGLForErrors(void) {
44 	CString strMsg;
45 	int		i = qglGetError();
46 	if (i != GL_NO_ERROR) {
47 		if (i == GL_OUT_OF_MEMORY) {
48 			//
49 			// strMsg.Format("OpenGL out of memory error %s\nDo you wish to save before
50 			// exiting?", gluErrorString((GLenum)i));
51 			//
52 			if (g_pParentWnd->MessageBox(strMsg, EDITOR_WINDOWTEXT " Error", MB_YESNO) == IDYES) {
53 				Map_SaveFile(NULL, false);
54 			}
55 
56 			exit(1);
57 		}
58 		else {
59 			// strMsg.Format("Warning: OpenGL Error %s\n ", gluErrorString((GLenum)i));
60 			common->Printf(strMsg.GetBuffer(0));
61 		}
62 	}
63 }
64 
65 /*
66  =======================================================================================================================
67  =======================================================================================================================
68  */
DoesFileExist(const char * pBuff,long & lSize)69 bool DoesFileExist(const char *pBuff, long &lSize) {
70 	CFile	file;
71 	if (file.Open(pBuff, CFile::modeRead | CFile::shareDenyNone)) {
72 		lSize += file.GetLength();
73 		file.Close();
74 		return true;
75 	}
76 
77 	return false;
78 }
79 
80 /*
81  =======================================================================================================================
82  =======================================================================================================================
83  */
ExtractPath_and_Filename(const char * pPath,CString & strPath,CString & strFilename)84 bool ExtractPath_and_Filename(const char *pPath, CString &strPath, CString &strFilename) {
85 	CString strPathName = pPath;
86 	int		nSlash = strPathName.ReverseFind('\\');
87 	if (nSlash >= 0) {
88 		strPath = strPathName.Left(nSlash + 1);
89 		strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1);
90 	}
91 	else {
92 		strFilename = pPath;
93 	}
94 
95 	return true;
96 }
97 
98 /*
99  =======================================================================================================================
100  =======================================================================================================================
101  */
Map_Snapshot()102 void Map_Snapshot() {
103 	CString strMsg;
104 
105 	//
106 	// we need to do the following 1. make sure the snapshot directory exists (create
107 	// it if it doesn't) 2. find out what the lastest save is based on number 3. inc
108 	// that and save the map
109 	//
110 	CString strOrgPath, strOrgFile;
111 	ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile);
112 	AddSlash(strOrgPath);
113 	strOrgPath += "snapshots";
114 
115 	bool			bGo = true;
116 	struct _stat	Stat;
117 	if (_stat(strOrgPath, &Stat) == -1) {
118 		bGo = (_mkdir(strOrgPath) != -1);
119 	}
120 
121 	AddSlash(strOrgPath);
122 	if (bGo) {
123 		int		nCount = 0;
124 		long	lSize = 0;
125 		CString strNewPath = strOrgPath;
126 		strNewPath += strOrgFile;
127 
128 		CString strFile;
129 		while (bGo) {
130 			strFile.Format("%s.%i", strNewPath.GetString(), nCount);
131 			bGo = DoesFileExist(strFile, lSize);
132 			nCount++;
133 		}
134 
135 		// strFile has the next available slot
136 		Map_SaveFile(strFile.GetBuffer(0), false);
137 		Sys_SetTitle(currentmap);
138 		if (lSize > 12 * 1024 * 1024) { // total size of saves > 4 mb
139 			common->Printf
140 			(
141 				"The snapshot files in the [%s] directory total more than 4 megabytes. You might consider cleaning the directory up.",
142 				strOrgPath.GetString()
143 			);
144 		}
145 	}
146 	else {
147 		strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetString());
148 		g_pParentWnd->MessageBox(strMsg);
149 	}
150 }
151 
152 /*
153  =======================================================================================================================
154 	QE_CheckAutoSave If five minutes have passed since making a change and the map hasn't been saved, save it out.
155  =======================================================================================================================
156  */
QE_CheckAutoSave(void)157 void QE_CheckAutoSave(void) {
158 	static bool inAutoSave = false;
159 	static bool autoToggle = false;
160 	if (inAutoSave) {
161 		Sys_Status("Did not autosave due recursive entry into autosave routine\n");
162 		return;
163 	}
164 
165 	if ( !mapModified ) {
166 		return;
167 	}
168 
169 	inAutoSave = true;
170 
171 	if ( g_PrefsDlg.m_bAutoSave ) {
172 		CString strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving...";
173 		Sys_Status(strMsg.GetBuffer(0), 0);
174 
175 		if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0) {
176 			Map_Snapshot();
177 		} else {
178 			Map_SaveFile(ValueForKey(g_qeglobals.d_project_entity, (autoToggle == 0) ? "autosave1" : "autosave2" ), false, true);
179 			autoToggle ^= 1;
180 		}
181 		Sys_Status("Autosaving...Saved.", 0);
182 		mapModified = 0;		// DHM - _D3XP
183 	} else {
184 		common->Printf("Autosave skipped...\n");
185 		Sys_Status("Autosave skipped...", 0);
186 	}
187 
188 	inAutoSave = false;
189 }
190 
191 /*
192  =======================================================================================================================
193  =======================================================================================================================
194  */
195 
196 const char	*g_pPathFixups[] = {
197 	"basepath",
198 
199 	// "remotebasepath",
200 	"entitypath",
201 
202 	// "texturepath",
203 	"autosave",
204 
205 	// "mapspath"
206 };
207 
208 const int	g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof (const char *);
209 
210 /*
211  =======================================================================================================================
212 	QE_LoadProject
213  =======================================================================================================================
214  */
QE_LoadProject(char * projectfile)215 bool QE_LoadProject(char *projectfile) {
216 	char		*data;
217 	ID_TIME_T		time;
218 
219 	common->Printf("QE_LoadProject (%s)\n", projectfile);
220 
221 	if ( fileSystem->ReadFile( projectfile, reinterpret_cast < void ** > (&data), &time) <= 0 ) {
222 		return false;
223 	}
224 
225 	g_strProject = projectfile;
226 	g_PrefsDlg.m_strLastProject = projectfile;
227 	g_PrefsDlg.SavePrefs();
228 
229 	CString strData = data;
230 
231 	fileSystem->FreeFile( data );
232 
233 	StartTokenParsing(strData.GetBuffer(0));
234 	g_qeglobals.d_project_entity = Entity_Parse(true);
235 	if (!g_qeglobals.d_project_entity) {
236 		Error("Couldn't parse %s", projectfile);
237 	}
238 
239 	// set here some default project settings you need
240 	if (strlen(ValueForKey(g_qeglobals.d_project_entity, "brush_primit")) == 0) {
241 		SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", "0");
242 	}
243 
244 	g_qeglobals.m_bBrushPrimitMode = IntForKey(g_qeglobals.d_project_entity, "brush_primit");
245 
246 	Eclass_InitForSourceDirectory(ValueForKey(g_qeglobals.d_project_entity, "entitypath"));
247 	g_Inspectors->FillClassList();	// list in entity window
248 
249 	Map_New();
250 
251 	// FillTextureMenu();
252 	FillBSPMenu();
253 
254 	return true;
255 }
256 
257 /*
258  =======================================================================================================================
259 	QE_SaveProject �
260  =======================================================================================================================
261  */
QE_SaveProject(const char * pProjectFile)262 bool QE_SaveProject(const char *pProjectFile) {
263 
264 	idFile *file = fileSystem->OpenFileWrite(pProjectFile);
265 	if ( !file ) {
266 		return false;
267 	}
268 
269 	file->Write("{\n", 2);
270 
271 	int count = g_qeglobals.d_project_entity->epairs.GetNumKeyVals();
272 	for (int i = 0; i < count; i++) {
273 		file->WriteFloatString( "\"%s\" \"%s\"\n", g_qeglobals.d_project_entity->epairs.GetKeyVal(i)->GetKey().c_str(), g_qeglobals.d_project_entity->epairs.GetKeyVal(i)->GetValue().c_str());
274 	}
275 
276 	file->Write("}\n", 2);
277 
278 	fileSystem->CloseFile( file );
279 
280 	return true;
281 }
282 
283 /* QE_KeyDown */
284 #define SPEED_MOVE	32
285 #define SPEED_TURN	22.5
286 
287 /*
288  =======================================================================================================================
289 	ConnectEntities Sets target / name on the two entities selected from the first selected to the secon
290  =======================================================================================================================
291  */
ConnectEntities(void)292 void ConnectEntities(void) {
293 	entity_t	*e1;
294 	const char		*target;
295 	idStr strTarget;
296 	int i, t;
297 
298 	if (g_qeglobals.d_select_count < 2) {
299 		Sys_Status("Must have at least two brushes selected.", 0);
300 		Sys_Beep();
301 		return;
302 	}
303 
304 	e1 = g_qeglobals.d_select_order[0]->owner;
305 
306 	for (i = 0; i < g_qeglobals.d_select_count; i++) {
307 		if (g_qeglobals.d_select_order[i]->owner == world_entity) {
308 			Sys_Status("Can't connect to the world.", 0);
309 			Sys_Beep();
310 			return;
311 		}
312 	}
313 
314 	for (i = 1; i < g_qeglobals.d_select_count; i++) {
315 		if (e1 == g_qeglobals.d_select_order[i]->owner) {
316 			Sys_Status("Brushes are from same entity.", 0);
317 			Sys_Beep();
318 			return;
319 		}
320 	}
321 
322 	target = ValueForKey(e1, "target");
323 	if ( target && *target) {
324 		for (t = 1; t < 2048; t++) {
325 			target = ValueForKey(e1, va("target%i", t));
326 			if (target && *target) {
327 				continue;
328 			} else {
329 				break;
330 			}
331 		}
332 	} else {
333 		t = 0;
334 	}
335 
336 	for (i = 1; i < g_qeglobals.d_select_count; i++) {
337 		target = ValueForKey(g_qeglobals.d_select_order[i]->owner, "name");
338 		if (target && *target) {
339 			strTarget = target;
340 		} else {
341 			UniqueTargetName(strTarget);
342 		}
343 		if (t == 0) {
344 			SetKeyValue(e1, "target", strTarget);
345 		} else {
346 			SetKeyValue(e1, va("target%i", t), strTarget);
347 		}
348 		t++;
349 	}
350 
351 	Sys_UpdateWindows(W_XY | W_CAMERA);
352 
353 	Select_Deselect();
354 	Select_Brush(g_qeglobals.d_select_order[1]);
355 }
356 
357 /*
358  =======================================================================================================================
359  =======================================================================================================================
360  */
QE_SingleBrush(bool bQuiet,bool entityOK)361 bool QE_SingleBrush(bool bQuiet, bool entityOK) {
362 	if ((selected_brushes.next == &selected_brushes) || (selected_brushes.next->next != &selected_brushes)) {
363 		if (!bQuiet) {
364 			Sys_Status("Error: you must have a single brush selected\n");
365 		}
366 
367 		return false;
368 	}
369 
370 	if (!entityOK && selected_brushes.next->owner->eclass->fixedsize) {
371 		if (!bQuiet) {
372 			Sys_Status("Error: you cannot manipulate fixed size entities\n");
373 		}
374 
375 		return false;
376 	}
377 
378 	return true;
379 }
380 
381 /*
382  =======================================================================================================================
383  =======================================================================================================================
384  */
QE_Init(void)385 void QE_Init(void) {
386 	/* initialize variables */
387 	g_qeglobals.d_gridsize = 8;
388 	g_qeglobals.d_showgrid = true;
389 
390 	/*
391 	 * other stuff �
392 	 * FIXME: idMaterial Texture_Init (true); Cam_Init (); XY_Init ();
393 	 */
394 	Z_Init();
395 }
396 
397 
398 int g_numbrushes, g_numentities;
399 
400 /*
401  =======================================================================================================================
402  =======================================================================================================================
403  */
QE_CountBrushesAndUpdateStatusBar(void)404 void QE_CountBrushesAndUpdateStatusBar(void) {
405 	static int	s_lastbrushcount, s_lastentitycount;
406 	static bool s_didonce;
407 
408 	// entity_t *e;
409 	brush_t		*b, *next;
410 
411 	g_numbrushes = 0;
412 	g_numentities = 0;
413 
414 	if (active_brushes.next != NULL) {
415 		for (b = active_brushes.next; b != NULL && b != &active_brushes; b = next) {
416 			next = b->next;
417 			if (b->brush_faces) {
418 				if (!b->owner->eclass->fixedsize) {
419 					g_numbrushes++;
420 				}
421 				else {
422 					g_numentities++;
423 				}
424 			}
425 		}
426 	}
427 
428 	/*
429 	 * if ( entities.next != NULL ) { for ( e = entities.next ; e != &entities &&
430 	 * g_numentities != MAX_MAP_ENTITIES ; e = e->next) { g_numentities++; } }
431 	 */
432 	if (((g_numbrushes != s_lastbrushcount) || (g_numentities != s_lastentitycount)) || (!s_didonce)) {
433 		Sys_UpdateStatusBar();
434 
435 		s_lastbrushcount = g_numbrushes;
436 		s_lastentitycount = g_numentities;
437 		s_didonce = true;
438 	}
439 }
440