2007-11-04 03:51:54 +00:00
/*
Copyright ( C ) 1999 - 2007 id Software , Inc . and contributors .
For a list of contributors , see the accompanying CONTRIBUTORS file .
This file is part of GtkRadiant .
GtkRadiant is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
GtkRadiant is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with GtkRadiant ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# if defined (__linux__) || defined (__APPLE__)
# include <gdk/gdkx.h>
# include <pwd.h>
2008-06-26 07:52:02 +00:00
# include <unistd.h>
2007-11-04 03:51:54 +00:00
# ifdef __linux__
# include <mntent.h>
# endif
# include <dirent.h>
# include <pthread.h>
# include <sys/wait.h>
# include <signal.h>
# include <sys/stat.h>
# endif
# include <gtk/gtk.h>
2010-11-26 19:50:08 +00:00
# include <gtk/gtkgl.h>
2008-06-26 07:52:02 +00:00
# include <glib/gi18n.h>
2007-11-04 03:51:54 +00:00
# include "stdafx.h"
# include <assert.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <stdlib.h>
# include "watchbsp.h"
# include "filters.h"
2010-11-26 19:50:08 +00:00
# include "glwidget.h"
2007-11-04 03:51:54 +00:00
bool g_bBuildList = false ;
int g_argc ;
char * * g_argv ;
// =============================================================================
// Splash screen
// get rid of it when debugging
# if defined (_DEBUG)
# define SKIP_SPLASH
# endif
static GtkWidget * splash_screen ;
// called based on a timer, or in particular cases when we don't want to keep it around
gint try_destroy_splash ( gpointer data )
{
if ( splash_screen )
{
gtk_widget_destroy ( splash_screen ) ;
splash_screen = NULL ;
}
return FALSE ;
}
static void create_splash ( )
{
GtkWidget * alert_frame , * alert_frame1 , * pixmap ;
splash_screen = gtk_window_new ( GTK_WINDOW_POPUP ) ;
gtk_window_position ( GTK_WINDOW ( splash_screen ) , GTK_WIN_POS_CENTER ) ;
gtk_widget_realize ( splash_screen ) ;
alert_frame1 = gtk_frame_new ( NULL ) ;
gtk_widget_show ( alert_frame1 ) ;
gtk_container_add ( GTK_CONTAINER ( splash_screen ) , alert_frame1 ) ;
gtk_frame_set_shadow_type ( GTK_FRAME ( alert_frame1 ) , GTK_SHADOW_OUT ) ;
alert_frame = gtk_frame_new ( NULL ) ;
gtk_widget_show ( alert_frame ) ;
gtk_container_add ( GTK_CONTAINER ( alert_frame1 ) , alert_frame ) ;
gtk_frame_set_shadow_type ( GTK_FRAME ( alert_frame ) , GTK_SHADOW_IN ) ;
gtk_container_border_width ( GTK_CONTAINER ( alert_frame ) , 3 ) ;
pixmap = gtk_preview_new ( GTK_PREVIEW_COLOR ) ;
gtk_widget_show ( pixmap ) ;
gtk_container_add ( GTK_CONTAINER ( alert_frame ) , pixmap ) ;
CString str ;
guint16 width , height ;
unsigned char * buf ;
str = g_strGameToolsPath ;
str + = " bitmaps/splash.bmp " ;
unsigned char * load_bitmap_file ( const char * filename , guint16 * width , guint16 * height ) ;
buf = load_bitmap_file ( str . GetBuffer ( ) , & width , & height ) ;
if ( ! buf )
{
str = g_strBitmapsPath ;
str + = " splash.bmp " ;
buf = load_bitmap_file ( str . GetBuffer ( ) , & width , & height ) ;
}
if ( buf )
{
GtkPreview * preview = GTK_PREVIEW ( pixmap ) ;
gtk_preview_size ( preview , width , height ) ;
for ( int y = 0 ; y < height ; y + + )
gtk_preview_draw_row ( preview , buf + y * width * 3 , 0 , y , width ) ;
}
gtk_widget_show_all ( splash_screen ) ;
while ( gtk_events_pending ( ) )
gtk_main_iteration ( ) ;
}
// =============================================================================
// Loki stuff
# if defined (__linux__) || defined (__APPLE__)
/* A short game name, could be used as argv[0] */
static char game_name [ 100 ] = " " ;
/* The directory where the data files can be found (run directory) */
static char datapath [ PATH_MAX ] ;
char * loki_gethomedir ( void )
{
char * home = NULL ;
home = getenv ( " HOME " ) ;
if ( home = = NULL )
{
uid_t id = getuid ( ) ;
struct passwd * pwd ;
setpwent ( ) ;
while ( ( pwd = getpwent ( ) ) ! = NULL )
{
if ( pwd - > pw_uid = = id )
{
home = pwd - > pw_dir ;
break ;
}
}
endpwent ( ) ;
}
return home ;
}
/* Must be called BEFORE loki_initialize */
void loki_setgamename ( const char * n )
{
strncpy ( game_name , n , sizeof ( game_name ) ) ;
}
# ifdef __linux__
/* Code to determine the mount point of a CD-ROM */
int loki_getmountpoint ( const char * device , char * mntpt , int max_size )
{
char devpath [ PATH_MAX ] , mntdevpath [ PATH_MAX ] ;
FILE * mountfp ;
struct mntent * mntent ;
int mounted ;
/* Nothing to do with no device file */
if ( device = = NULL )
{
* mntpt = ' \0 ' ;
return - 1 ;
}
/* Get the fully qualified path of the CD-ROM device */
if ( realpath ( device , devpath ) = = NULL )
{
perror ( " realpath() on your CD-ROM failed " ) ;
return ( - 1 ) ;
}
/* Get the mount point */
mounted = - 1 ;
memset ( mntpt , 0 , max_size ) ;
mountfp = setmntent ( _PATH_MNTTAB , " r " ) ;
if ( mountfp ! = NULL )
{
mounted = 0 ;
while ( ( mntent = getmntent ( mountfp ) ) ! = NULL )
{
char * tmp , mntdev [ 1024 ] ;
strcpy ( mntdev , mntent - > mnt_fsname ) ;
if ( strcmp ( mntent - > mnt_type , " supermount " ) = = 0 )
{
tmp = strstr ( mntent - > mnt_opts , " dev= " ) ;
if ( tmp )
{
strcpy ( mntdev , tmp + strlen ( " dev= " ) ) ;
tmp = strchr ( mntdev , ' , ' ) ;
if ( tmp )
{
* tmp = ' \0 ' ;
}
}
}
if ( strncmp ( mntdev , " /dev " , 4 ) | |
realpath ( mntdev , mntdevpath ) = = NULL )
{
continue ;
}
if ( strcmp ( mntdevpath , devpath ) = = 0 )
{
mounted = 1 ;
assert ( ( int ) strlen ( mntent - > mnt_dir ) < max_size ) ;
strncpy ( mntpt , mntent - > mnt_dir , max_size - 1 ) ;
mntpt [ max_size - 1 ] = ' \0 ' ;
break ;
}
}
endmntent ( mountfp ) ;
}
return ( mounted ) ;
2008-06-26 07:52:02 +00:00
}
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 07:52:02 +00:00
/*
2007-11-04 03:51:54 +00:00
This function gets the directory containing the running program .
argv0 - the 0 ' th argument to the program
*/
// FIXME TTimo
// I don't understand this function. It looks like something cut from another piece of software
// we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var.
// even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell
void loki_initpaths ( char * argv0 )
{
char temppath [ PATH_MAX ] ; //, env[100];
char * home ; //, *ptr, *data_env;
home = loki_gethomedir ( ) ;
if ( home = = NULL )
{
home = " . " ;
}
if ( * game_name = = 0 ) /* Game name defaults to argv[0] */
loki_setgamename ( argv0 ) ;
strcpy ( temppath , argv0 ) ; /* If this overflows, it's your own fault :) */
if ( ! strrchr ( temppath , ' / ' ) )
{
char * path ;
char * last ;
int found ;
found = 0 ;
path = getenv ( " PATH " ) ;
do
{
/* Initialize our filename variable */
temppath [ 0 ] = ' \0 ' ;
/* Get next entry from path variable */
last = strchr ( path , ' : ' ) ;
if ( ! last )
last = path + strlen ( path ) ;
/* Perform tilde expansion */
if ( * path = = ' ~ ' )
{
strcpy ( temppath , home ) ;
+ + path ;
}
/* Fill in the rest of the filename */
if ( last > ( path + 1 ) )
{
strncat ( temppath , path , ( last - path ) ) ;
strcat ( temppath , " / " ) ;
}
strcat ( temppath , " ./ " ) ;
strcat ( temppath , argv0 ) ;
/* See if it exists, and update path */
if ( access ( temppath , X_OK ) = = 0 )
{
+ + found ;
}
path = last + 1 ;
} while ( * last & & ! found ) ;
} else
{
/* Increment argv0 to the basename */
argv0 = strrchr ( argv0 , ' / ' ) + 1 ;
}
/* Now canonicalize it to a full pathname for the data path */
if ( realpath ( temppath , datapath ) )
{
/* There should always be '/' in the path */
* ( strrchr ( datapath , ' / ' ) ) = ' \0 ' ;
}
}
char * loki_getdatapath ( void )
{
return ( datapath ) ;
}
# endif
// end of Loki stuff
// =============================================================================
void error_redirect ( const gchar * domain , GLogLevelFlags log_level , const gchar * message , gpointer user_data )
{
gboolean in_recursion ;
gboolean is_fatal ;
char buf [ 256 ] ;
in_recursion = ( log_level & G_LOG_FLAG_RECURSION ) ! = 0 ;
is_fatal = ( log_level & G_LOG_FLAG_FATAL ) ! = 0 ;
log_level = ( GLogLevelFlags ) ( log_level & G_LOG_LEVEL_MASK ) ;
if ( ! message )
message = " (NULL) message " ;
if ( domain )
strcpy ( buf , domain ) ;
else
strcpy ( buf , " ** " ) ;
strcat ( buf , " - " ) ;
switch ( log_level )
{
case G_LOG_LEVEL_ERROR :
if ( in_recursion )
strcat ( buf , " ERROR (recursed) **: " ) ;
else
strcat ( buf , " ERROR **: " ) ;
break ;
case G_LOG_LEVEL_CRITICAL :
if ( in_recursion )
strcat ( buf , " CRITICAL (recursed) **: " ) ;
else
strcat ( buf , " CRITICAL **: " ) ;
break ;
case G_LOG_LEVEL_WARNING :
if ( in_recursion )
strcat ( buf , " WARNING (recursed) **: " ) ;
else
strcat ( buf , " WARNING **: " ) ;
break ;
case G_LOG_LEVEL_MESSAGE :
if ( in_recursion )
strcat ( buf , " Message (recursed): " ) ;
else
strcat ( buf , " Message: " ) ;
break ;
case G_LOG_LEVEL_INFO :
if ( in_recursion )
strcat ( buf , " INFO (recursed): " ) ;
else
strcat ( buf , " INFO: " ) ;
break ;
case G_LOG_LEVEL_DEBUG :
if ( in_recursion )
strcat ( buf , " DEBUG (recursed): " ) ;
else
strcat ( buf , " DEBUG: " ) ;
break ;
default :
/* we are used for a log level that is not defined by GLib itself,
* try to make the best out of it .
*/
if ( in_recursion )
strcat ( buf , " LOG (recursed: " ) ;
else
strcat ( buf , " LOG ( " ) ;
if ( log_level )
{
gchar string [ ] = " 0x00): " ;
gchar * p = string + 2 ;
guint i ;
i = g_bit_nth_msf ( log_level , - 1 ) ;
* p = i > > 4 ;
p + + ;
* p = ' 0 ' + ( i & 0xf ) ;
if ( * p > ' 9 ' )
* p + = ' A ' - ' 9 ' - 1 ;
strcat ( buf , string ) ;
} else
strcat ( buf , " ): " ) ;
}
strcat ( buf , message ) ;
if ( is_fatal )
strcat ( buf , " \n aborting... \n " ) ;
else
strcat ( buf , " \n " ) ;
printf ( " %s \n " , buf ) ;
Sys_FPrintf ( SYS_WRN , buf ) ;
// TTimo NOTE: in some cases it may be handy to log only to the file
// Sys_FPrintf (SYS_NOCON, buf);
}
2008-06-26 08:31:13 +00:00
# define GETTEXT_PACKAGE "radiant"
# define LOCALEDIR "lang"
2007-12-25 00:10:45 +00:00
int main ( int argc , char * argv [ ] ) {
char * libgl , * ptr ;
int i , j , k ;
2007-11-04 03:51:54 +00:00
2011-01-22 03:22:21 +00:00
2010-11-14 01:40:25 +00:00
/*
Rambetter on Sat Nov 13 , 2010 :
The following line fixes parsing and writing of floating point numbers in locales such as
Italy , Germany , and others outside of en_US . In particular , in such problem locales , users
are not able to use certain map entities such as " light " because the definitions of these entities
in the entity definition files contain floating point values written in the standard " C " format
( containing a dot instead of , for example , a comma ) . The call sscanf ( ) is all over the code ,
including parsing entity definition files and reading Radiant preferences . sscanf ( ) is sensitive
to locale ( in particular when reading floating point numbers ) .
The line below is the minimalistic way to address only this particular problem - the parsing
and writing of floating point values . There may be other yet - undiscovered bugs related to
locale still lingering in the code . When such bugs are discovered , they should be addressed by
setting more than just " LC_NUMERIC=C " ( for example LC_CTYPE for regular expression matching )
or by fixing the problem in the actual code instead of fiddling with LC_ * variables .
Another way to fix the floating point format problem is to locate all calls such as * scanf ( )
and * printf ( ) in the code and replace them with other functions . However , we ' re also using
external libraries such as libxml and [ maybe ? ] they use locale to parse their numeric values .
I ' m just saying , it may get ugly if we try to fix the problem without setting LC_NUMERIC .
Usage of sscanf ( ) throughout the code looks like so :
sscanf ( str , " %f %f %f " , & val1 , & val2 , & val3 ) ;
Code like this exists in many files , here are 4 examples :
tools / quake3 / q3map2 / light . c
tools / quake3 / q3map2 / model . c
radiant / preferences . cpp
plugins / entity / miscmodel . cpp
Also affected are printf ( ) calls when using formats that contain " %f " .
I did some research and putenv ( ) seems to be the best choice for being cross - platform . It
used to be a function in Windows ( now deprecated ) :
http : //msdn.microsoft.com/en-us/library/ms235321(VS.80).aspx
And of course it ' s defined in UNIX .
One more thing . the gtk_init ( ) call below modifies all of the locale settings . In fact if it
weren ' t for gtk_init ( ) , we wouldn ' t have to set LC_NUMERIC ( parsing of floating points with
a dot works just fine before the gtk_init ( ) call on a sample Linux system ) . If we were to
just setlocale ( ) here , it would get clobbered by gtk_init ( ) . So instead of using setlocale ( )
_after_ gtk_init ( ) , I chose to fix this problem via environment variable . I think it ' s cleaner
that way .
*/
putenv ( " LC_NUMERIC=C " ) ;
2007-11-04 03:51:54 +00:00
# ifdef _WIN32
libgl = " opengl32.dll " ;
# endif
# if defined (__linux__)
libgl = " libGL.so.1 " ;
# endif
# ifdef __APPLE__
libgl = " /usr/X11R6/lib/libGL.1.dylib " ;
# endif
# if defined (__linux__) || defined (__APPLE__)
// Give away unnecessary root privileges.
// Important: must be done before calling gtk_init().
char * loginname ;
struct passwd * pw ;
seteuid ( getuid ( ) ) ;
2007-12-25 00:10:45 +00:00
if ( geteuid ( ) = = 0 & & ( loginname = getlogin ( ) ) ! = NULL & & ( pw = getpwnam ( loginname ) ) ! = NULL ) {
setuid ( pw - > pw_uid ) ;
}
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 08:31:13 +00:00
bindtextdomain ( GETTEXT_PACKAGE , LOCALEDIR ) ;
bind_textdomain_codeset ( GETTEXT_PACKAGE , " UTF-8 " ) ;
textdomain ( GETTEXT_PACKAGE ) ;
// gtk_disable_setlocale();
2007-11-04 03:51:54 +00:00
gtk_init ( & argc , & argv ) ;
2010-11-26 19:50:08 +00:00
gtk_gl_init ( & argc , & argv ) ;
gdk_gl_init ( & argc , & argv ) ;
// TODO: Find a better place to call this.
gtk_glwidget_create_font ( ) ;
2007-11-04 03:51:54 +00:00
if ( ( ptr = getenv ( " Q3R_LIBGL " ) ) ! = NULL )
libgl = ptr ;
for ( i = 1 ; i < argc ; i + + )
{
char * param = argv [ i ] ;
if ( param [ 0 ] = = ' - ' & & param [ 1 ] = = ' - ' )
{
param + = 2 ;
if ( ( strcmp ( param , " libgl " ) = = 0 ) & & ( i ! = argc ) )
{
libgl = argv [ i + 1 ] ;
argv [ i ] = argv [ i + 1 ] = NULL ;
i + + ;
} else if ( strcmp ( param , " builddefs " ) = = 0 )
{
g_bBuildList = true ;
argv [ i ] = NULL ;
}
}
}
for ( i = 1 ; i < argc ; i + + )
{
for ( k = i ; k < argc ; k + + )
if ( argv [ k ] ! = NULL )
break ;
if ( k > i )
{
k - = i ;
for ( j = i + k ; j < argc ; j + + )
argv [ j - k ] = argv [ j ] ;
argc - = k ;
}
}
g_argc = argc ;
g_argv = argv ;
g_strPluginsDir = " plugins/ " ;
g_strModulesDir = " modules/ " ;
# ifdef _WIN32
// get path to the editor
char * pBuffer = g_strAppPath . GetBufferSetLength ( _MAX_PATH + 1 ) ;
GetModuleFileName ( NULL , pBuffer , _MAX_PATH ) ;
pBuffer [ g_strAppPath . ReverseFind ( ' \\ ' ) + 1 ] = ' \0 ' ;
QE_ConvertDOSToUnixName ( pBuffer , pBuffer ) ;
g_strAppPath . ReleaseBuffer ( ) ;
g_strBitmapsPath = g_strAppPath ;
g_strBitmapsPath + = " bitmaps/ " ;
CGameDialog : : UpdateNetrun ( false ) ; // read the netrun configuration
2007-12-25 00:10:45 +00:00
if ( CGameDialog : : GetNetrun ( ) ) {
2007-11-04 03:51:54 +00:00
// we have to find a per-user g_strTempPath
// this behaves the same as on Linux
g_strTempPath = getenv ( " USERPROFILE " ) ;
if ( ! g_strTempPath . GetLength ( ) )
{
CString msg ;
msg = " Radiant is configured to run from a network installation. \n " ;
msg + = " I couldn't find the environement variable USERPROFILE \n " ;
msg + = " I'm going to use C: \\ RadiantSettings. Please set USERPROFILE \n " ;
gtk_MessageBox ( NULL , msg , " Radiant - Network mode " , MB_OK ) ;
g_strTempPath = " C: \\ " ;
}
g_strTempPath + = " \\ RadiantSettings \\ " ;
Q_mkdir ( g_strTempPath . GetBuffer ( ) , 0755 ) ;
g_strTempPath + = RADIANT_VERSION ;
g_strTempPath + = " \\ " ;
Q_mkdir ( g_strTempPath . GetBuffer ( ) , 0755 ) ;
}
else
{
// use the core path as temp (to save commandlist.txt, and do the .pid files)
g_strTempPath = g_strAppPath ;
}
# endif
# if defined (__linux__) || defined (__APPLE__)
Str home ;
home = g_get_home_dir ( ) ;
AddSlash ( home ) ;
home + = " .radiant/ " ;
Q_mkdir ( home . GetBuffer ( ) , 0775 ) ;
home + = RADIANT_VERSION ;
Q_mkdir ( home . GetBuffer ( ) , 0775 ) ;
g_strTempPath = home . GetBuffer ( ) ;
AddSlash ( g_strTempPath ) ;
loki_initpaths ( argv [ 0 ] ) ;
// NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
// it's a general convention in Radiant to have the slash at the end of directories
char real [ PATH_MAX ] ;
realpath ( loki_getdatapath ( ) , real ) ;
if ( real [ strlen ( real ) - 1 ] ! = ' / ' )
strcat ( real , " / " ) ;
g_strAppPath = real ;
// radiant is installed in the parent dir of "tools/"
// NOTE: this is not very easy for debugging
// maybe add options to lookup in several places?
// (for now I had to create symlinks)
g_strBitmapsPath = g_strAppPath ;
g_strBitmapsPath + = " bitmaps/ " ;
2008-06-26 07:52:02 +00:00
2007-11-04 03:51:54 +00:00
// we will set this right after the game selection is done
g_strGameToolsPath = g_strAppPath ;
# endif
// init the DTD path
g_strDTDPath = g_strAppPath ;
g_strDTDPath + = " dtds/ " ;
/*!
the global prefs loading / game selection dialog might fail for any reason we don ' t know about
we need to catch when it happens , to cleanup the stateful prefs which might be killing it
and to turn on console logging for lookup of the problem
this is the first part of the two step . pid system
*/
g_pidFile = g_strTempPath . GetBuffer ( ) ;
g_pidFile + = " radiant.pid " ;
FILE * pid ;
2007-12-25 00:10:45 +00:00
pid = fopen ( g_pidFile . GetBuffer ( ) , " r " ) ;
if ( pid ! = NULL ) {
2007-11-04 03:51:54 +00:00
fclose ( pid ) ;
CString msg ;
if ( remove ( g_pidFile . GetBuffer ( ) ) = = - 1 )
{
msg = " WARNING: Could not delete " ; msg + = g_pidFile ;
gtk_MessageBox ( NULL , msg , " Radiant " , MB_OK | MB_ICONERROR ) ;
}
// in debug, never prompt to clean registry, turn console logging auto after a failed start
# if !defined(_DEBUG)
msg = " Found the file " ;
msg + = g_pidFile ;
msg + = " . \n This indicates that Radiant failed during the game selection startup last time it was run. \n "
" Choose YES to clean Radiant's registry settings and shut down Radiant. \n "
" WARNING: the global prefs will be lost if you choose YES. " ;
if ( gtk_MessageBox ( NULL , msg , " Radiant - Reset global startup? " , MB_YESNO | MB_ICONQUESTION ) = = IDYES )
{
// remove global prefs and shutdown
g_PrefsDlg . mGamesDialog . Reset ( ) ;
// remove the prefs file (like a full reset of the registry)
//remove (g_PrefsDlg.m_inipath->str);
gtk_MessageBox ( NULL , " Removed global settings, choose OK to close Radiant. " , " Radiant " , MB_OK ) ;
_exit ( - 1 ) ;
}
msg = " Logging console output to " ;
msg + = g_strTempPath ;
msg + = " radiant.log \n Refer to the log if Radiant fails to start again. " ;
gtk_MessageBox ( NULL , msg , " Radiant - Console Log " , MB_OK ) ;
# endif
// set without saving, the class is not in a coherent state yet
// just do the value change and call to start logging, CGamesDialog will pickup when relevant
g_PrefsDlg . mGamesDialog . m_bLogConsole = true ;
g_PrefsDlg . mGamesDialog . m_bForceLogConsole = true ;
Sys_LogFile ( ) ;
}
// create a primary .pid for global init run
2007-12-25 00:10:45 +00:00
pid = fopen ( g_pidFile . GetBuffer ( ) , " w " ) ;
if ( pid ) {
fclose ( pid ) ;
}
2008-06-26 07:52:02 +00:00
2007-11-04 03:51:54 +00:00
// a safe check to avoid people running broken installations
// (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
// make something idiot proof and someone will make better idiots, this may be overkill
// let's leave it disabled in debug mode in any case
# ifndef _DEBUG
2007-12-25 00:10:45 +00:00
//#define CHECK_VERSION
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 07:52:02 +00:00
# ifdef CHECK_VERSION
2007-11-04 03:51:54 +00:00
// locate and open RADIANT_MAJOR and RADIANT_MINOR
qboolean bVerIsGood = true ;
Str ver_file_name ;
ver_file_name = g_strAppPath ;
ver_file_name + = " RADIANT_MAJOR " ;
FILE * ver_file = fopen ( ver_file_name . GetBuffer ( ) , " r " ) ;
if ( ver_file )
{
char buf [ 10 ] ;
int chomp ;
fread ( buf , 1 , 10 , ver_file ) ;
// chomp it (the hard way)
chomp = 0 ;
while ( buf [ chomp ] > = ' 0 ' & & buf [ chomp ] < = ' 9 ' )
chomp + + ;
buf [ chomp ] = ' \0 ' ;
if ( strcmp ( buf , RADIANT_MAJOR_VERSION ) )
{
Sys_Printf ( " ERROR: file RADIANT_MAJOR doesn't match ('%s') \n " , buf ) ;
bVerIsGood = false ;
}
}
else
{
Sys_Printf ( " ERROR: can't find RADIANT_MAJOR in '%s' \n " , ver_file_name . GetBuffer ( ) ) ;
bVerIsGood = false ;
}
ver_file_name = g_strAppPath ;
ver_file_name + = " RADIANT_MINOR " ;
ver_file = fopen ( ver_file_name . GetBuffer ( ) , " r " ) ;
if ( ver_file )
{
char buf [ 10 ] ;
int chomp ;
fread ( buf , 1 , 10 , ver_file ) ;
// chomp it (the hard way)
chomp = 0 ;
while ( buf [ chomp ] > = ' 0 ' & & buf [ chomp ] < = ' 9 ' )
chomp + + ;
buf [ chomp ] = ' \0 ' ;
if ( strcmp ( buf , RADIANT_MINOR_VERSION ) )
{
Sys_Printf ( " ERROR: file RADIANT_MINOR doesn't match ('%s') \n " , buf ) ;
bVerIsGood = false ;
}
}
else
{
Sys_Printf ( " ERROR: can't find RADIANT_MINOR in '%s' \n " , ver_file_name . GetBuffer ( ) ) ;
bVerIsGood = false ;
}
if ( ! bVerIsGood )
{
CString msg ;
msg = " This editor binary ( " RADIANT_VERSION " ) doesn't match what the latest setup has configured in this directory \n " ;
msg + = " Make sure you run the right/latest editor binary you installed \n " ;
msg + = g_strAppPath ; msg + = " \n " ;
msg + = " Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information " ;
gtk_MessageBox ( NULL , msg . GetBuffer ( ) , " Radiant " , MB_OK , " http://www.qeradiant.com/faq/index.cgi?file=219 " ) ;
_exit ( - 1 ) ;
}
# endif
2008-06-26 07:52:02 +00:00
2007-11-04 03:51:54 +00:00
g_qeglobals . disable_ini = false ;
2007-12-25 00:10:45 +00:00
g_PrefsDlg . Init ( ) ;
2007-11-04 03:51:54 +00:00
// close the primary
2007-12-25 00:10:45 +00:00
if ( remove ( g_pidFile . GetBuffer ( ) ) = = - 1 ) {
2007-11-04 03:51:54 +00:00
CString msg ;
msg = " WARNING: Could not delete " ; msg + = g_pidGameFile ;
gtk_MessageBox ( NULL , msg , " Radiant " , MB_OK | MB_ICONERROR ) ;
}
2008-06-26 07:52:02 +00:00
2007-11-04 03:51:54 +00:00
/*!
now the secondary game dependant . pid file
*/
g_pidGameFile = g_PrefsDlg . m_rc_path - > str ;
g_pidGameFile + = " radiant-game.pid " ;
pid = fopen ( g_pidGameFile . GetBuffer ( ) , " r " ) ;
if ( pid ! = NULL )
{
fclose ( pid ) ;
CString msg ;
if ( remove ( g_pidGameFile . GetBuffer ( ) ) = = - 1 )
{
msg = " WARNING: Could not delete " ; msg + = g_pidGameFile ;
gtk_MessageBox ( NULL , msg , " Radiant " , MB_OK | MB_ICONERROR ) ;
}
msg = " Found the file " ;
msg + = g_pidGameFile ;
msg + = " . \n This indicates that Radiant failed to load the last time it was run. \n "
" Choose YES to clean Radiant's registry settings and shut down Radiant. \n "
" WARNING: preferences will be lost if you choose YES. " ;
// in debug, never prompt to clean registry, turn console logging auto after a failed start
# if !defined(_DEBUG)
//bleh
if ( gtk_MessageBox ( NULL , msg , " Radiant - Clean Registry? " , MB_YESNO | MB_ICONQUESTION ) = = IDYES )
{
// remove the game prefs files
remove ( g_PrefsDlg . m_inipath - > str ) ;
char buf [ PATH_MAX ] ;
sprintf ( buf , " %sSavedInfo.bin " , g_PrefsDlg . m_rc_path - > str ) ;
remove ( buf ) ;
// remove the global pref too
g_PrefsDlg . mGamesDialog . Reset ( ) ;
gtk_MessageBox ( NULL , " Cleaned registry settings, choose OK to close Radiant. \n The next time Radiant runs it will use default settings. " , " Radiant " , MB_OK ) ;
_exit ( - 1 ) ;
}
msg = " Logging console output to " ;
msg + = g_strTempPath ;
msg + = " radiant.log \n Refer to the log if Radiant fails to start again. " ;
gtk_MessageBox ( NULL , msg , " Radiant - Console Log " , MB_OK ) ;
# endif
// force console logging on! (will go in prefs too)
g_PrefsDlg . mGamesDialog . m_bLogConsole = true ;
g_PrefsDlg . mGamesDialog . SavePrefs ( ) ;
Sys_LogFile ( ) ;
g_PrefsDlg . LoadPrefs ( ) ;
} else
{
// create one, will remove right after entering message loop
pid = fopen ( g_pidGameFile . GetBuffer ( ) , " w " ) ;
if ( pid )
fclose ( pid ) ;
g_PrefsDlg . LoadPrefs ( ) ;
# ifndef _DEBUG // I can't be arsed about that prompt in debug mode
// if console logging is on in the prefs, warn about performance hit
if ( g_PrefsDlg . mGamesDialog . m_bLogConsole )
{
if ( gtk_MessageBox ( NULL , " Preferences indicate that console logging is on. This affects performance. \n "
" Turn it off? " , " Radiant " , MB_YESNO | MB_ICONQUESTION ) = = IDYES )
{
g_PrefsDlg . mGamesDialog . m_bLogConsole = false ;
g_PrefsDlg . mGamesDialog . SavePrefs ( ) ;
}
}
# endif
// toggle console logging if necessary
Sys_LogFile ( ) ;
}
// we should search in g_strTempPath, then move over to look at g_strAppPath?
# ifdef _WIN32
// fine tune the look of the app using a gtk rc file
// we try to load an RC file placed in the application directory
// build the full path
Str sRCFile ;
sRCFile = g_strAppPath ;
sRCFile + = " radiantgtkrc " ;
// we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
pBuffer = ( char * ) sRCFile . GetBuffer ( ) ;
for ( i = 0 ; i < sRCFile . GetLength ( ) ; i + + )
{
if ( pBuffer [ i ] = = ' / ' )
{
pBuffer [ i ] = ' \\ ' ;
}
}
// check the file exists
if ( access ( sRCFile . GetBuffer ( ) , R_OK ) ! = 0 )
Sys_Printf ( " RC file %s not found \n " , sRCFile . GetBuffer ( ) ) ;
else
{
Sys_Printf ( " Attemping to load RC file %s \n " , sRCFile . GetBuffer ( ) ) ;
gtk_rc_parse ( sRCFile . GetBuffer ( ) ) ;
}
# endif
# ifndef SKIP_SPLASH
2007-12-25 00:10:45 +00:00
create_splash ( ) ;
2007-11-04 03:51:54 +00:00
# endif
if ( ! QGL_Init ( libgl , " " ) )
{
Sys_FPrintf ( SYS_ERR , " Failed to load OpenGL libraries \n " ) ;
_exit ( 1 ) ;
return 1 ;
}
# if defined (__linux__) || defined (__APPLE__)
if ( ( qglXQueryExtension = = NULL ) | | ( qglXQueryExtension ( GDK_DISPLAY ( ) , NULL , NULL ) ! = True ) )
{
Sys_FPrintf ( SYS_ERR , " glXQueryExtension failed \n " ) ;
_exit ( 1 ) ;
return 1 ;
}
# endif
// redirect Gtk warnings to the console
2007-12-25 00:10:45 +00:00
g_log_set_handler ( " Gdk " , ( GLogLevelFlags ) ( G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING |
2007-11-04 03:51:54 +00:00
G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG ) , error_redirect , NULL ) ;
2007-12-25 00:10:45 +00:00
g_log_set_handler ( " Gtk " , ( GLogLevelFlags ) ( G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING |
2007-11-04 03:51:54 +00:00
G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG ) , error_redirect , NULL ) ;
// spog - creates new filters list for the first time
2007-12-25 00:10:45 +00:00
g_qeglobals . d_savedinfo . filters = NULL ;
2011-01-23 09:12:34 +00:00
g_qeglobals . d_savedinfo . filters = FilterAddBase ( g_qeglobals . d_savedinfo . filters ) ;
2007-11-04 03:51:54 +00:00
2007-12-25 00:10:45 +00:00
g_pParentWnd = new MainFrame ( ) ;
2007-11-04 03:51:54 +00:00
2007-12-25 00:10:45 +00:00
if ( g_PrefsDlg . m_bLoadLastMap & & g_PrefsDlg . m_strLastMap . GetLength ( ) > 0 ) {
Map_LoadFile ( g_PrefsDlg . m_strLastMap . GetBuffer ( ) ) ;
} else {
Map_New ( ) ;
}
2007-11-04 03:51:54 +00:00
// load up shaders now that we have the map loaded
// eviltypeguy
2007-12-25 00:10:45 +00:00
Texture_ShowStartupShaders ( ) ;
2007-11-04 03:51:54 +00:00
# ifndef SKIP_SPLASH
2007-12-25 00:10:45 +00:00
gdk_window_raise ( splash_screen - > window ) ;
gtk_window_set_transient_for ( GTK_WINDOW ( splash_screen ) , GTK_WINDOW ( g_pParentWnd - > m_pWidget ) ) ;
gtk_timeout_add ( 1000 , try_destroy_splash , NULL ) ;
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 07:52:02 +00:00
2007-11-04 03:51:54 +00:00
g_pParentWnd - > GetSynapseServer ( ) . DumpActiveClients ( ) ;
//++timo: temporary debug
g_pParentWnd - > DoWatchBSP ( ) ;
2007-12-25 00:10:45 +00:00
gtk_main ( ) ;
2007-11-04 03:51:54 +00:00
// close the log file if any
// NOTE: don't save prefs past this point!
g_PrefsDlg . mGamesDialog . m_bLogConsole = false ;
// set the console window to NULL to avoid Sys_Printf crashing
g_qeglobals_gui . d_edit = NULL ;
Sys_LogFile ( ) ;
// NOTE TTimo not sure what this _exit(0) call is worth
// restricting it to linux build
# ifdef __linux__
2007-12-25 00:10:45 +00:00
_exit ( 0 ) ;
2007-11-04 03:51:54 +00:00
# endif
return 0 ;
}
// ydnar: quick and dirty fix, just make the buffer bigger
# define BIG_PATH_MAX 4096
// TTimo: decompose the BSP command into several steps so we can monitor them eventually
void QE_ExpandBspString ( char * bspaction , GPtrArray * out_array , char * mapname )
{
const char * in ;
char * out ;
char src [ BIG_PATH_MAX ] ;
char rsh [ BIG_PATH_MAX ] ;
char base [ BIG_PATH_MAX ] ;
strcpy ( src , mapname ) ;
strlwr ( src ) ;
in = strstr ( src , " maps/ " ) ;
if ( ! in )
{
in = strstr ( src , " maps/ " ) ;
}
if ( in )
{
in + = 5 ;
strcpy ( base , in ) ;
out = base ;
while ( * out )
{
if ( * out = = ' \\ ' )
{
* out = ' / ' ;
}
out + + ;
}
} else
{
ExtractFileName ( mapname , base ) ;
}
// this important step alters the map name to add fs_game
// NOTE: it used to add fs_basepath too
// the fs_basepath addition moved to being in the project file during the bug fixing rush
// but it may not have been the right thing to do
// HACK: halflife compiler tools don't support -fs_game
// HACK: neither does JKII/SoF2/ etc..
// do we use & have fs_game?
2008-06-26 07:52:02 +00:00
2007-11-04 03:51:54 +00:00
if ( g_pGameDescription - > mGameFile ! = " hl.game " & &
* ValueForKey ( g_qeglobals . d_project_entity , " gamename " ) ! = ' \0 ' )
{
// set with fs_game
sprintf ( src , " -fs_game %s \" %s \" " , ValueForKey ( g_qeglobals . d_project_entity , " gamename " ) , mapname ) ;
}
else
{
sprintf ( src , " \" %s \" " , mapname ) ;
}
rsh [ 0 ] = 0 ;
QE_ConvertDOSToUnixName ( src , src ) ;
// initialise the first step
out = new char [ BIG_PATH_MAX ] ; //% PATH_MAX
g_ptr_array_add ( out_array , out ) ;
in = ValueForKey ( g_qeglobals . d_project_entity , bspaction ) ;
while ( * in )
{
if ( in [ 0 ] = = ' ! ' )
{
strcpy ( out , rsh ) ;
out + = strlen ( rsh ) ;
in + + ;
continue ;
}
if ( in [ 0 ] = = ' # ' )
{
char tmp [ 2048 ] ;
// we process these only if monitoring
if ( g_PrefsDlg . m_bWatchBSP )
{
// -connect global option (the only global option so far anyway)
strcpy ( tmp , " -connect 127.0.0.1:39000 " ) ;
strcpy ( out , tmp ) ;
out + = strlen ( tmp ) ;
}
in + + ;
continue ;
}
if ( in [ 0 ] = = ' $ ' )
{
// $ expansion
strcpy ( out , src ) ;
out + = strlen ( src ) ;
in + + ;
continue ;
}
if ( in [ 0 ] = = ' @ ' )
{
* out + + = ' " ' ;
in + + ;
continue ;
}
if ( in [ 0 ] = = ' & ' )
if ( in [ 1 ] = = ' & ' )
{
// start a new step
* out = 0 ;
in = in + 2 ;
out = new char [ BIG_PATH_MAX ] ; //% PATH_MAX
g_ptr_array_add ( out_array , out ) ;
}
* out + + = * in + + ;
}
* out = 0 ;
}
void FindReplace ( CString & strContents , const char * pTag , const char * pValue )
{
if ( strcmp ( pTag , pValue ) = = 0 )
return ;
for ( int nPos = strContents . Find ( pTag ) ; nPos > = 0 ; nPos = strContents . Find ( pTag ) )
{
int nRightLen = strContents . GetLength ( ) - strlen ( pTag ) - nPos ;
CString strLeft = strContents . Left ( nPos ) ;
CString strRight = strContents . Right ( nRightLen ) ;
strLeft + = pValue ;
strLeft + = strRight ;
strContents = strLeft ;
}
}
// save the map, deals with regioning
void SaveWithRegion ( char * name )
{
strcpy ( name , currentmap ) ;
if ( region_active )
{
// temporary cut the region to save regular map
region_active = false ;
Map_SaveFile ( name , false ) ;
region_active = true ;
StripExtension ( name ) ;
strcat ( name , " .reg " ) ;
}
Map_SaveFile ( name , region_active ) ;
}
void RunBsp ( char * command )
{
GPtrArray * sys ;
char batpath [ BIG_PATH_MAX ] ; //% PATH_MAX
char temppath [ BIG_PATH_MAX ] ; //% PATH_MAX
char name [ BIG_PATH_MAX ] ; //% PATH_MAX
char cWork [ BIG_PATH_MAX ] ; //% PATH_MAX
FILE * hFile ;
unsigned int i ;
SetInspectorMode ( W_CONSOLE ) ;
strcpy ( temppath , g_strTempPath . GetBuffer ( ) ) ;
SaveWithRegion ( name ) ;
const char * rsh = ValueForKey ( g_qeglobals . d_project_entity , " rshcmd " ) ;
if ( rsh = = NULL )
{
CString strPath , strFile ;
ExtractPath_and_Filename ( name , strPath , strFile ) ;
AddSlash ( strPath ) ;
strncpy ( cWork , strPath , 1024 ) ;
strcat ( cWork , strFile ) ;
} else
{
strcpy ( cWork , name ) ;
}
// get the array ready
//++timo TODO: free the array, free the strings ourselves with delete[]
sys = g_ptr_array_new ( ) ;
QE_ExpandBspString ( command , sys , cWork ) ;
if ( g_PrefsDlg . m_bWatchBSP )
{
// grab the file name for engine running
char * bspname = new char [ 1024 ] ;
ExtractFileName ( currentmap , bspname ) ;
StripExtension ( bspname ) ;
g_pParentWnd - > GetWatchBSP ( ) - > DoMonitoringLoop ( sys , bspname ) ;
} else
{
// write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
CString strSys ;
for ( i = 0 ; i < sys - > len ; i + + )
{
strSys + = ( char * ) g_ptr_array_index ( sys , i ) ;
# ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window
2008-06-26 07:52:02 +00:00
if ( i = = 0 )
2007-11-04 03:51:54 +00:00
strSys + = " > " ;
2008-06-26 07:52:02 +00:00
else
2007-11-04 03:51:54 +00:00
strSys + = " >> " ;
strSys + = " \" " ;
strSys + = temppath ;
strSys + = " junk.txt \" " ;
# endif
strSys + = " \n " ;
} ;
# if defined (__linux__) || defined (__APPLE__)
// write qe3bsp.sh
sprintf ( batpath , " %sqe3bsp.sh " , temppath ) ;
Sys_Printf ( " Writing the compile script to '%s' \n " , batpath ) ;
Sys_Printf ( " The build output will be saved in '%sjunk.txt' \n " , temppath ) ;
hFile = fopen ( batpath , " w " ) ;
if ( ! hFile )
Error ( " Can't write to %s " , batpath ) ;
fprintf ( hFile , " #!/bin/sh \n \n " ) ;
fprintf ( hFile , strSys . GetBuffer ( ) ) ;
fclose ( hFile ) ;
chmod ( batpath , 0744 ) ;
# endif
# ifdef _WIN32
sprintf ( batpath , " %sqe3bsp.bat " , temppath ) ;
Sys_Printf ( " Writing the compile script to '%s' \n " , batpath ) ;
Sys_Printf ( " The build output will be saved in '%sjunk.txt' \n " , temppath ) ;
hFile = fopen ( batpath , " w " ) ;
if ( ! hFile )
Error ( " Can't write to %s " , batpath ) ;
fprintf ( hFile , strSys . GetBuffer ( ) ) ;
2008-06-26 07:52:02 +00:00
fclose ( hFile ) ;
2007-11-04 03:51:54 +00:00
# endif
Pointfile_Delete ( ) ;
# if defined (__linux__) || defined (__APPLE__)
pid_t pid ;
pid = fork ( ) ;
switch ( pid )
{
case - 1 :
Error ( " CreateProcess failed " ) ;
break ;
case 0 :
execlp ( batpath , batpath , NULL ) ;
printf ( " execlp error ! " ) ;
_exit ( 0 ) ;
break ;
default :
break ;
}
# endif
# ifdef _WIN32
Sys_Printf ( " Running bsp command... \n " ) ;
Sys_Printf ( " \n %s \n " , strSys . GetBuffer ( ) ) ;
WinExec ( batpath , SW_SHOWNORMAL ) ;
# endif
}
# ifdef _DEBUG
// yeah, do it .. but not now right before 1.1-TA-beta release
Sys_Printf ( " TODO: erase GPtrArray \n " ) ;
# endif
}
#if 0
# ifdef _WIN32
int WINAPI QEW_SetupPixelFormat ( HDC hDC , qboolean zbuffer )
{
static PIXELFORMATDESCRIPTOR pfd = {
sizeof ( PIXELFORMATDESCRIPTOR ) , // size of this pfd
1 , // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER , // double buffered
PFD_TYPE_RGBA , // RGBA type
24 , // 24-bit color depth
0 , 0 , 0 , 0 , 0 , 0 , // color bits ignored
0 , // no alpha buffer
0 , // shift bit ignored
0 , // no accumulation buffer
0 , 0 , 0 , 0 , // accum bits ignored
32 , // depth bits
0 , // no stencil buffer
0 , // no auxiliary buffer
PFD_MAIN_PLANE , // main layer
0 , // reserved
0 , 0 , 0 // layer masks ignored
} ; //
2008-06-26 07:52:02 +00:00
int pixelformat = 0 ;
2007-11-04 03:51:54 +00:00
zbuffer = true ;
if ( ! zbuffer )
pfd . cDepthBits = 0 ;
if ( ( pixelformat = ChoosePixelFormat ( hDC , & pfd ) ) = = 0 )
{
LPVOID lpMsgBuf ;
FormatMessage (
2008-06-26 07:52:02 +00:00
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
2007-11-04 03:51:54 +00:00
FORMAT_MESSAGE_IGNORE_INSERTS ,
NULL ,
GetLastError ( ) ,
MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , // Default language
( LPTSTR ) & lpMsgBuf ,
0 ,
2008-06-26 07:52:02 +00:00
NULL
2007-11-04 03:51:54 +00:00
) ;
Sys_FPrintf ( SYS_WRN , " GetLastError: %s " , lpMsgBuf ) ;
Error ( " ChoosePixelFormat failed " ) ;
}
if ( ! SetPixelFormat ( hDC , pixelformat , & pfd ) )
Error ( " SetPixelFormat failed " ) ;
return pixelformat ;
}
# endif
# endif