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