2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
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.
32 // Leonardo Zide (leo@lokigames.com)
37 #include "globaldefs.h"
41 #include "debugging/debugging.h"
43 #include "ifilesystem.h"
48 #include <uilib/uilib.h>
50 #include "stream/textfilestream.h"
52 #include "stream/stringstream.h"
56 #include "gtkutil/messagebox.h"
61 #include "camwindow.h"
62 #include "mainframe.h"
63 #include "preferences.h"
68 QEGlobals_t g_qeglobals;
77 // VFS initialization -----------------------
78 // we will call GlobalFileSystem().initDirectory, giving the directories to look in (for files in pk3's and for standalone files)
79 // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order
80 // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too
82 const char* enginepath = EnginePath_get();
83 const char* homepath = g_qeglobals.m_userEnginePath.c_str(); // returns enginepath if not homepath is not set
85 const char* basegame = basegame_get();
86 const char* gamename = gamename_get(); // returns basegame if gamename is not set
89 StringOutputStream editorGamePath( 256 );
90 editorGamePath << GlobalRadiant().getDataPath() << DEFAULT_EDITORVFS_DIRNAME;
91 GlobalFileSystem().initDirectory( editorGamePath.c_str() );
93 globalOutputStream() << "engine path: " << enginepath << "\n";
94 globalOutputStream() << "home path: " << homepath << "\n";
95 globalOutputStream() << "base game: " << basegame << "\n";
96 globalOutputStream() << "game name: " << gamename << "\n";
98 // if we have a mod dir
99 if ( !string_equal( gamename, basegame ) ) {
100 // if we have a home dir
101 if ( !string_equal( homepath, enginepath ) )
103 // ~/.<gameprefix>/<fs_game>
104 if ( homepath && !g_disableHomePath ) {
105 StringOutputStream userGamePath( 256 );
106 userGamePath << homepath << gamename << '/';
107 GlobalFileSystem().initDirectory( userGamePath.c_str() );
111 // <fs_basepath>/<fs_game>
112 if ( !g_disableEnginePath ) {
113 StringOutputStream globalGamePath( 256 );
114 globalGamePath << enginepath << gamename << '/';
115 GlobalFileSystem().initDirectory( globalGamePath.c_str() );
119 // if we have a home dir
120 if ( !string_equal( homepath, enginepath ) )
122 // ~/.<gameprefix>/<fs_main>
123 if ( homepath && !g_disableHomePath ) {
124 StringOutputStream userBasePath( 256 );
125 userBasePath << homepath << basegame << '/';
126 GlobalFileSystem().initDirectory( userBasePath.c_str() );
130 // <fs_basepath>/<fs_main>
131 if ( !g_disableEnginePath ) {
132 StringOutputStream globalBasePath( 256 );
133 globalBasePath << enginepath << basegame << '/';
134 GlobalFileSystem().initDirectory( globalBasePath.c_str() );
138 for ( int i = 0; i < g_pakPathCount; i++ ) {
139 if (g_strcmp0( g_strPakPath[i].c_str(), "")) {
140 GlobalFileSystem().initDirectory( g_strPakPath[i].c_str() );
145 int g_numbrushes = 0;
146 int g_numentities = 0;
148 void QE_UpdateStatusBar(){
150 sprintf( buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
151 g_pParentWnd->SetStatusText( g_pParentWnd->m_brushcount_status, buffer );
154 SimpleCounter g_brushCount;
156 void QE_brushCountChanged(){
157 g_numbrushes = int(g_brushCount.get() );
158 QE_UpdateStatusBar();
161 SimpleCounter g_entityCount;
163 void QE_entityCountChanged(){
164 g_numentities = int(g_entityCount.get() );
165 QE_UpdateStatusBar();
168 bool ConfirmModified( const char* title ){
169 if ( !Map_Modified( g_map ) ) {
173 auto result = ui::alert( MainFrame_getWindow(), "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 );
174 if ( result == ui::alert_response::CANCEL ) {
177 if ( result == ui::alert_response::YES ) {
178 if ( Map_Unnamed( g_map ) ) {
190 // this is expected to not be used since
191 // ".[ExecutableType]" is replaced by "[ExecutableExt]"
192 const char *exe_ext = GDEF_OS_EXE_EXT;
193 build_set_variable( "ExecutableType", exe_ext[0] == '\0' ? exe_ext : exe_ext + 1 );
195 build_set_variable( "ExecutableExt", GDEF_OS_EXE_EXT );
196 build_set_variable( "RadiantPath", AppPath_get() );
197 build_set_variable( "EnginePath", EnginePath_get() );
198 build_set_variable( "UserEnginePath", g_qeglobals.m_userEnginePath.c_str() );
200 build_set_variable( "MonitorAddress", ( g_WatchBSP_Enabled ) ? "127.0.0.1:39000" : "" );
202 build_set_variable( "GameName", gamename_get() );
204 StringBuffer ExtraQ3map2Args;
206 for ( int i = 0; i < g_pakPathCount; i++ ) {
207 if ( g_strcmp0( g_strPakPath[i].c_str(), "") ) {
208 ExtraQ3map2Args.push_string( " -fs_pakpath \"" );
209 ExtraQ3map2Args.push_string( g_strPakPath[i].c_str() );
210 ExtraQ3map2Args.push_string( "\"" );
215 if ( g_disableEnginePath ) {
216 ExtraQ3map2Args.push_string( " -fs_nobasepath " );
219 if ( g_disableHomePath ) {
220 ExtraQ3map2Args.push_string( " -fs_nohomepath " );
223 build_set_variable( "ExtraQ3map2Args", ExtraQ3map2Args.c_str() );
225 const char* mapname = Map_Name( g_map );
226 StringOutputStream name( 256 );
227 name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".bsp";
229 build_set_variable( "MapFile", mapname );
230 build_set_variable( "BspFile", name.c_str() );
234 build_clear_variables();
237 class ArrayCommandListener : public CommandListener
241 ArrayCommandListener(){
242 m_array = g_ptr_array_new();
245 ~ArrayCommandListener(){
246 g_ptr_array_free( m_array, TRUE );
249 void execute( const char* command ){
250 g_ptr_array_add( m_array, g_strdup( command ) );
253 GPtrArray* array() const {
258 class BatchCommandListener : public CommandListener
260 TextOutputStream& m_file;
261 std::size_t m_commandCount;
262 const char* m_outputRedirect;
264 BatchCommandListener( TextOutputStream& file, const char* outputRedirect ) : m_file( file ), m_commandCount( 0 ), m_outputRedirect( outputRedirect ){
267 void execute( const char* command ){
269 if ( m_commandCount == 0 ) {
276 m_file << "\"" << m_outputRedirect << "\"";
282 bool Region_cameraValid(){
283 Vector3 vOrig( vector3_snapped( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ) ) );
285 for ( int i = 0 ; i < 3 ; i++ )
287 if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) {
295 void RunBSP( const char* name ){
296 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503
297 // make sure we don't attempt to region compile a map with the camera outside the region
298 if ( region_active && !Region_cameraValid() ) {
299 globalErrorStream() << "The camera must be in the region to start a region compile.\n";
305 if ( Map_Unnamed( g_map ) ) {
306 globalOutputStream() << "build cancelled\n";
310 if ( g_SnapShots_Enabled && !Map_Unnamed( g_map ) && Map_Modified( g_map ) ) {
314 if ( region_active ) {
315 const char* mapname = Map_Name( g_map );
316 StringOutputStream name( 256 );
317 name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".reg";
318 Map_SaveRegion( name.c_str() );
325 if ( g_WatchBSP_Enabled ) {
326 ArrayCommandListener listener;
327 build_run( name, listener );
328 // grab the file name for engine running
329 const char* fullname = Map_Name( g_map );
330 StringOutputStream bspname( 64 );
331 bspname << StringRange( path_get_filename_start( fullname ), path_get_filename_base_end( fullname ) );
332 BuildMonitor_Run( listener.array(), bspname.c_str() );
336 char junkpath[PATH_MAX];
337 strcpy( junkpath, SettingsPath_get() );
338 strcat( junkpath, "junk.txt" );
340 char batpath[PATH_MAX];
342 strcpy( batpath, SettingsPath_get() );
343 strcat( batpath, "qe3bsp.sh" );
344 #elif GDEF_OS_WINDOWS
345 strcpy( batpath, SettingsPath_get() );
346 strcat( batpath, "qe3bsp.bat" );
348 #error "unsupported platform"
350 bool written = false;
352 TextFileOutputStream batchFile( batpath );
353 if ( !batchFile.failed() ) {
355 batchFile << "#!/bin/sh \n\n";
357 BatchCommandListener listener( batchFile, junkpath );
358 build_run( name, listener );
364 chmod( batpath, 0744 );
366 globalOutputStream() << "Writing the compile script to '" << batpath << "'\n";
367 globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n";
368 Q_Exec( batpath, NULL, NULL, true, false );
375 // =============================================================================
378 void Sys_SetTitle( const char *text, bool modified ){
379 StringOutputStream title;
386 gtk_window_set_title(MainFrame_getWindow(), title.c_str() );
389 bool g_bWaitCursor = false;
391 void Sys_BeginWait( void ){
392 ScreenUpdates_Disable( "Processing...", "Please Wait" );
393 GdkCursor *cursor = gdk_cursor_new( GDK_WATCH );
394 gdk_window_set_cursor( gtk_widget_get_window(MainFrame_getWindow()), cursor );
395 gdk_cursor_unref( cursor );
396 g_bWaitCursor = true;
399 void Sys_EndWait( void ){
400 ScreenUpdates_Enable();
401 gdk_window_set_cursor(gtk_widget_get_window(MainFrame_getWindow()), 0 );
402 g_bWaitCursor = false;
405 void Sys_Beep( void ){