]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/qe3.cpp
add [BspFile] to be used in compile command lines to explicitly refer to the .bsp
[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 #if defined(POSIX)
82   const char* userRoot = g_qeglobals.m_userEnginePath.c_str();
83 #endif
84   const char* globalRoot = EnginePath_get();
85
86   // if we have a mod dir
87   if(!string_equal(gamename, basegame))
88   {
89 #if defined(POSIX)
90     // ~/.<gameprefix>/<fs_game>
91     {
92       StringOutputStream userGamePath(256);
93       userGamePath << userRoot << gamename << '/';
94       GlobalFileSystem().initDirectory(userGamePath.c_str());
95     }
96 #endif
97
98     // <fs_basepath>/<fs_game>
99     {
100       StringOutputStream globalGamePath(256);
101       globalGamePath << globalRoot << gamename << '/';
102       GlobalFileSystem().initDirectory(globalGamePath.c_str());
103     }
104   }
105
106 #if defined(POSIX)
107   // ~/.<gameprefix>/<fs_main>
108   {
109     StringOutputStream userBasePath(256);
110     userBasePath << userRoot << basegame << '/';
111     GlobalFileSystem().initDirectory(userBasePath.c_str());
112   }
113 #endif
114
115   // <fs_basepath>/<fs_main>
116   {
117     StringOutputStream globalBasePath(256);
118     globalBasePath << globalRoot << basegame << '/';
119     GlobalFileSystem().initDirectory(globalBasePath.c_str());
120   }
121 }
122
123 int g_numbrushes = 0;
124 int g_numentities = 0;
125
126 void QE_UpdateStatusBar()
127 {
128   char buffer[128];
129   sprintf(buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities);
130   g_pParentWnd->SetStatusText(g_pParentWnd->m_brushcount_status, buffer);
131 }
132
133 SimpleCounter g_brushCount;
134
135 void QE_brushCountChanged()
136 {
137   g_numbrushes = int(g_brushCount.get());
138   QE_UpdateStatusBar();
139 }
140
141 SimpleCounter g_entityCount;
142
143 void QE_entityCountChanged()
144 {
145   g_numentities = int(g_entityCount.get());
146   QE_UpdateStatusBar();
147 }
148
149 bool ConfirmModified(const char* title)
150 {
151   if (!Map_Modified(g_map))
152     return true;
153
154   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);
155   if(result == eIDCANCEL)
156   {
157     return false;
158   }
159   if(result == eIDYES)
160   {
161     if(Map_Unnamed(g_map))
162     {
163       return Map_SaveAs();
164     }
165     else
166     {
167       return Map_Save();
168     }
169   }
170   return true;
171 }
172
173 void bsp_init()
174 {
175   build_set_variable("RadiantPath", AppPath_get());
176   build_set_variable("ExecutableType", RADIANT_EXECUTABLE);
177   build_set_variable("EnginePath", EnginePath_get());
178   build_set_variable("MonitorAddress", (g_WatchBSP_Enabled) ? "127.0.0.1:39000" : "");
179   build_set_variable("GameName", gamename_get());
180
181   const char* mapname = Map_Name(g_map);
182   StringOutputStream name(256);
183   name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".bsp";
184
185   build_set_variable("MapFile", mapname);
186   build_set_variable("BspFile", name.c_str());
187 }
188
189 void bsp_shutdown()
190 {
191   build_clear_variables();
192 }
193
194 class ArrayCommandListener : public CommandListener
195 {
196   GPtrArray* m_array;
197 public:
198   ArrayCommandListener()
199   {
200     m_array = g_ptr_array_new();
201   }
202   ~ArrayCommandListener()
203   {
204     g_ptr_array_free(m_array, TRUE);
205   }
206
207   void execute(const char* command)
208   {
209     g_ptr_array_add(m_array, g_strdup(command));
210   }
211
212   GPtrArray* array() const
213   {
214     return m_array;
215   }
216 };
217
218 class BatchCommandListener : public CommandListener
219 {
220   TextOutputStream& m_file;
221   std::size_t m_commandCount;
222   const char* m_outputRedirect;
223 public:
224   BatchCommandListener(TextOutputStream& file, const char* outputRedirect) : m_file(file), m_commandCount(0), m_outputRedirect(outputRedirect)
225   {
226   }
227
228   void execute(const char* command)
229   {
230     m_file << command;
231     if (m_commandCount == 0)
232     {
233       m_file << " > ";
234     }
235     else
236     {
237       m_file << " >> ";
238     }
239     m_file << "\"" << m_outputRedirect << "\"";
240     m_file << "\n";
241     ++m_commandCount;
242   }
243 };
244
245 bool Region_cameraValid()
246 {
247   Vector3 vOrig(vector3_snapped(Camera_getOrigin(*g_pParentWnd->GetCamWnd())));
248
249   for (int i=0 ; i<3 ; i++)
250   {
251     if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
252     {
253       return false;
254     }
255   }
256   return true;
257 }
258
259
260 void RunBSP(const char* name)
261 {
262   // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503
263   // make sure we don't attempt to region compile a map with the camera outside the region
264   if (region_active && !Region_cameraValid())
265   {
266     globalErrorStream() << "The camera must be in the region to start a region compile.\n";
267     return;
268   }
269
270   SaveMap();
271
272   if(Map_Unnamed(g_map))
273   {
274     globalOutputStream() << "build cancelled\n";
275     return;
276   }
277
278   if (g_SnapShots_Enabled && !Map_Unnamed(g_map) && Map_Modified(g_map))
279   {
280     Map_Snapshot();
281   }
282
283   if (region_active)
284   {
285     const char* mapname = Map_Name(g_map);
286     StringOutputStream name(256);
287     name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".reg";
288     Map_SaveRegion(name.c_str());
289   }
290
291   Pointfile_Delete();
292
293   bsp_init();
294
295   if (g_WatchBSP_Enabled)
296   {
297     ArrayCommandListener listener;
298     build_run(name, listener);
299     // grab the file name for engine running
300     const char* fullname = Map_Name(g_map);
301     StringOutputStream bspname(64);
302     bspname << StringRange(path_get_filename_start(fullname), path_get_filename_base_end(fullname));
303     BuildMonitor_Run( listener.array(), bspname.c_str() );
304   }
305   else
306   {
307     char junkpath[PATH_MAX];
308     strcpy(junkpath, SettingsPath_get());
309     strcat(junkpath, "junk.txt");
310
311     char batpath[PATH_MAX];
312 #if defined(POSIX)
313     strcpy(batpath, SettingsPath_get());
314     strcat(batpath, "qe3bsp.sh");
315 #elif defined(WIN32)
316     strcpy(batpath, SettingsPath_get());
317     strcat(batpath, "qe3bsp.bat");
318 #else
319 #error "unsupported platform"
320 #endif
321     bool written = false;
322     {
323       TextFileOutputStream batchFile(batpath);
324       if(!batchFile.failed())
325       {
326 #if defined (POSIX)
327         batchFile << "#!/bin/sh \n\n";
328 #endif
329         BatchCommandListener listener(batchFile, junkpath);
330         build_run(name, listener);
331         written = true;
332       }
333     }
334     if(written)
335     {
336 #if defined (POSIX)
337       chmod (batpath, 0744);
338 #endif
339       globalOutputStream() << "Writing the compile script to '" << batpath << "'\n";
340       globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n";
341       Q_Exec(batpath, NULL, NULL, true, false);
342     }
343   }
344
345   bsp_shutdown();
346 }
347
348 // =============================================================================
349 // Sys_ functions
350
351 void Sys_SetTitle(const char *text, bool modified)
352 {
353   StringOutputStream title;
354   title << text;
355
356   if(modified)
357   {
358     title << " *";
359   }
360
361   gtk_window_set_title(MainFrame_getWindow(), title.c_str());
362 }
363
364 bool g_bWaitCursor = false;
365
366 void Sys_BeginWait (void)
367 {
368   ScreenUpdates_Disable("Processing...", "Please Wait");
369   GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
370   gdk_window_set_cursor(GTK_WIDGET(MainFrame_getWindow())->window, cursor);
371   gdk_cursor_unref (cursor);
372   g_bWaitCursor = true;
373 }
374
375 void Sys_EndWait (void)
376 {
377   ScreenUpdates_Enable();
378   gdk_window_set_cursor(GTK_WIDGET(MainFrame_getWindow())->window, 0);
379   g_bWaitCursor = false;
380 }
381
382 void Sys_Beep (void)
383 {
384   gdk_beep();
385 }
386