]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/qe3.cpp
q3map2: use "My Games" directory if exists on Win32
[xonotic/netradiant.git] / radiant / qe3.cpp
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 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 GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 /*
23 The following source code is licensed by Id Software and subject to the terms of 
24 its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with 
25 GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT, 
26 please contact Id Software immediately at info@idsoftware.com.
27 */
28
29 //
30 // Linux stuff
31 //
32 // Leonardo Zide (leo@lokigames.com)
33 //
34
35 #include "qe3.h"
36
37 #include "debugging/debugging.h"
38
39 #include "ifilesystem.h"
40 //#include "imap.h"
41
42 #include <map>
43
44 #include <gtk/gtktearoffmenuitem.h>
45
46 #include "stream/textfilestream.h"
47 #include "cmdlib.h"
48 #include "stream/stringstream.h"
49 #include "os/path.h"
50 #include "scenelib.h"
51
52 #include "gtkutil/messagebox.h"
53 #include "error.h"
54 #include "map.h"
55 #include "build.h"
56 #include "points.h"
57 #include "camwindow.h"
58 #include "mainframe.h"
59 #include "preferences.h"
60 #include "watchbsp.h"
61 #include "autosave.h"
62 #include "convert.h"
63
64 QEGlobals_t  g_qeglobals;
65
66
67 #if defined(WIN32)
68 #define PATH_MAX 260
69 #endif
70
71
72 void QE_InitVFS()
73 {
74   // VFS initialization -----------------------
75   // we will call GlobalFileSystem().initDirectory, giving the directories to look in (for files in pk3's and for standalone files)
76   // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order
77   // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too
78
79   const char* gamename = gamename_get();
80   const char* basegame = basegame_get();
81   const char* userRoot = g_qeglobals.m_userEnginePath.c_str();
82   const char* globalRoot = EnginePath_get();
83
84   // if we have a mod dir
85   if(!string_equal(gamename, basegame))
86   {
87     // ~/.<gameprefix>/<fs_game>
88     if(userRoot)
89     {
90       StringOutputStream userGamePath(256);
91       userGamePath << userRoot << gamename << '/';
92       GlobalFileSystem().initDirectory(userGamePath.c_str());
93     }
94
95     // <fs_basepath>/<fs_game>
96     {
97       StringOutputStream globalGamePath(256);
98       globalGamePath << globalRoot << gamename << '/';
99       GlobalFileSystem().initDirectory(globalGamePath.c_str());
100     }
101   }
102
103   // ~/.<gameprefix>/<fs_main>
104   if(userRoot)
105   {
106     StringOutputStream userBasePath(256);
107     userBasePath << userRoot << basegame << '/';
108     GlobalFileSystem().initDirectory(userBasePath.c_str());
109   }
110
111   // <fs_basepath>/<fs_main>
112   {
113     StringOutputStream globalBasePath(256);
114     globalBasePath << globalRoot << basegame << '/';
115     GlobalFileSystem().initDirectory(globalBasePath.c_str());
116   }
117 }
118
119 int g_numbrushes = 0;
120 int g_numentities = 0;
121
122 void QE_UpdateStatusBar()
123 {
124   char buffer[128];
125   sprintf(buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities);
126   g_pParentWnd->SetStatusText(g_pParentWnd->m_brushcount_status, buffer);
127 }
128
129 SimpleCounter g_brushCount;
130
131 void QE_brushCountChanged()
132 {
133   g_numbrushes = int(g_brushCount.get());
134   QE_UpdateStatusBar();
135 }
136
137 SimpleCounter g_entityCount;
138
139 void QE_entityCountChanged()
140 {
141   g_numentities = int(g_entityCount.get());
142   QE_UpdateStatusBar();
143 }
144
145 bool ConfirmModified(const char* title)
146 {
147   if (!Map_Modified(g_map))
148     return true;
149
150   EMessageBoxReturn result = gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, eMB_YESNOCANCEL, eMB_ICONQUESTION);
151   if(result == eIDCANCEL)
152   {
153     return false;
154   }
155   if(result == eIDYES)
156   {
157     if(Map_Unnamed(g_map))
158     {
159       return Map_SaveAs();
160     }
161     else
162     {
163       return Map_Save();
164     }
165   }
166   return true;
167 }
168
169 void bsp_init()
170 {
171   build_set_variable("RadiantPath", AppPath_get());
172   build_set_variable("ExecutableType", RADIANT_EXECUTABLE);
173   build_set_variable("EnginePath", EnginePath_get());
174   build_set_variable("MonitorAddress", (g_WatchBSP_Enabled) ? "127.0.0.1:39000" : "");
175   build_set_variable("GameName", gamename_get());
176
177   const char* mapname = Map_Name(g_map);
178   StringOutputStream name(256);
179   name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".bsp";
180
181   build_set_variable("MapFile", mapname);
182   build_set_variable("BspFile", name.c_str());
183 }
184
185 void bsp_shutdown()
186 {
187   build_clear_variables();
188 }
189
190 class ArrayCommandListener : public CommandListener
191 {
192   GPtrArray* m_array;
193 public:
194   ArrayCommandListener()
195   {
196     m_array = g_ptr_array_new();
197   }
198   ~ArrayCommandListener()
199   {
200     g_ptr_array_free(m_array, TRUE);
201   }
202
203   void execute(const char* command)
204   {
205     g_ptr_array_add(m_array, g_strdup(command));
206   }
207
208   GPtrArray* array() const
209   {
210     return m_array;
211   }
212 };
213
214 class BatchCommandListener : public CommandListener
215 {
216   TextOutputStream& m_file;
217   std::size_t m_commandCount;
218   const char* m_outputRedirect;
219 public:
220   BatchCommandListener(TextOutputStream& file, const char* outputRedirect) : m_file(file), m_commandCount(0), m_outputRedirect(outputRedirect)
221   {
222   }
223
224   void execute(const char* command)
225   {
226     m_file << command;
227     if (m_commandCount == 0)
228     {
229       m_file << " > ";
230     }
231     else
232     {
233       m_file << " >> ";
234     }
235     m_file << "\"" << m_outputRedirect << "\"";
236     m_file << "\n";
237     ++m_commandCount;
238   }
239 };
240
241 bool Region_cameraValid()
242 {
243   Vector3 vOrig(vector3_snapped(Camera_getOrigin(*g_pParentWnd->GetCamWnd())));
244
245   for (int i=0 ; i<3 ; i++)
246   {
247     if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
248     {
249       return false;
250     }
251   }
252   return true;
253 }
254
255
256 void RunBSP(const char* name)
257 {
258   // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503
259   // make sure we don't attempt to region compile a map with the camera outside the region
260   if (region_active && !Region_cameraValid())
261   {
262     globalErrorStream() << "The camera must be in the region to start a region compile.\n";
263     return;
264   }
265
266   SaveMap();
267
268   if(Map_Unnamed(g_map))
269   {
270     globalOutputStream() << "build cancelled\n";
271     return;
272   }
273
274   if (g_SnapShots_Enabled && !Map_Unnamed(g_map) && Map_Modified(g_map))
275   {
276     Map_Snapshot();
277   }
278
279   if (region_active)
280   {
281     const char* mapname = Map_Name(g_map);
282     StringOutputStream name(256);
283     name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".reg";
284     Map_SaveRegion(name.c_str());
285   }
286
287   Pointfile_Delete();
288
289   bsp_init();
290
291   if (g_WatchBSP_Enabled)
292   {
293     ArrayCommandListener listener;
294     build_run(name, listener);
295     // grab the file name for engine running
296     const char* fullname = Map_Name(g_map);
297     StringOutputStream bspname(64);
298     bspname << StringRange(path_get_filename_start(fullname), path_get_filename_base_end(fullname));
299     BuildMonitor_Run( listener.array(), bspname.c_str() );
300   }
301   else
302   {
303     char junkpath[PATH_MAX];
304     strcpy(junkpath, SettingsPath_get());
305     strcat(junkpath, "junk.txt");
306
307     char batpath[PATH_MAX];
308 #if defined(POSIX)
309     strcpy(batpath, SettingsPath_get());
310     strcat(batpath, "qe3bsp.sh");
311 #elif defined(WIN32)
312     strcpy(batpath, SettingsPath_get());
313     strcat(batpath, "qe3bsp.bat");
314 #else
315 #error "unsupported platform"
316 #endif
317     bool written = false;
318     {
319       TextFileOutputStream batchFile(batpath);
320       if(!batchFile.failed())
321       {
322 #if defined (POSIX)
323         batchFile << "#!/bin/sh \n\n";
324 #endif
325         BatchCommandListener listener(batchFile, junkpath);
326         build_run(name, listener);
327         written = true;
328       }
329     }
330     if(written)
331     {
332 #if defined (POSIX)
333       chmod (batpath, 0744);
334 #endif
335       globalOutputStream() << "Writing the compile script to '" << batpath << "'\n";
336       globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n";
337       Q_Exec(batpath, NULL, NULL, true, false);
338     }
339   }
340
341   bsp_shutdown();
342 }
343
344 // =============================================================================
345 // Sys_ functions
346
347 void Sys_SetTitle(const char *text, bool modified)
348 {
349   StringOutputStream title;
350   title << text;
351
352   if(modified)
353   {
354     title << " *";
355   }
356
357   gtk_window_set_title(MainFrame_getWindow(), title.c_str());
358 }
359
360 bool g_bWaitCursor = false;
361
362 void Sys_BeginWait (void)
363 {
364   ScreenUpdates_Disable("Processing...", "Please Wait");
365   GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
366   gdk_window_set_cursor(GTK_WIDGET(MainFrame_getWindow())->window, cursor);
367   gdk_cursor_unref (cursor);
368   g_bWaitCursor = true;
369 }
370
371 void Sys_EndWait (void)
372 {
373   ScreenUpdates_Enable();
374   gdk_window_set_cursor(GTK_WIDGET(MainFrame_getWindow())->window, 0);
375   g_bWaitCursor = false;
376 }
377
378 void Sys_Beep (void)
379 {
380   gdk_beep();
381 }
382