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 Fri Jan 21, 2011:
435 People with recent NVIDIA cards and Windows 7 (Aero) are complaining about "hall of mirrors"
436 effect in the OpenGL viewports. The code below is borrowed from NetRadiant to address
437 this issue. This change turns off desktop compositing (globally) while Radiant is running.
438 It's a real hack but the "correct" fix is very involving, so until the underlying problem
439 is addressed we need this code here. I don't know for sure what the underlying problem is,
440 but I have a hunch it's the version of gtkglext.dll we're using.
445 lib = LoadLibrary("dwmapi.dll");
448 void (WINAPI *qDwmEnableComposition) (bool bEnable) =
449 (void (WINAPI *) (bool bEnable)) GetProcAddress(lib, "DwmEnableComposition");
450 if (qDwmEnableComposition)
452 qDwmEnableComposition(FALSE);
460 Rambetter on Sat Nov 13, 2010:
462 The following line fixes parsing and writing of floating point numbers in locales such as
463 Italy, Germany, and others outside of en_US. In particular, in such problem locales, users
464 are not able to use certain map entities such as "light" because the definitions of these entities
465 in the entity definition files contain floating point values written in the standard "C" format
466 (containing a dot instead of, for example, a comma). The call sscanf() is all over the code,
467 including parsing entity definition files and reading Radiant preferences. sscanf() is sensitive
468 to locale (in particular when reading floating point numbers).
470 The line below is the minimalistic way to address only this particular problem - the parsing
471 and writing of floating point values. There may be other yet-undiscovered bugs related to
472 locale still lingering in the code. When such bugs are discovered, they should be addressed by
473 setting more than just "LC_NUMERIC=C" (for example LC_CTYPE for regular expression matching)
474 or by fixing the problem in the actual code instead of fiddling with LC_* variables.
476 Another way to fix the floating point format problem is to locate all calls such as *scanf()
477 and *printf() in the code and replace them with other functions. However, we're also using
478 external libraries such as libxml and [maybe?] they use locale to parse their numeric values.
479 I'm just saying, it may get ugly if we try to fix the problem without setting LC_NUMERIC.
481 Usage of sscanf() throughout the code looks like so:
482 sscanf(str, "%f %f %f", &val1, &val2, &val3);
483 Code like this exists in many files, here are 4 examples:
484 tools/quake3/q3map2/light.c
485 tools/quake3/q3map2/model.c
486 radiant/preferences.cpp
487 plugins/entity/miscmodel.cpp
489 Also affected are printf() calls when using formats that contain "%f".
491 I did some research and putenv() seems to be the best choice for being cross-platform. It
492 used to be a function in Windows (now deprecated):
493 http://msdn.microsoft.com/en-us/library/ms235321(VS.80).aspx
494 And of course it's defined in UNIX.
496 One more thing. the gtk_init() call below modifies all of the locale settings. In fact if it
497 weren't for gtk_init(), we wouldn't have to set LC_NUMERIC (parsing of floating points with
498 a dot works just fine before the gtk_init() call on a sample Linux system). If we were to
499 just setlocale() here, it would get clobbered by gtk_init(). So instead of using setlocale()
500 _after_ gtk_init(), I chose to fix this problem via environment variable. I think it's cleaner
503 putenv("LC_NUMERIC=C");
506 libgl = "opengl32.dll";
509 #if defined (__linux__)
510 libgl = "libGL.so.1";
514 libgl = "/usr/X11R6/lib/libGL.1.dylib";
517 #if defined (__linux__) || defined (__APPLE__)
518 // Give away unnecessary root privileges.
519 // Important: must be done before calling gtk_init().
523 if ( geteuid() == 0 && ( loginname = getlogin() ) != NULL && ( pw = getpwnam(loginname) ) != NULL ) {
529 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
530 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
531 textdomain(GETTEXT_PACKAGE);
532 // gtk_disable_setlocale();
534 gtk_init(&argc, &argv);
535 gtk_gl_init(&argc, &argv);
536 gdk_gl_init(&argc, &argv);
538 // TODO: Find a better place to call this.
539 gtk_glwidget_create_font();
541 if ((ptr = getenv ("Q3R_LIBGL")) != NULL)
544 for (i = 1; i < argc; i++)
546 char* param = argv[i];
548 if (param[0] == '-' && param[1] == '-')
552 if ((strcmp (param, "libgl") == 0) && (i != argc))
555 argv[i] = argv[i+1] = NULL;
557 } else if (strcmp (param, "builddefs") == 0)
565 for (i = 1; i < argc; i++)
567 for (k = i; k < argc; k++)
574 for (j = i + k; j < argc; j++)
583 g_strPluginsDir = "plugins/";
584 g_strModulesDir = "modules/";
587 // get path to the editor
588 char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1);
589 GetModuleFileName(NULL, pBuffer, _MAX_PATH);
590 pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0';
591 QE_ConvertDOSToUnixName(pBuffer, pBuffer);
592 g_strAppPath.ReleaseBuffer();
594 g_strBitmapsPath = g_strAppPath;
595 g_strBitmapsPath += "bitmaps/";
597 CGameDialog::UpdateNetrun(false); // read the netrun configuration
599 if ( CGameDialog::GetNetrun() ) {
600 // we have to find a per-user g_strTempPath
601 // this behaves the same as on Linux
602 g_strTempPath = getenv("USERPROFILE");
603 if (!g_strTempPath.GetLength())
606 msg = "Radiant is configured to run from a network installation.\n";
607 msg += "I couldn't find the environement variable USERPROFILE\n";
608 msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n";
609 gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK);
610 g_strTempPath = "C:\\";
612 g_strTempPath += "\\RadiantSettings\\";
613 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
614 g_strTempPath += RADIANT_VERSION;
615 g_strTempPath += "\\";
616 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
620 // use the core path as temp (to save commandlist.txt, and do the .pid files)
621 g_strTempPath = g_strAppPath;
626 #if defined (__linux__) || defined (__APPLE__)
628 home = g_get_home_dir ();
631 Q_mkdir (home.GetBuffer (), 0775);
632 home += RADIANT_VERSION;
633 Q_mkdir (home.GetBuffer (), 0775);
634 g_strTempPath = home.GetBuffer ();
635 AddSlash (g_strTempPath);
637 loki_initpaths(argv[0]);
639 // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
640 // it's a general convention in Radiant to have the slash at the end of directories
642 realpath (loki_getdatapath(), real);
643 if (real[strlen(real)-1] != '/')
648 // radiant is installed in the parent dir of "tools/"
649 // NOTE: this is not very easy for debugging
650 // maybe add options to lookup in several places?
651 // (for now I had to create symlinks)
652 g_strBitmapsPath = g_strAppPath;
653 g_strBitmapsPath += "bitmaps/";
655 // we will set this right after the game selection is done
656 g_strGameToolsPath = g_strAppPath;
661 g_strDTDPath = g_strAppPath;
662 g_strDTDPath += "dtds/";
665 the global prefs loading / game selection dialog might fail for any reason we don't know about
666 we need to catch when it happens, to cleanup the stateful prefs which might be killing it
667 and to turn on console logging for lookup of the problem
668 this is the first part of the two step .pid system
670 g_pidFile = g_strTempPath.GetBuffer ();
671 g_pidFile += "radiant.pid";
674 pid = fopen( g_pidFile.GetBuffer(), "r" );
679 if (remove (g_pidFile.GetBuffer ()) == -1)
681 msg = "WARNING: Could not delete "; msg += g_pidFile;
682 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
685 // in debug, never prompt to clean registry, turn console logging auto after a failed start
687 msg = "Found the file ";
689 msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n"
690 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
691 "WARNING: the global prefs will be lost if you choose YES.";
693 if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES)
695 // remove global prefs and shutdown
696 g_PrefsDlg.mGamesDialog.Reset();
697 // remove the prefs file (like a full reset of the registry)
698 //remove (g_PrefsDlg.m_inipath->str);
699 gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK );
702 msg = "Logging console output to ";
703 msg += g_strTempPath;
704 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
706 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
709 // set without saving, the class is not in a coherent state yet
710 // just do the value change and call to start logging, CGamesDialog will pickup when relevant
711 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
712 g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true;
716 // create a primary .pid for global init run
717 pid = fopen( g_pidFile.GetBuffer(), "w" );
722 // a safe check to avoid people running broken installations
723 // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
724 // make something idiot proof and someone will make better idiots, this may be overkill
725 // let's leave it disabled in debug mode in any case
727 //#define CHECK_VERSION
730 // locate and open RADIANT_MAJOR and RADIANT_MINOR
731 qboolean bVerIsGood = true;
733 ver_file_name = g_strAppPath;
734 ver_file_name += "RADIANT_MAJOR";
735 FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r");
740 fread(buf, 1, 10, ver_file);
741 // chomp it (the hard way)
743 while(buf[chomp] >= '0' && buf[chomp] <= '9')
746 if (strcmp(buf, RADIANT_MAJOR_VERSION))
748 Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf);
754 Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer());
757 ver_file_name = g_strAppPath;
758 ver_file_name += "RADIANT_MINOR";
759 ver_file = fopen (ver_file_name.GetBuffer(), "r");
764 fread(buf, 1, 10, ver_file);
765 // chomp it (the hard way)
767 while(buf[chomp] >= '0' && buf[chomp] <= '9')
770 if (strcmp(buf, RADIANT_MINOR_VERSION))
772 Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf);
778 Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer());
784 msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n";
785 msg += "Make sure you run the right/latest editor binary you installed\n";
786 msg += g_strAppPath; msg += "\n";
787 msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information";
788 gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219");
793 g_qeglobals.disable_ini = false;
797 if ( remove( g_pidFile.GetBuffer () ) == -1 ) {
799 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
800 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
804 now the secondary game dependant .pid file
806 g_pidGameFile = g_PrefsDlg.m_rc_path->str;
807 g_pidGameFile += "radiant-game.pid";
809 pid = fopen (g_pidGameFile.GetBuffer(), "r");
814 if (remove (g_pidGameFile.GetBuffer ()) == -1)
816 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
817 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
820 msg = "Found the file ";
821 msg += g_pidGameFile;
822 msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n"
823 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
824 "WARNING: preferences will be lost if you choose YES.";
826 // in debug, never prompt to clean registry, turn console logging auto after a failed start
829 if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES)
831 // remove the game prefs files
832 remove (g_PrefsDlg.m_inipath->str);
834 sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str);
836 // remove the global pref too
837 g_PrefsDlg.mGamesDialog.Reset();
838 gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK );
841 msg = "Logging console output to ";
842 msg += g_strTempPath;
843 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
845 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
848 // force console logging on! (will go in prefs too)
849 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
850 g_PrefsDlg.mGamesDialog.SavePrefs();
853 g_PrefsDlg.LoadPrefs();
857 // create one, will remove right after entering message loop
858 pid = fopen (g_pidGameFile.GetBuffer(), "w");
862 g_PrefsDlg.LoadPrefs();
864 #ifndef _DEBUG // I can't be arsed about that prompt in debug mode
865 // if console logging is on in the prefs, warn about performance hit
866 if (g_PrefsDlg.mGamesDialog.m_bLogConsole)
868 if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n"
869 "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES)
871 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
872 g_PrefsDlg.mGamesDialog.SavePrefs();
876 // toggle console logging if necessary
880 // we should search in g_strTempPath, then move over to look at g_strAppPath?
882 // fine tune the look of the app using a gtk rc file
883 // we try to load an RC file placed in the application directory
884 // build the full path
886 sRCFile = g_strAppPath;
887 sRCFile += "radiantgtkrc";
888 // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
889 pBuffer = (char *)sRCFile.GetBuffer();
890 for (i=0; i<sRCFile.GetLength(); i++)
897 // check the file exists
898 if (access(sRCFile.GetBuffer(), R_OK) != 0)
899 Sys_Printf("RC file %s not found\n", sRCFile.GetBuffer());
902 Sys_Printf ("Attemping to load RC file %s\n", sRCFile.GetBuffer());
903 gtk_rc_parse (sRCFile.GetBuffer());
911 if (!QGL_Init(libgl, ""))
913 Sys_FPrintf (SYS_ERR, "Failed to load OpenGL libraries\n");
918 #if defined (__linux__) || defined (__APPLE__)
919 if ((qglXQueryExtension == NULL) || (qglXQueryExtension(GDK_DISPLAY(),NULL,NULL) != True))
921 Sys_FPrintf (SYS_ERR, "glXQueryExtension failed\n");
927 // redirect Gtk warnings to the console
928 g_log_set_handler( "Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
929 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
930 g_log_set_handler( "Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
931 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
933 // spog - creates new filters list for the first time
934 g_qeglobals.d_savedinfo.filters = NULL;
935 g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters);
937 g_pParentWnd = new MainFrame();
939 if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) {
940 Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer());
945 // load up shaders now that we have the map loaded
947 Texture_ShowStartupShaders();
950 gdk_window_raise(splash_screen->window);
951 gtk_window_set_transient_for( GTK_WINDOW( splash_screen ), GTK_WINDOW( g_pParentWnd->m_pWidget ) );
952 gtk_timeout_add( 1000, try_destroy_splash, NULL );
955 g_pParentWnd->GetSynapseServer().DumpActiveClients();
957 //++timo: temporary debug
958 g_pParentWnd->DoWatchBSP();
962 // close the log file if any
963 // NOTE: don't save prefs past this point!
964 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
965 // set the console window to NULL to avoid Sys_Printf crashing
966 g_qeglobals_gui.d_edit = NULL;
969 // NOTE TTimo not sure what this _exit(0) call is worth
970 // restricting it to linux build
977 // ydnar: quick and dirty fix, just make the buffer bigger
978 #define BIG_PATH_MAX 4096
980 // TTimo: decompose the BSP command into several steps so we can monitor them eventually
981 void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname)
985 char src[BIG_PATH_MAX];
986 char rsh[BIG_PATH_MAX];
987 char base[BIG_PATH_MAX];
989 strcpy(src, mapname);
991 in = strstr(src, "maps/");
994 in = strstr(src, "maps/");
1011 ExtractFileName (mapname, base);
1014 // this important step alters the map name to add fs_game
1015 // NOTE: it used to add fs_basepath too
1016 // the fs_basepath addition moved to being in the project file during the bug fixing rush
1017 // but it may not have been the right thing to do
1019 // HACK: halflife compiler tools don't support -fs_game
1020 // HACK: neither does JKII/SoF2/ etc..
1021 // do we use & have fs_game?
1023 if (g_pGameDescription->mGameFile != "hl.game" &&
1024 *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0')
1027 sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname);
1031 sprintf(src, "\"%s\"", mapname);
1036 QE_ConvertDOSToUnixName(src, src);
1038 // initialise the first step
1039 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1040 g_ptr_array_add( out_array, out );
1042 in = ValueForKey( g_qeglobals.d_project_entity, bspaction );
1055 // we process these only if monitoring
1056 if (g_PrefsDlg.m_bWatchBSP)
1058 // -connect global option (the only global option so far anyway)
1059 strcpy (tmp, " -connect 127.0.0.1:39000 ");
1086 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1087 g_ptr_array_add( out_array, out );
1094 void FindReplace(CString& strContents, const char* pTag, const char* pValue)
1096 if (strcmp(pTag, pValue) == 0)
1098 for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
1100 int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
1101 CString strLeft = strContents.Left(nPos);
1102 CString strRight = strContents.Right(nRightLen);
1104 strLeft += strRight;
1105 strContents = strLeft;
1109 // save the map, deals with regioning
1110 void SaveWithRegion(char *name)
1112 strcpy (name, currentmap);
1115 // temporary cut the region to save regular map
1116 region_active = false;
1117 Map_SaveFile (name, false);
1118 region_active = true;
1119 StripExtension (name);
1120 strcat (name, ".reg");
1123 Map_SaveFile (name, region_active);
1126 void RunBsp (char *command)
1129 char batpath[BIG_PATH_MAX]; //% PATH_MAX
1130 char temppath[BIG_PATH_MAX]; //% PATH_MAX
1131 char name[BIG_PATH_MAX]; //% PATH_MAX
1132 char cWork[BIG_PATH_MAX]; //% PATH_MAX
1136 SetInspectorMode(W_CONSOLE);
1138 strcpy (temppath, g_strTempPath.GetBuffer ());
1140 SaveWithRegion(name);
1142 const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd");
1145 CString strPath, strFile;
1147 ExtractPath_and_Filename(name, strPath, strFile);
1149 strncpy(cWork, strPath, 1024);
1150 strcat(cWork, strFile);
1153 strcpy(cWork, name);
1156 // get the array ready
1157 //++timo TODO: free the array, free the strings ourselves with delete[]
1158 sys = g_ptr_array_new();
1160 QE_ExpandBspString (command, sys, cWork);
1162 if (g_PrefsDlg.m_bWatchBSP)
1164 // grab the file name for engine running
1165 char *bspname = new char[1024];
1166 ExtractFileName( currentmap, bspname );
1167 StripExtension( bspname );
1168 g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname );
1171 // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
1173 for (i=0; i < sys->len; i++ )
1175 strSys += (char *)g_ptr_array_index( sys, i);
1176 #ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window
1183 strSys += "junk.txt\"";
1188 #if defined (__linux__) || defined (__APPLE__)
1191 sprintf (batpath, "%sqe3bsp.sh", temppath);
1192 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1193 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1194 hFile = fopen(batpath, "w");
1196 Error ("Can't write to %s", batpath);
1197 fprintf (hFile, "#!/bin/sh \n\n");
1198 fprintf (hFile, strSys.GetBuffer());
1200 chmod (batpath, 0744);
1204 sprintf (batpath, "%sqe3bsp.bat", temppath);
1205 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1206 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1207 hFile = fopen(batpath, "w");
1209 Error ("Can't write to %s", batpath);
1210 fprintf (hFile, strSys.GetBuffer());
1214 Pointfile_Delete ();
1216 #if defined (__linux__) || defined (__APPLE__)
1224 Error ("CreateProcess failed");
1227 execlp (batpath, batpath, NULL);
1228 printf ("execlp error !");
1237 Sys_Printf ("Running bsp command...\n");
1238 Sys_Printf ("\n%s\n", strSys.GetBuffer());
1240 WinExec( batpath, SW_SHOWNORMAL );
1244 // yeah, do it .. but not now right before 1.1-TA-beta release
1245 Sys_Printf("TODO: erase GPtrArray\n");
1253 int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer )
1255 static PIXELFORMATDESCRIPTOR pfd = {
1256 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1257 1, // version number
1258 PFD_DRAW_TO_WINDOW | // support window
1259 PFD_SUPPORT_OPENGL | // support OpenGL
1260 PFD_DOUBLEBUFFER, // double buffered
1261 PFD_TYPE_RGBA, // RGBA type
1262 24, // 24-bit color depth
1263 0, 0, 0, 0, 0, 0, // color bits ignored
1264 0, // no alpha buffer
1265 0, // shift bit ignored
1266 0, // no accumulation buffer
1267 0, 0, 0, 0, // accum bits ignored
1269 0, // no stencil buffer
1270 0, // no auxiliary buffer
1271 PFD_MAIN_PLANE, // main layer
1273 0, 0, 0 // layer masks ignored
1275 int pixelformat = 0;
1281 if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
1285 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1286 FORMAT_MESSAGE_FROM_SYSTEM |
1287 FORMAT_MESSAGE_IGNORE_INSERTS,
1290 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1295 Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf);
1296 Error ("ChoosePixelFormat failed");
1299 if (!SetPixelFormat(hDC, pixelformat, &pfd))
1300 Error ("SetPixelFormat failed");