]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/qe3.cpp
4de16016b47204021291864ee93e9d083ab50032
[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/gtk.h>
45 #include <uilib/uilib.h>
46
47 #include "stream/textfilestream.h"
48 #include "cmdlib.h"
49 #include "stream/stringstream.h"
50 #include "os/path.h"
51 #include "scenelib.h"
52
53 #include "gtkutil/messagebox.h"
54 #include "error.h"
55 #include "map.h"
56 #include "build.h"
57 #include "points.h"
58 #include "camwindow.h"
59 #include "mainframe.h"
60 #include "preferences.h"
61 #include "watchbsp.h"
62 #include "autosave.h"
63 #include "convert.h"
64
65 QEGlobals_t g_qeglobals;
66
67
68 #if defined( WIN32 )
69 #define PATH_MAX 260
70 #endif
71
72
73 void QE_InitVFS(){
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                 // ~/.<gameprefix>/<fs_game>
87                 if ( userRoot ) {
88                         StringOutputStream userGamePath( 256 );
89                         userGamePath << userRoot << gamename << '/';
90                         GlobalFileSystem().initDirectory( userGamePath.c_str() );
91                 }
92
93                 // <fs_basepath>/<fs_game>
94                 {
95                         StringOutputStream globalGamePath( 256 );
96                         globalGamePath << globalRoot << gamename << '/';
97                         GlobalFileSystem().initDirectory( globalGamePath.c_str() );
98                 }
99         }
100
101         // ~/.<gameprefix>/<fs_main>
102         if ( userRoot ) {
103                 StringOutputStream userBasePath( 256 );
104                 userBasePath << userRoot << basegame << '/';
105                 GlobalFileSystem().initDirectory( userBasePath.c_str() );
106         }
107
108         // <fs_basepath>/<fs_main>
109         {
110                 StringOutputStream globalBasePath( 256 );
111                 globalBasePath << globalRoot << basegame << '/';
112                 GlobalFileSystem().initDirectory( globalBasePath.c_str() );
113         }
114 }
115
116 int g_numbrushes = 0;
117 int g_numentities = 0;
118
119 void QE_UpdateStatusBar(){
120         char buffer[128];
121         sprintf( buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
122         g_pParentWnd->SetStatusText( g_pParentWnd->m_brushcount_status, buffer );
123 }
124
125 SimpleCounter g_brushCount;
126
127 void QE_brushCountChanged(){
128         g_numbrushes = int(g_brushCount.get() );
129         QE_UpdateStatusBar();
130 }
131
132 SimpleCounter g_entityCount;
133
134 void QE_entityCountChanged(){
135         g_numentities = int(g_entityCount.get() );
136         QE_UpdateStatusBar();
137 }
138
139 bool ConfirmModified( const char* title ){
140         if ( !Map_Modified( g_map ) ) {
141                 return true;
142         }
143
144         auto result = MainFrame_getWindow().alert( "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, ui::alert_type::YESNOCANCEL, ui::alert_icon::Question );
145         if ( result == ui::alert_response::CANCEL ) {
146                 return false;
147         }
148         if ( result == ui::alert_response::YES ) {
149                 if ( Map_Unnamed( g_map ) ) {
150                         return Map_SaveAs();
151                 }
152                 else
153                 {
154                         return Map_Save();
155                 }
156         }
157         return true;
158 }
159
160 void bsp_init(){
161         build_set_variable( "RadiantPath", AppPath_get() );
162         build_set_variable( "ExecutableType", RADIANT_EXECUTABLE );
163         build_set_variable( "EnginePath", EnginePath_get() );
164         build_set_variable( "UserEnginePath", g_qeglobals.m_userEnginePath.c_str() );
165         build_set_variable( "MonitorAddress", ( g_WatchBSP_Enabled ) ? "127.0.0.1:39000" : "" );
166         build_set_variable( "GameName", gamename_get() );
167
168         const char* mapname = Map_Name( g_map );
169         StringOutputStream name( 256 );
170         name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".bsp";
171
172         build_set_variable( "MapFile", mapname );
173         build_set_variable( "BspFile", name.c_str() );
174 }
175
176 void bsp_shutdown(){
177         build_clear_variables();
178 }
179
180 class ArrayCommandListener : public CommandListener
181 {
182 GPtrArray* m_array;
183 public:
184 ArrayCommandListener(){
185         m_array = g_ptr_array_new();
186 }
187 ~ArrayCommandListener(){
188         g_ptr_array_free( m_array, TRUE );
189 }
190
191 void execute( const char* command ){
192         g_ptr_array_add( m_array, g_strdup( command ) );
193 }
194
195 GPtrArray* array() const {
196         return m_array;
197 }
198 };
199
200 class BatchCommandListener : public CommandListener
201 {
202 TextOutputStream& m_file;
203 std::size_t m_commandCount;
204 const char* m_outputRedirect;
205 public:
206 BatchCommandListener( TextOutputStream& file, const char* outputRedirect ) : m_file( file ), m_commandCount( 0 ), m_outputRedirect( outputRedirect ){
207 }
208
209 void execute( const char* command ){
210         m_file << command;
211         if ( m_commandCount == 0 ) {
212                 m_file << " > ";
213         }
214         else
215         {
216                 m_file << " >> ";
217         }
218         m_file << "\"" << m_outputRedirect << "\"";
219         m_file << "\n";
220         ++m_commandCount;
221 }
222 };
223
224 bool Region_cameraValid(){
225         Vector3 vOrig( vector3_snapped( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ) ) );
226
227         for ( int i = 0 ; i < 3 ; i++ )
228         {
229                 if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) {
230                         return false;
231                 }
232         }
233         return true;
234 }
235
236
237 void RunBSP( const char* name ){
238         // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503
239         // make sure we don't attempt to region compile a map with the camera outside the region
240         if ( region_active && !Region_cameraValid() ) {
241                 globalErrorStream() << "The camera must be in the region to start a region compile.\n";
242                 return;
243         }
244
245         SaveMap();
246
247         if ( Map_Unnamed( g_map ) ) {
248                 globalOutputStream() << "build cancelled\n";
249                 return;
250         }
251
252         if ( g_SnapShots_Enabled && !Map_Unnamed( g_map ) && Map_Modified( g_map ) ) {
253                 Map_Snapshot();
254         }
255
256         if ( region_active ) {
257                 const char* mapname = Map_Name( g_map );
258                 StringOutputStream name( 256 );
259                 name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".reg";
260                 Map_SaveRegion( name.c_str() );
261         }
262
263         Pointfile_Delete();
264
265         bsp_init();
266
267         if ( g_WatchBSP_Enabled ) {
268                 ArrayCommandListener listener;
269                 build_run( name, listener );
270                 // grab the file name for engine running
271                 const char* fullname = Map_Name( g_map );
272                 StringOutputStream bspname( 64 );
273                 bspname << StringRange( path_get_filename_start( fullname ), path_get_filename_base_end( fullname ) );
274                 BuildMonitor_Run( listener.array(), bspname.c_str() );
275         }
276         else
277         {
278                 char junkpath[PATH_MAX];
279                 strcpy( junkpath, SettingsPath_get() );
280                 strcat( junkpath, "junk.txt" );
281
282                 char batpath[PATH_MAX];
283 #if defined( POSIX )
284                 strcpy( batpath, SettingsPath_get() );
285                 strcat( batpath, "qe3bsp.sh" );
286 #elif defined( WIN32 )
287                 strcpy( batpath, SettingsPath_get() );
288                 strcat( batpath, "qe3bsp.bat" );
289 #else
290 #error "unsupported platform"
291 #endif
292                 bool written = false;
293                 {
294                         TextFileOutputStream batchFile( batpath );
295                         if ( !batchFile.failed() ) {
296 #if defined ( POSIX )
297                                 batchFile << "#!/bin/sh \n\n";
298 #endif
299                                 BatchCommandListener listener( batchFile, junkpath );
300                                 build_run( name, listener );
301                                 written = true;
302                         }
303                 }
304                 if ( written ) {
305 #if defined ( POSIX )
306                         chmod( batpath, 0744 );
307 #endif
308                         globalOutputStream() << "Writing the compile script to '" << batpath << "'\n";
309                         globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n";
310                         Q_Exec( batpath, NULL, NULL, true, false );
311                 }
312         }
313
314         bsp_shutdown();
315 }
316
317 // =============================================================================
318 // Sys_ functions
319
320 void Sys_SetTitle( const char *text, bool modified ){
321         StringOutputStream title;
322         title << text;
323
324         if ( modified ) {
325                 title << " *";
326         }
327
328         gtk_window_set_title(MainFrame_getWindow(), title.c_str() );
329 }
330
331 bool g_bWaitCursor = false;
332
333 void Sys_BeginWait( void ){
334         ScreenUpdates_Disable( "Processing...", "Please Wait" );
335         GdkCursor *cursor = gdk_cursor_new( GDK_WATCH );
336         gdk_window_set_cursor( gtk_widget_get_window(MainFrame_getWindow()), cursor );
337         gdk_cursor_unref( cursor );
338         g_bWaitCursor = true;
339 }
340
341 void Sys_EndWait( void ){
342         ScreenUpdates_Enable();
343         gdk_window_set_cursor(gtk_widget_get_window(MainFrame_getWindow()), 0 );
344         g_bWaitCursor = false;
345 }
346
347 void Sys_Beep( void ){
348         gdk_beep();
349 }