2 Copyright (C) 1999-2007 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
22 #if defined (__linux__) || defined (__APPLE__)
37 #include <gtk/gtkgl.h>
38 #include <glib/gi18n.h>
41 #include <sys/types.h>
50 bool g_bBuildList = false;
54 // =============================================================================
57 // get rid of it when debugging
62 static GtkWidget *splash_screen;
64 // called based on a timer, or in particular cases when we don't want to keep it around
65 gint try_destroy_splash (gpointer data)
69 gtk_widget_destroy (splash_screen);
75 static void create_splash ()
77 GtkWidget *alert_frame, *alert_frame1, *pixmap;
79 splash_screen = gtk_window_new (GTK_WINDOW_POPUP);
80 gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER);
81 gtk_widget_realize (splash_screen);
83 alert_frame1 = gtk_frame_new (NULL);
84 gtk_widget_show (alert_frame1);
85 gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1);
86 gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT);
88 alert_frame = gtk_frame_new (NULL);
89 gtk_widget_show (alert_frame);
91 gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame);
92 gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN);
93 gtk_container_border_width (GTK_CONTAINER (alert_frame), 3);
95 pixmap = gtk_preview_new (GTK_PREVIEW_COLOR);
96 gtk_widget_show (pixmap);
97 gtk_container_add (GTK_CONTAINER (alert_frame), pixmap);
100 guint16 width, height;
103 str = g_strGameToolsPath;
104 str += "bitmaps/splash.bmp";
106 unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height);
107 buf = load_bitmap_file (str.GetBuffer (), &width, &height);
111 str = g_strBitmapsPath;
114 buf = load_bitmap_file (str.GetBuffer (), &width, &height);
119 GtkPreview *preview = GTK_PREVIEW (pixmap);
120 gtk_preview_size (preview, width, height);
121 for (int y = 0; y < height; y++)
122 gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width);
125 gtk_widget_show_all (splash_screen);
127 while (gtk_events_pending ())
128 gtk_main_iteration ();
131 // =============================================================================
134 #if defined (__linux__) || defined (__APPLE__)
136 /* A short game name, could be used as argv[0] */
137 static char game_name[100] = "";
139 /* The directory where the data files can be found (run directory) */
140 static char datapath[PATH_MAX];
142 char *loki_gethomedir(void)
146 home = getenv("HOME");
153 while ( (pwd = getpwent()) != NULL )
155 if ( pwd->pw_uid == id )
166 /* Must be called BEFORE loki_initialize */
167 void loki_setgamename(const char *n)
169 strncpy(game_name, n, sizeof(game_name));
173 /* Code to determine the mount point of a CD-ROM */
174 int loki_getmountpoint(const char *device, char *mntpt, int max_size)
176 char devpath[PATH_MAX], mntdevpath[PATH_MAX];
178 struct mntent *mntent;
181 /* Nothing to do with no device file */
182 if ( device == NULL )
188 /* Get the fully qualified path of the CD-ROM device */
189 if ( realpath(device, devpath) == NULL )
191 perror("realpath() on your CD-ROM failed");
195 /* Get the mount point */
197 memset(mntpt, 0, max_size);
198 mountfp = setmntent( _PATH_MNTTAB, "r" );
199 if ( mountfp != NULL )
202 while ( (mntent = getmntent( mountfp )) != NULL )
204 char *tmp, mntdev[1024];
206 strcpy(mntdev, mntent->mnt_fsname);
207 if ( strcmp(mntent->mnt_type, "supermount") == 0 )
209 tmp = strstr(mntent->mnt_opts, "dev=");
212 strcpy(mntdev, tmp+strlen("dev="));
213 tmp = strchr(mntdev, ',');
220 if ( strncmp(mntdev, "/dev", 4) ||
221 realpath(mntdev, mntdevpath) == NULL )
225 if ( strcmp( mntdevpath, devpath ) == 0 )
228 assert((int)strlen( mntent->mnt_dir ) < max_size);
229 strncpy( mntpt, mntent->mnt_dir, max_size-1);
230 mntpt[max_size-1] = '\0';
234 endmntent( mountfp );
241 This function gets the directory containing the running program.
242 argv0 - the 0'th argument to the program
245 // I don't understand this function. It looks like something cut from another piece of software
246 // we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var.
247 // even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell
248 void loki_initpaths(char *argv0)
250 char temppath[PATH_MAX]; //, env[100];
251 char *home; //, *ptr, *data_env;
253 home = loki_gethomedir();
259 if (*game_name == 0) /* Game name defaults to argv[0] */
260 loki_setgamename(argv0);
262 strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */
263 if ( ! strrchr(temppath, '/') )
270 path = getenv("PATH");
273 /* Initialize our filename variable */
276 /* Get next entry from path variable */
277 last = strchr(path, ':');
279 last = path+strlen(path);
281 /* Perform tilde expansion */
284 strcpy(temppath, home);
288 /* Fill in the rest of the filename */
289 if ( last > (path+1) )
291 strncat(temppath, path, (last-path));
292 strcat(temppath, "/");
294 strcat(temppath, "./");
295 strcat(temppath, argv0);
297 /* See if it exists, and update path */
298 if ( access(temppath, X_OK) == 0 )
304 } while ( *last && !found );
308 /* Increment argv0 to the basename */
309 argv0 = strrchr(argv0, '/')+1;
312 /* Now canonicalize it to a full pathname for the data path */
313 if ( realpath(temppath, datapath) )
315 /* There should always be '/' in the path */
316 *(strrchr(datapath, '/')) = '\0';
320 char *loki_getdatapath(void)
328 // =============================================================================
330 void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
332 gboolean in_recursion;
336 in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
337 is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
338 log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK);
341 message = "(NULL) message";
344 strcpy (buf, domain);
351 case G_LOG_LEVEL_ERROR:
353 strcat (buf, "ERROR (recursed) **: ");
355 strcat (buf, "ERROR **: ");
357 case G_LOG_LEVEL_CRITICAL:
359 strcat (buf, "CRITICAL (recursed) **: ");
361 strcat (buf, "CRITICAL **: ");
363 case G_LOG_LEVEL_WARNING:
365 strcat (buf, "WARNING (recursed) **: ");
367 strcat (buf, "WARNING **: ");
369 case G_LOG_LEVEL_MESSAGE:
371 strcat (buf, "Message (recursed): ");
373 strcat (buf, "Message: ");
375 case G_LOG_LEVEL_INFO:
377 strcat (buf, "INFO (recursed): ");
379 strcat (buf, "INFO: ");
381 case G_LOG_LEVEL_DEBUG:
383 strcat (buf, "DEBUG (recursed): ");
385 strcat (buf, "DEBUG: ");
388 /* we are used for a log level that is not defined by GLib itself,
389 * try to make the best out of it.
392 strcat (buf, "LOG (recursed:");
394 strcat (buf, "LOG (");
397 gchar string[] = "0x00): ";
398 gchar *p = string + 2;
401 i = g_bit_nth_msf (log_level, -1);
404 *p = '0' + (i & 0xf);
408 strcat (buf, string);
413 strcat (buf, message);
415 strcat (buf, "\naborting...\n");
419 printf ("%s\n", buf);
420 Sys_FPrintf (SYS_WRN, buf);
421 // TTimo NOTE: in some cases it may be handy to log only to the file
422 // Sys_FPrintf (SYS_NOCON, buf);
425 #define GETTEXT_PACKAGE "radiant"
426 #define LOCALEDIR "lang"
428 int main( int argc, char* argv[] ) {
434 Rambetter on Sat Nov 13, 2010:
436 The following line fixes parsing and writing of floating point numbers in locales such as
437 Italy, Germany, and others outside of en_US. In particular, in such problem locales, users
438 are not able to use certain map entities such as "light" because the definitions of these entities
439 in the entity definition files contain floating point values written in the standard "C" format
440 (containing a dot instead of, for example, a comma). The call sscanf() is all over the code,
441 including parsing entity definition files and reading Radiant preferences. sscanf() is sensitive
442 to locale (in particular when reading floating point numbers).
444 The line below is the minimalistic way to address only this particular problem - the parsing
445 and writing of floating point values. There may be other yet-undiscovered bugs related to
446 locale still lingering in the code. When such bugs are discovered, they should be addressed by
447 setting more than just "LC_NUMERIC=C" (for example LC_CTYPE for regular expression matching)
448 or by fixing the problem in the actual code instead of fiddling with LC_* variables.
450 Another way to fix the floating point format problem is to locate all calls such as *scanf()
451 and *printf() in the code and replace them with other functions. However, we're also using
452 external libraries such as libxml and [maybe?] they use locale to parse their numeric values.
453 I'm just saying, it may get ugly if we try to fix the problem without setting LC_NUMERIC.
455 Usage of sscanf() throughout the code looks like so:
456 sscanf(str, "%f %f %f", &val1, &val2, &val3);
457 Code like this exists in many files, here are 4 examples:
458 tools/quake3/q3map2/light.c
459 tools/quake3/q3map2/model.c
460 radiant/preferences.cpp
461 plugins/entity/miscmodel.cpp
463 Also affected are printf() calls when using formats that contain "%f".
465 I did some research and putenv() seems to be the best choice for being cross-platform. It
466 used to be a function in Windows (now deprecated):
467 http://msdn.microsoft.com/en-us/library/ms235321(VS.80).aspx
468 And of course it's defined in UNIX.
470 One more thing. the gtk_init() call below modifies all of the locale settings. In fact if it
471 weren't for gtk_init(), we wouldn't have to set LC_NUMERIC (parsing of floating points with
472 a dot works just fine before the gtk_init() call on a sample Linux system). If we were to
473 just setlocale() here, it would get clobbered by gtk_init(). So instead of using setlocale()
474 _after_ gtk_init(), I chose to fix this problem via environment variable. I think it's cleaner
477 putenv("LC_NUMERIC=C");
480 libgl = "opengl32.dll";
483 #if defined (__linux__)
484 libgl = "libGL.so.1";
488 libgl = "/usr/X11R6/lib/libGL.1.dylib";
491 #if defined (__linux__) || defined (__APPLE__)
492 // Give away unnecessary root privileges.
493 // Important: must be done before calling gtk_init().
497 if ( geteuid() == 0 && ( loginname = getlogin() ) != NULL && ( pw = getpwnam(loginname) ) != NULL ) {
503 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
504 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
505 textdomain(GETTEXT_PACKAGE);
506 // gtk_disable_setlocale();
508 gtk_init(&argc, &argv);
509 gtk_gl_init(&argc, &argv);
510 gdk_gl_init(&argc, &argv);
512 // TODO: Find a better place to call this.
513 gtk_glwidget_create_font();
515 if ((ptr = getenv ("Q3R_LIBGL")) != NULL)
518 for (i = 1; i < argc; i++)
520 char* param = argv[i];
522 if (param[0] == '-' && param[1] == '-')
526 if ((strcmp (param, "libgl") == 0) && (i != argc))
529 argv[i] = argv[i+1] = NULL;
531 } else if (strcmp (param, "builddefs") == 0)
539 for (i = 1; i < argc; i++)
541 for (k = i; k < argc; k++)
548 for (j = i + k; j < argc; j++)
557 g_strPluginsDir = "plugins/";
558 g_strModulesDir = "modules/";
561 // get path to the editor
562 char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1);
563 GetModuleFileName(NULL, pBuffer, _MAX_PATH);
564 pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0';
565 QE_ConvertDOSToUnixName(pBuffer, pBuffer);
566 g_strAppPath.ReleaseBuffer();
568 g_strBitmapsPath = g_strAppPath;
569 g_strBitmapsPath += "bitmaps/";
571 CGameDialog::UpdateNetrun(false); // read the netrun configuration
573 if ( CGameDialog::GetNetrun() ) {
574 // we have to find a per-user g_strTempPath
575 // this behaves the same as on Linux
576 g_strTempPath = getenv("USERPROFILE");
577 if (!g_strTempPath.GetLength())
580 msg = "Radiant is configured to run from a network installation.\n";
581 msg += "I couldn't find the environement variable USERPROFILE\n";
582 msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n";
583 gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK);
584 g_strTempPath = "C:\\";
586 g_strTempPath += "\\RadiantSettings\\";
587 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
588 g_strTempPath += RADIANT_VERSION;
589 g_strTempPath += "\\";
590 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
594 // use the core path as temp (to save commandlist.txt, and do the .pid files)
595 g_strTempPath = g_strAppPath;
600 #if defined (__linux__) || defined (__APPLE__)
602 home = g_get_home_dir ();
605 Q_mkdir (home.GetBuffer (), 0775);
606 home += RADIANT_VERSION;
607 Q_mkdir (home.GetBuffer (), 0775);
608 g_strTempPath = home.GetBuffer ();
609 AddSlash (g_strTempPath);
611 loki_initpaths(argv[0]);
613 // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
614 // it's a general convention in Radiant to have the slash at the end of directories
616 realpath (loki_getdatapath(), real);
617 if (real[strlen(real)-1] != '/')
622 // radiant is installed in the parent dir of "tools/"
623 // NOTE: this is not very easy for debugging
624 // maybe add options to lookup in several places?
625 // (for now I had to create symlinks)
626 g_strBitmapsPath = g_strAppPath;
627 g_strBitmapsPath += "bitmaps/";
629 // we will set this right after the game selection is done
630 g_strGameToolsPath = g_strAppPath;
635 g_strDTDPath = g_strAppPath;
636 g_strDTDPath += "dtds/";
639 the global prefs loading / game selection dialog might fail for any reason we don't know about
640 we need to catch when it happens, to cleanup the stateful prefs which might be killing it
641 and to turn on console logging for lookup of the problem
642 this is the first part of the two step .pid system
644 g_pidFile = g_strTempPath.GetBuffer ();
645 g_pidFile += "radiant.pid";
648 pid = fopen( g_pidFile.GetBuffer(), "r" );
653 if (remove (g_pidFile.GetBuffer ()) == -1)
655 msg = "WARNING: Could not delete "; msg += g_pidFile;
656 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
659 // in debug, never prompt to clean registry, turn console logging auto after a failed start
661 msg = "Found the file ";
663 msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n"
664 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
665 "WARNING: the global prefs will be lost if you choose YES.";
667 if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES)
669 // remove global prefs and shutdown
670 g_PrefsDlg.mGamesDialog.Reset();
671 // remove the prefs file (like a full reset of the registry)
672 //remove (g_PrefsDlg.m_inipath->str);
673 gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK );
676 msg = "Logging console output to ";
677 msg += g_strTempPath;
678 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
680 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
683 // set without saving, the class is not in a coherent state yet
684 // just do the value change and call to start logging, CGamesDialog will pickup when relevant
685 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
686 g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true;
690 // create a primary .pid for global init run
691 pid = fopen( g_pidFile.GetBuffer(), "w" );
696 // a safe check to avoid people running broken installations
697 // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
698 // make something idiot proof and someone will make better idiots, this may be overkill
699 // let's leave it disabled in debug mode in any case
701 //#define CHECK_VERSION
704 // locate and open RADIANT_MAJOR and RADIANT_MINOR
705 qboolean bVerIsGood = true;
707 ver_file_name = g_strAppPath;
708 ver_file_name += "RADIANT_MAJOR";
709 FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r");
714 fread(buf, 1, 10, ver_file);
715 // chomp it (the hard way)
717 while(buf[chomp] >= '0' && buf[chomp] <= '9')
720 if (strcmp(buf, RADIANT_MAJOR_VERSION))
722 Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf);
728 Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer());
731 ver_file_name = g_strAppPath;
732 ver_file_name += "RADIANT_MINOR";
733 ver_file = fopen (ver_file_name.GetBuffer(), "r");
738 fread(buf, 1, 10, ver_file);
739 // chomp it (the hard way)
741 while(buf[chomp] >= '0' && buf[chomp] <= '9')
744 if (strcmp(buf, RADIANT_MINOR_VERSION))
746 Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf);
752 Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer());
758 msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n";
759 msg += "Make sure you run the right/latest editor binary you installed\n";
760 msg += g_strAppPath; msg += "\n";
761 msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information";
762 gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219");
767 g_qeglobals.disable_ini = false;
771 if ( remove( g_pidFile.GetBuffer () ) == -1 ) {
773 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
774 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
778 now the secondary game dependant .pid file
780 g_pidGameFile = g_PrefsDlg.m_rc_path->str;
781 g_pidGameFile += "radiant-game.pid";
783 pid = fopen (g_pidGameFile.GetBuffer(), "r");
788 if (remove (g_pidGameFile.GetBuffer ()) == -1)
790 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
791 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
794 msg = "Found the file ";
795 msg += g_pidGameFile;
796 msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n"
797 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
798 "WARNING: preferences will be lost if you choose YES.";
800 // in debug, never prompt to clean registry, turn console logging auto after a failed start
803 if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES)
805 // remove the game prefs files
806 remove (g_PrefsDlg.m_inipath->str);
808 sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str);
810 // remove the global pref too
811 g_PrefsDlg.mGamesDialog.Reset();
812 gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK );
815 msg = "Logging console output to ";
816 msg += g_strTempPath;
817 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
819 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
822 // force console logging on! (will go in prefs too)
823 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
824 g_PrefsDlg.mGamesDialog.SavePrefs();
827 g_PrefsDlg.LoadPrefs();
831 // create one, will remove right after entering message loop
832 pid = fopen (g_pidGameFile.GetBuffer(), "w");
836 g_PrefsDlg.LoadPrefs();
838 #ifndef _DEBUG // I can't be arsed about that prompt in debug mode
839 // if console logging is on in the prefs, warn about performance hit
840 if (g_PrefsDlg.mGamesDialog.m_bLogConsole)
842 if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n"
843 "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES)
845 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
846 g_PrefsDlg.mGamesDialog.SavePrefs();
850 // toggle console logging if necessary
854 // we should search in g_strTempPath, then move over to look at g_strAppPath?
856 // fine tune the look of the app using a gtk rc file
857 // we try to load an RC file placed in the application directory
858 // build the full path
860 sRCFile = g_strAppPath;
861 sRCFile += "radiantgtkrc";
862 // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
863 pBuffer = (char *)sRCFile.GetBuffer();
864 for (i=0; i<sRCFile.GetLength(); i++)
871 // check the file exists
872 if (access(sRCFile.GetBuffer(), R_OK) != 0)
873 Sys_Printf("RC file %s not found\n", sRCFile.GetBuffer());
876 Sys_Printf ("Attemping to load RC file %s\n", sRCFile.GetBuffer());
877 gtk_rc_parse (sRCFile.GetBuffer());
885 if (!QGL_Init(libgl, ""))
887 Sys_FPrintf (SYS_ERR, "Failed to load OpenGL libraries\n");
892 #if defined (__linux__) || defined (__APPLE__)
893 if ((qglXQueryExtension == NULL) || (qglXQueryExtension(GDK_DISPLAY(),NULL,NULL) != True))
895 Sys_FPrintf (SYS_ERR, "glXQueryExtension failed\n");
901 // redirect Gtk warnings to the console
902 g_log_set_handler( "Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
903 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
904 g_log_set_handler( "Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
905 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
907 // spog - creates new filters list for the first time
908 g_qeglobals.d_savedinfo.filters = NULL;
909 g_qeglobals.d_savedinfo.filters = FilterAddBase(g_qeglobals.d_savedinfo.filters);
911 g_pParentWnd = new MainFrame();
913 if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) {
914 Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer());
919 // load up shaders now that we have the map loaded
921 Texture_ShowStartupShaders();
924 gdk_window_raise(splash_screen->window);
925 gtk_window_set_transient_for( GTK_WINDOW( splash_screen ), GTK_WINDOW( g_pParentWnd->m_pWidget ) );
926 gtk_timeout_add( 1000, try_destroy_splash, NULL );
929 g_pParentWnd->GetSynapseServer().DumpActiveClients();
931 //++timo: temporary debug
932 g_pParentWnd->DoWatchBSP();
936 // close the log file if any
937 // NOTE: don't save prefs past this point!
938 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
939 // set the console window to NULL to avoid Sys_Printf crashing
940 g_qeglobals_gui.d_edit = NULL;
943 // NOTE TTimo not sure what this _exit(0) call is worth
944 // restricting it to linux build
951 // ydnar: quick and dirty fix, just make the buffer bigger
952 #define BIG_PATH_MAX 4096
954 // TTimo: decompose the BSP command into several steps so we can monitor them eventually
955 void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname)
959 char src[BIG_PATH_MAX];
960 char rsh[BIG_PATH_MAX];
961 char base[BIG_PATH_MAX];
963 strcpy(src, mapname);
965 in = strstr(src, "maps/");
968 in = strstr(src, "maps/");
985 ExtractFileName (mapname, base);
988 // this important step alters the map name to add fs_game
989 // NOTE: it used to add fs_basepath too
990 // the fs_basepath addition moved to being in the project file during the bug fixing rush
991 // but it may not have been the right thing to do
993 // HACK: halflife compiler tools don't support -fs_game
994 // HACK: neither does JKII/SoF2/ etc..
995 // do we use & have fs_game?
997 if (g_pGameDescription->mGameFile != "hl.game" &&
998 *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0')
1001 sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname);
1005 sprintf(src, "\"%s\"", mapname);
1010 QE_ConvertDOSToUnixName(src, src);
1012 // initialise the first step
1013 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1014 g_ptr_array_add( out_array, out );
1016 in = ValueForKey( g_qeglobals.d_project_entity, bspaction );
1029 // we process these only if monitoring
1030 if (g_PrefsDlg.m_bWatchBSP)
1032 // -connect global option (the only global option so far anyway)
1033 strcpy (tmp, " -connect 127.0.0.1:39000 ");
1060 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1061 g_ptr_array_add( out_array, out );
1068 void FindReplace(CString& strContents, const char* pTag, const char* pValue)
1070 if (strcmp(pTag, pValue) == 0)
1072 for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
1074 int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
1075 CString strLeft = strContents.Left(nPos);
1076 CString strRight = strContents.Right(nRightLen);
1078 strLeft += strRight;
1079 strContents = strLeft;
1083 // save the map, deals with regioning
1084 void SaveWithRegion(char *name)
1086 strcpy (name, currentmap);
1089 // temporary cut the region to save regular map
1090 region_active = false;
1091 Map_SaveFile (name, false);
1092 region_active = true;
1093 StripExtension (name);
1094 strcat (name, ".reg");
1097 Map_SaveFile (name, region_active);
1100 void RunBsp (char *command)
1103 char batpath[BIG_PATH_MAX]; //% PATH_MAX
1104 char temppath[BIG_PATH_MAX]; //% PATH_MAX
1105 char name[BIG_PATH_MAX]; //% PATH_MAX
1106 char cWork[BIG_PATH_MAX]; //% PATH_MAX
1110 SetInspectorMode(W_CONSOLE);
1112 strcpy (temppath, g_strTempPath.GetBuffer ());
1114 SaveWithRegion(name);
1116 const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd");
1119 CString strPath, strFile;
1121 ExtractPath_and_Filename(name, strPath, strFile);
1123 strncpy(cWork, strPath, 1024);
1124 strcat(cWork, strFile);
1127 strcpy(cWork, name);
1130 // get the array ready
1131 //++timo TODO: free the array, free the strings ourselves with delete[]
1132 sys = g_ptr_array_new();
1134 QE_ExpandBspString (command, sys, cWork);
1136 if (g_PrefsDlg.m_bWatchBSP)
1138 // grab the file name for engine running
1139 char *bspname = new char[1024];
1140 ExtractFileName( currentmap, bspname );
1141 StripExtension( bspname );
1142 g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname );
1145 // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
1147 for (i=0; i < sys->len; i++ )
1149 strSys += (char *)g_ptr_array_index( sys, i);
1150 #ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window
1157 strSys += "junk.txt\"";
1162 #if defined (__linux__) || defined (__APPLE__)
1165 sprintf (batpath, "%sqe3bsp.sh", temppath);
1166 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1167 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1168 hFile = fopen(batpath, "w");
1170 Error ("Can't write to %s", batpath);
1171 fprintf (hFile, "#!/bin/sh \n\n");
1172 fprintf (hFile, strSys.GetBuffer());
1174 chmod (batpath, 0744);
1178 sprintf (batpath, "%sqe3bsp.bat", temppath);
1179 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1180 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1181 hFile = fopen(batpath, "w");
1183 Error ("Can't write to %s", batpath);
1184 fprintf (hFile, strSys.GetBuffer());
1188 Pointfile_Delete ();
1190 #if defined (__linux__) || defined (__APPLE__)
1198 Error ("CreateProcess failed");
1201 execlp (batpath, batpath, NULL);
1202 printf ("execlp error !");
1211 Sys_Printf ("Running bsp command...\n");
1212 Sys_Printf ("\n%s\n", strSys.GetBuffer());
1214 WinExec( batpath, SW_SHOWNORMAL );
1218 // yeah, do it .. but not now right before 1.1-TA-beta release
1219 Sys_Printf("TODO: erase GPtrArray\n");
1227 int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer )
1229 static PIXELFORMATDESCRIPTOR pfd = {
1230 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1231 1, // version number
1232 PFD_DRAW_TO_WINDOW | // support window
1233 PFD_SUPPORT_OPENGL | // support OpenGL
1234 PFD_DOUBLEBUFFER, // double buffered
1235 PFD_TYPE_RGBA, // RGBA type
1236 24, // 24-bit color depth
1237 0, 0, 0, 0, 0, 0, // color bits ignored
1238 0, // no alpha buffer
1239 0, // shift bit ignored
1240 0, // no accumulation buffer
1241 0, 0, 0, 0, // accum bits ignored
1243 0, // no stencil buffer
1244 0, // no auxiliary buffer
1245 PFD_MAIN_PLANE, // main layer
1247 0, 0, 0 // layer masks ignored
1249 int pixelformat = 0;
1255 if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
1259 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1260 FORMAT_MESSAGE_FROM_SYSTEM |
1261 FORMAT_MESSAGE_IGNORE_INSERTS,
1264 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1269 Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf);
1270 Error ("ChoosePixelFormat failed");
1273 if (!SetPixelFormat(hDC, pixelformat, &pfd))
1274 Error ("SetPixelFormat failed");