]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/qe3.cpp
Merge branch 'master' of git://git.xonotic.org/xonotic/netradiant
[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("UserEnginePath", g_qeglobals.m_userEnginePath.c_str());
175   build_set_variable("MonitorAddress", (g_WatchBSP_Enabled) ? "127.0.0.1:39000" : "");
176   build_set_variable("GameName", gamename_get());
177
178   const char* mapname = Map_Name(g_map);
179   StringOutputStream name(256);
180   name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".bsp";
181
182   build_set_variable("MapFile", mapname);
183   build_set_variable("BspFile", name.c_str());
184 }
185
186 void bsp_shutdown()
187 {
188   build_clear_variables();
189 }
190
191 class ArrayCommandListener : public CommandListener
192 {
193   GPtrArray* m_array;
194 public:
195   ArrayCommandListener()
196   {
197     m_array = g_ptr_array_new();
198   }
199   ~ArrayCommandListener()
200   {
201     g_ptr_array_free(m_array, TRUE);
202   }
203
204   void execute(const char* command)
205   {
206     g_ptr_array_add(m_array, g_strdup(command));
207   }
208
209   GPtrArray* array() const
210   {
211     return m_array;
212   }
213 };
214
215 class BatchCommandListener : public CommandListener
216 {
217   TextOutputStream& m_file;
218   std::size_t m_commandCount;
219   const char* m_outputRedirect;
220 public:
221   BatchCommandListener(TextOutputStream& file, const char* outputRedirect) : m_file(file), m_commandCount(0), m_outputRedirect(outputRedirect)
222   {
223   }
224
225   void execute(const char* command)
226   {
227     m_file << command;
228     if (m_commandCount == 0)
229     {
230       m_file << " > ";
231     }
232     else
233     {
234       m_file << " >> ";
235     }
236     m_file << "\"" << m_outputRedirect << "\"";
237     m_file << "\n";
238     ++m_commandCount;
239   }
240 };
241
242 bool Region_cameraValid()
243 {
244   Vector3 vOrig(vector3_snapped(Camera_getOrigin(*g_pParentWnd->GetCamWnd())));
245
246   for (int i=0 ; i<3 ; i++)
247   {
248     if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
249     {
250       return false;
251     }
252   }
253   return true;
254 }
255
256
257 void RunBSP(const char* name)
258 {
259   // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503
260   // make sure we don't attempt to region compile a map with the camera outside the region
261   if (region_active && !Region_cameraValid())
262   {
263     globalErrorStream() << "The camera must be in the region to start a region compile.\n";
264     return;
265   }
266
267   SaveMap();
268
269   if(Map_Unnamed(g_map))
270   {
271     globalOutputStream() << "build cancelled\n";
272     return;
273   }
274
275   if (g_SnapShots_Enabled && !Map_Unnamed(g_map) && Map_Modified(g_map))
276   {
277     Map_Snapshot();
278   }
279
280   if (region_active)
281   {
282     const char* mapname = Map_Name(g_map);
283     StringOutputStream name(256);
284     name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".reg";
285     Map_SaveRegion(name.c_str());
286   }
287
288   Pointfile_Delete();
289
290   bsp_init();
291
292   if (g_WatchBSP_Enabled)
293   {
294     ArrayCommandListener listener;
295     build_run(name, listener);
296     // grab the file name for engine running
297     const char* fullname = Map_Name(g_map);
298     StringOutputStream bspname(64);
299     bspname << StringRange(path_get_filename_start(fullname), path_get_filename_base_end(fullname));
300     BuildMonitor_Run( listener.array(), bspname.c_str() );
301   }
302   else
303   {
304     char junkpath[PATH_MAX];
305     strcpy(junkpath, SettingsPath_get());
306     strcat(junkpath, "junk.txt");
307
308     char batpath[PATH_MAX];
309 #if defined(POSIX)
310     strcpy(batpath, SettingsPath_get());
311     strcat(batpath, "qe3bsp.sh");
312 #elif defined(WIN32)
313     strcpy(batpath, SettingsPath_get());
314     strcat(batpath, "qe3bsp.bat");
315 #else
316 #error "unsupported platform"
317 #endif
318     bool written = false;
319     {
320       TextFileOutputStream batchFile(batpath);
321       if(!batchFile.failed())
322       {
323 #if defined (POSIX)
324         batchFile << "#!/bin/sh \n\n";
325 #endif
326         BatchCommandListener listener(batchFile, junkpath);
327         build_run(name, listener);
328         written = true;
329       }
330     }
331     if(written)
332     {
333 #if defined (POSIX)
334       chmod (batpath, 0744);
335 #endif
336       globalOutputStream() << "Writing the compile script to '" << batpath << "'\n";
337       globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n";
338       Q_Exec(batpath, NULL, NULL, true, false);
339     }
340   }
341
342   bsp_shutdown();
343 }
344
345 // =============================================================================
346 // Sys_ functions
347
348 void Sys_SetTitle(const char *text, bool modified)
349 {
350   StringOutputStream title;
351   title << text;
352
353   if(modified)
354   {
355     title << " *";
356   }
357
358   gtk_window_set_title(MainFrame_getWindow(), title.c_str());
359 }
360
361 bool g_bWaitCursor = false;
362
363 void Sys_BeginWait (void)
364 {
365   ScreenUpdates_Disable("Processing...", "Please Wait");
366   GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
367   gdk_window_set_cursor(GTK_WIDGET(MainFrame_getWindow())->window, cursor);
368   gdk_cursor_unref (cursor);
369   g_bWaitCursor = true;
370 }
371
372 void Sys_EndWait (void)
373 {
374   ScreenUpdates_Enable();
375   gdk_window_set_cursor(GTK_WIDGET(MainFrame_getWindow())->window, 0);
376   g_bWaitCursor = false;
377 }
378
379 void Sys_Beep (void)
380 {
381   gdk_beep();
382 }
383