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[] ) {
433 Rambetter on Sat Nov 13, 2010:
435 The following line fixes parsing and writing of floating point numbers in locales such as
436 Italy, Germany, and others outside of en_US. In particular, in such problem locales, users
437 are not able to use certain map entities such as "light" because the definitions of these entities
438 in the entity definition files contain floating point values written in the standard "C" format
439 (containing a dot instead of, for example, a comma). The call sscanf() is all over the code,
440 including parsing entity definition files and reading Radiant preferences. sscanf() is sensitive
441 to locale (in particular when reading floating point numbers).
443 The line below is the minimalistic way to address only this particular problem - the parsing
444 and writing of floating point values. There may be other yet-undiscovered bugs related to
445 locale still lingering in the code. When such bugs are discovered, they should be addressed by
446 setting more than just "LC_NUMERIC=C" (for example LC_CTYPE for regular expression matching)
447 or by fixing the problem in the actual code instead of fiddling with LC_* variables.
449 Another way to fix the floating point format problem is to locate all calls such as *scanf()
450 and *printf() in the code and replace them with other functions. However, we're also using
451 external libraries such as libxml and [maybe?] they use locale to parse their numeric values.
452 I'm just saying, it may get ugly if we try to fix the problem without setting LC_NUMERIC.
454 Usage of sscanf() throughout the code looks like so:
455 sscanf(str, "%f %f %f", &val1, &val2, &val3);
456 Code like this exists in many files, here are 4 examples:
457 tools/quake3/q3map2/light.c
458 tools/quake3/q3map2/model.c
459 radiant/preferences.cpp
460 plugins/entity/miscmodel.cpp
462 Also affected are printf() calls when using formats that contain "%f".
464 I did some research and putenv() seems to be the best choice for being cross-platform. It
465 used to be a function in Windows (now deprecated):
466 http://msdn.microsoft.com/en-us/library/ms235321(VS.80).aspx
467 And of course it's defined in UNIX.
469 One more thing. the gtk_init() call below modifies all of the locale settings. In fact if it
470 weren't for gtk_init(), we wouldn't have to set LC_NUMERIC (parsing of floating points with
471 a dot works just fine before the gtk_init() call on a sample Linux system). If we were to
472 just setlocale() here, it would get clobbered by gtk_init(). So instead of using setlocale()
473 _after_ gtk_init(), I chose to fix this problem via environment variable. I think it's cleaner
476 putenv("LC_NUMERIC=C");
479 libgl = "opengl32.dll";
482 #if defined (__linux__)
483 libgl = "libGL.so.1";
487 libgl = "/usr/X11R6/lib/libGL.1.dylib";
490 #if defined (__linux__) || defined (__APPLE__)
491 // Give away unnecessary root privileges.
492 // Important: must be done before calling gtk_init().
496 if ( geteuid() == 0 && ( loginname = getlogin() ) != NULL && ( pw = getpwnam(loginname) ) != NULL ) {
502 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
503 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
504 textdomain(GETTEXT_PACKAGE);
505 // gtk_disable_setlocale();
507 gtk_init(&argc, &argv);
508 gtk_gl_init(&argc, &argv);
509 gdk_gl_init(&argc, &argv);
511 // TODO: Find a better place to call this.
512 gtk_glwidget_create_font();
514 if ((ptr = getenv ("Q3R_LIBGL")) != NULL)
517 for (i = 1; i < argc; i++)
519 char* param = argv[i];
521 if (param[0] == '-' && param[1] == '-')
525 if ((strcmp (param, "libgl") == 0) && (i != argc))
528 argv[i] = argv[i+1] = NULL;
530 } else if (strcmp (param, "builddefs") == 0)
538 for (i = 1; i < argc; i++)
540 for (k = i; k < argc; k++)
547 for (j = i + k; j < argc; j++)
556 g_strPluginsDir = "plugins/";
557 g_strModulesDir = "modules/";
560 // get path to the editor
561 char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1);
562 GetModuleFileName(NULL, pBuffer, _MAX_PATH);
563 pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0';
564 QE_ConvertDOSToUnixName(pBuffer, pBuffer);
565 g_strAppPath.ReleaseBuffer();
567 g_strBitmapsPath = g_strAppPath;
568 g_strBitmapsPath += "bitmaps/";
570 CGameDialog::UpdateNetrun(false); // read the netrun configuration
572 if ( CGameDialog::GetNetrun() ) {
573 // we have to find a per-user g_strTempPath
574 // this behaves the same as on Linux
575 g_strTempPath = getenv("USERPROFILE");
576 if (!g_strTempPath.GetLength())
579 msg = "Radiant is configured to run from a network installation.\n";
580 msg += "I couldn't find the environement variable USERPROFILE\n";
581 msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n";
582 gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK);
583 g_strTempPath = "C:\\";
585 g_strTempPath += "\\RadiantSettings\\";
586 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
587 g_strTempPath += RADIANT_VERSION;
588 g_strTempPath += "\\";
589 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
593 // use the core path as temp (to save commandlist.txt, and do the .pid files)
594 g_strTempPath = g_strAppPath;
599 #if defined (__linux__) || defined (__APPLE__)
601 home = g_get_home_dir ();
604 Q_mkdir (home.GetBuffer (), 0775);
605 home += RADIANT_VERSION;
606 Q_mkdir (home.GetBuffer (), 0775);
607 g_strTempPath = home.GetBuffer ();
608 AddSlash (g_strTempPath);
610 loki_initpaths(argv[0]);
612 // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
613 // it's a general convention in Radiant to have the slash at the end of directories
615 realpath (loki_getdatapath(), real);
616 if (real[strlen(real)-1] != '/')
621 // radiant is installed in the parent dir of "tools/"
622 // NOTE: this is not very easy for debugging
623 // maybe add options to lookup in several places?
624 // (for now I had to create symlinks)
625 g_strBitmapsPath = g_strAppPath;
626 g_strBitmapsPath += "bitmaps/";
628 // we will set this right after the game selection is done
629 g_strGameToolsPath = g_strAppPath;
634 g_strDTDPath = g_strAppPath;
635 g_strDTDPath += "dtds/";
638 the global prefs loading / game selection dialog might fail for any reason we don't know about
639 we need to catch when it happens, to cleanup the stateful prefs which might be killing it
640 and to turn on console logging for lookup of the problem
641 this is the first part of the two step .pid system
643 g_pidFile = g_strTempPath.GetBuffer ();
644 g_pidFile += "radiant.pid";
647 pid = fopen( g_pidFile.GetBuffer(), "r" );
652 if (remove (g_pidFile.GetBuffer ()) == -1)
654 msg = "WARNING: Could not delete "; msg += g_pidFile;
655 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
658 // in debug, never prompt to clean registry, turn console logging auto after a failed start
660 msg = "Found the file ";
662 msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n"
663 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
664 "WARNING: the global prefs will be lost if you choose YES.";
666 if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES)
668 // remove global prefs and shutdown
669 g_PrefsDlg.mGamesDialog.Reset();
670 // remove the prefs file (like a full reset of the registry)
671 //remove (g_PrefsDlg.m_inipath->str);
672 gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK );
675 msg = "Logging console output to ";
676 msg += g_strTempPath;
677 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
679 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
682 // set without saving, the class is not in a coherent state yet
683 // just do the value change and call to start logging, CGamesDialog will pickup when relevant
684 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
685 g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true;
689 // create a primary .pid for global init run
690 pid = fopen( g_pidFile.GetBuffer(), "w" );
695 // a safe check to avoid people running broken installations
696 // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
697 // make something idiot proof and someone will make better idiots, this may be overkill
698 // let's leave it disabled in debug mode in any case
700 //#define CHECK_VERSION
703 // locate and open RADIANT_MAJOR and RADIANT_MINOR
704 qboolean bVerIsGood = true;
706 ver_file_name = g_strAppPath;
707 ver_file_name += "RADIANT_MAJOR";
708 FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r");
713 fread(buf, 1, 10, ver_file);
714 // chomp it (the hard way)
716 while(buf[chomp] >= '0' && buf[chomp] <= '9')
719 if (strcmp(buf, RADIANT_MAJOR_VERSION))
721 Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf);
727 Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer());
730 ver_file_name = g_strAppPath;
731 ver_file_name += "RADIANT_MINOR";
732 ver_file = fopen (ver_file_name.GetBuffer(), "r");
737 fread(buf, 1, 10, ver_file);
738 // chomp it (the hard way)
740 while(buf[chomp] >= '0' && buf[chomp] <= '9')
743 if (strcmp(buf, RADIANT_MINOR_VERSION))
745 Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf);
751 Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer());
757 msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n";
758 msg += "Make sure you run the right/latest editor binary you installed\n";
759 msg += g_strAppPath; msg += "\n";
760 msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information";
761 gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219");
766 g_qeglobals.disable_ini = false;
770 if ( remove( g_pidFile.GetBuffer () ) == -1 ) {
772 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
773 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
777 now the secondary game dependant .pid file
779 g_pidGameFile = g_PrefsDlg.m_rc_path->str;
780 g_pidGameFile += "radiant-game.pid";
782 pid = fopen (g_pidGameFile.GetBuffer(), "r");
787 if (remove (g_pidGameFile.GetBuffer ()) == -1)
789 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
790 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
793 msg = "Found the file ";
794 msg += g_pidGameFile;
795 msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n"
796 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
797 "WARNING: preferences will be lost if you choose YES.";
799 // in debug, never prompt to clean registry, turn console logging auto after a failed start
802 if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES)
804 // remove the game prefs files
805 remove (g_PrefsDlg.m_inipath->str);
807 sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str);
809 // remove the global pref too
810 g_PrefsDlg.mGamesDialog.Reset();
811 gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK );
814 msg = "Logging console output to ";
815 msg += g_strTempPath;
816 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
818 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
821 // force console logging on! (will go in prefs too)
822 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
823 g_PrefsDlg.mGamesDialog.SavePrefs();
826 g_PrefsDlg.LoadPrefs();
830 // create one, will remove right after entering message loop
831 pid = fopen (g_pidGameFile.GetBuffer(), "w");
835 g_PrefsDlg.LoadPrefs();
837 #ifndef _DEBUG // I can't be arsed about that prompt in debug mode
838 // if console logging is on in the prefs, warn about performance hit
839 if (g_PrefsDlg.mGamesDialog.m_bLogConsole)
841 if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n"
842 "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES)
844 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
845 g_PrefsDlg.mGamesDialog.SavePrefs();
849 // toggle console logging if necessary
853 // we should search in g_strTempPath, then move over to look at g_strAppPath?
855 // fine tune the look of the app using a gtk rc file
856 // we try to load an RC file placed in the application directory
857 // build the full path
859 sRCFile = g_strAppPath;
860 sRCFile += "radiantgtkrc";
861 // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
862 pBuffer = (char *)sRCFile.GetBuffer();
863 for (i=0; i<sRCFile.GetLength(); i++)
870 // check the file exists
871 if (access(sRCFile.GetBuffer(), R_OK) != 0)
872 Sys_Printf("RC file %s not found\n", sRCFile.GetBuffer());
875 Sys_Printf ("Attemping to load RC file %s\n", sRCFile.GetBuffer());
876 gtk_rc_parse (sRCFile.GetBuffer());
884 if (!QGL_Init(libgl, ""))
886 Sys_FPrintf (SYS_ERR, "Failed to load OpenGL libraries\n");
891 #if defined (__linux__) || defined (__APPLE__)
892 if ((qglXQueryExtension == NULL) || (qglXQueryExtension(GDK_DISPLAY(),NULL,NULL) != True))
894 Sys_FPrintf (SYS_ERR, "glXQueryExtension failed\n");
900 // redirect Gtk warnings to the console
901 g_log_set_handler( "Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
902 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
903 g_log_set_handler( "Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
904 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
906 // spog - creates new filters list for the first time
907 g_qeglobals.d_savedinfo.filters = NULL;
908 g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters);
910 g_pParentWnd = new MainFrame();
912 if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) {
913 Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer());
918 // load up shaders now that we have the map loaded
920 Texture_ShowStartupShaders();
923 gdk_window_raise(splash_screen->window);
924 gtk_window_set_transient_for( GTK_WINDOW( splash_screen ), GTK_WINDOW( g_pParentWnd->m_pWidget ) );
925 gtk_timeout_add( 1000, try_destroy_splash, NULL );
928 g_pParentWnd->GetSynapseServer().DumpActiveClients();
930 //++timo: temporary debug
931 g_pParentWnd->DoWatchBSP();
935 // close the log file if any
936 // NOTE: don't save prefs past this point!
937 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
938 // set the console window to NULL to avoid Sys_Printf crashing
939 g_qeglobals_gui.d_edit = NULL;
942 // NOTE TTimo not sure what this _exit(0) call is worth
943 // restricting it to linux build
950 // ydnar: quick and dirty fix, just make the buffer bigger
951 #define BIG_PATH_MAX 4096
953 // TTimo: decompose the BSP command into several steps so we can monitor them eventually
954 void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname)
958 char src[BIG_PATH_MAX];
959 char rsh[BIG_PATH_MAX];
960 char base[BIG_PATH_MAX];
962 strcpy(src, mapname);
964 in = strstr(src, "maps/");
967 in = strstr(src, "maps/");
984 ExtractFileName (mapname, base);
987 // this important step alters the map name to add fs_game
988 // NOTE: it used to add fs_basepath too
989 // the fs_basepath addition moved to being in the project file during the bug fixing rush
990 // but it may not have been the right thing to do
992 // HACK: halflife compiler tools don't support -fs_game
993 // HACK: neither does JKII/SoF2/ etc..
994 // do we use & have fs_game?
996 if (g_pGameDescription->mGameFile != "hl.game" &&
997 *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0')
1000 sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname);
1004 sprintf(src, "\"%s\"", mapname);
1009 QE_ConvertDOSToUnixName(src, src);
1011 // initialise the first step
1012 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1013 g_ptr_array_add( out_array, out );
1015 in = ValueForKey( g_qeglobals.d_project_entity, bspaction );
1028 // we process these only if monitoring
1029 if (g_PrefsDlg.m_bWatchBSP)
1031 // -connect global option (the only global option so far anyway)
1032 strcpy (tmp, " -connect 127.0.0.1:39000 ");
1059 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1060 g_ptr_array_add( out_array, out );
1067 void FindReplace(CString& strContents, const char* pTag, const char* pValue)
1069 if (strcmp(pTag, pValue) == 0)
1071 for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
1073 int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
1074 CString strLeft = strContents.Left(nPos);
1075 CString strRight = strContents.Right(nRightLen);
1077 strLeft += strRight;
1078 strContents = strLeft;
1082 // save the map, deals with regioning
1083 void SaveWithRegion(char *name)
1085 strcpy (name, currentmap);
1088 // temporary cut the region to save regular map
1089 region_active = false;
1090 Map_SaveFile (name, false);
1091 region_active = true;
1092 StripExtension (name);
1093 strcat (name, ".reg");
1096 Map_SaveFile (name, region_active);
1099 void RunBsp (char *command)
1102 char batpath[BIG_PATH_MAX]; //% PATH_MAX
1103 char temppath[BIG_PATH_MAX]; //% PATH_MAX
1104 char name[BIG_PATH_MAX]; //% PATH_MAX
1105 char cWork[BIG_PATH_MAX]; //% PATH_MAX
1109 SetInspectorMode(W_CONSOLE);
1111 strcpy (temppath, g_strTempPath.GetBuffer ());
1113 SaveWithRegion(name);
1115 const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd");
1118 CString strPath, strFile;
1120 ExtractPath_and_Filename(name, strPath, strFile);
1122 strncpy(cWork, strPath, 1024);
1123 strcat(cWork, strFile);
1126 strcpy(cWork, name);
1129 // get the array ready
1130 //++timo TODO: free the array, free the strings ourselves with delete[]
1131 sys = g_ptr_array_new();
1133 QE_ExpandBspString (command, sys, cWork);
1135 if (g_PrefsDlg.m_bWatchBSP)
1137 // grab the file name for engine running
1138 char *bspname = new char[1024];
1139 ExtractFileName( currentmap, bspname );
1140 StripExtension( bspname );
1141 g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname );
1144 // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
1146 for (i=0; i < sys->len; i++ )
1148 strSys += (char *)g_ptr_array_index( sys, i);
1149 #ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window
1156 strSys += "junk.txt\"";
1161 #if defined (__linux__) || defined (__APPLE__)
1164 sprintf (batpath, "%sqe3bsp.sh", temppath);
1165 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1166 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1167 hFile = fopen(batpath, "w");
1169 Error ("Can't write to %s", batpath);
1170 fprintf (hFile, "#!/bin/sh \n\n");
1171 fprintf (hFile, strSys.GetBuffer());
1173 chmod (batpath, 0744);
1177 sprintf (batpath, "%sqe3bsp.bat", temppath);
1178 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1179 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1180 hFile = fopen(batpath, "w");
1182 Error ("Can't write to %s", batpath);
1183 fprintf (hFile, strSys.GetBuffer());
1187 Pointfile_Delete ();
1189 #if defined (__linux__) || defined (__APPLE__)
1197 Error ("CreateProcess failed");
1200 execlp (batpath, batpath, NULL);
1201 printf ("execlp error !");
1210 Sys_Printf ("Running bsp command...\n");
1211 Sys_Printf ("\n%s\n", strSys.GetBuffer());
1213 WinExec( batpath, SW_SHOWNORMAL );
1217 // yeah, do it .. but not now right before 1.1-TA-beta release
1218 Sys_Printf("TODO: erase GPtrArray\n");
1226 int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer )
1228 static PIXELFORMATDESCRIPTOR pfd = {
1229 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1230 1, // version number
1231 PFD_DRAW_TO_WINDOW | // support window
1232 PFD_SUPPORT_OPENGL | // support OpenGL
1233 PFD_DOUBLEBUFFER, // double buffered
1234 PFD_TYPE_RGBA, // RGBA type
1235 24, // 24-bit color depth
1236 0, 0, 0, 0, 0, 0, // color bits ignored
1237 0, // no alpha buffer
1238 0, // shift bit ignored
1239 0, // no accumulation buffer
1240 0, 0, 0, 0, // accum bits ignored
1242 0, // no stencil buffer
1243 0, // no auxiliary buffer
1244 PFD_MAIN_PLANE, // main layer
1246 0, 0, 0 // layer masks ignored
1248 int pixelformat = 0;
1254 if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
1258 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1259 FORMAT_MESSAGE_FROM_SYSTEM |
1260 FORMAT_MESSAGE_IGNORE_INSERTS,
1263 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1268 Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf);
1269 Error ("ChoosePixelFormat failed");
1272 if (!SetPixelFormat(hDC, pixelformat, &pfd))
1273 Error ("SetPixelFormat failed");